From 78d026114e3401f8266c84af454f4b302ca34dee Mon Sep 17 00:00:00 2001 From: HENRY Benjamin Date: Mon, 7 Jun 2021 14:35:19 +0200 Subject: [PATCH 01/82] init --- .../BombAnimator/BombAnimatorComponent.cpp | 5 +++++ .../BombAnimator/BombAnimatorComponent.hpp | 21 +++++++++++++++++++ .../BombAnimator/BombAnimatorSystem.cpp | 5 +++++ .../BombAnimator/BombAnimatorSystem.hpp | 14 +++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 sources/Component/BombAnimator/BombAnimatorComponent.cpp create mode 100644 sources/Component/BombAnimator/BombAnimatorComponent.hpp create mode 100644 sources/System/BombAnimator/BombAnimatorSystem.cpp create mode 100644 sources/System/BombAnimator/BombAnimatorSystem.hpp diff --git a/sources/Component/BombAnimator/BombAnimatorComponent.cpp b/sources/Component/BombAnimator/BombAnimatorComponent.cpp new file mode 100644 index 00000000..3ff7574c --- /dev/null +++ b/sources/Component/BombAnimator/BombAnimatorComponent.cpp @@ -0,0 +1,5 @@ +// +// Created by hbenjamin on 07/06/2021. +// + +#include "BombAnimatorComponent.hpp" diff --git a/sources/Component/BombAnimator/BombAnimatorComponent.hpp b/sources/Component/BombAnimator/BombAnimatorComponent.hpp new file mode 100644 index 00000000..78e8ebc6 --- /dev/null +++ b/sources/Component/BombAnimator/BombAnimatorComponent.hpp @@ -0,0 +1,21 @@ +// +// Created by hbenjamin on 07/06/2021. +// + +#pragma once +namespace BBM { + class BombAnimatorComponent { + public: + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief ctor + explicit BombAnimatorComponent(WAL::Entity &entity); + //! @brief copy ctor + BombAnimatorComponent(const BombAnimatorComponent &) = default; + //! @brief dtor + ~BombAnimatorComponent() override = default; + //! @brief assignment operator + BombAnimatorComponent &operator=(const BombAnimatorComponent &) = delete; + }; +} \ No newline at end of file diff --git a/sources/System/BombAnimator/BombAnimatorSystem.cpp b/sources/System/BombAnimator/BombAnimatorSystem.cpp new file mode 100644 index 00000000..3bae8d09 --- /dev/null +++ b/sources/System/BombAnimator/BombAnimatorSystem.cpp @@ -0,0 +1,5 @@ +// +// Created by hbenjamin on 07/06/2021. +// + +#include "BombAnimatorSystem.hpp" diff --git a/sources/System/BombAnimator/BombAnimatorSystem.hpp b/sources/System/BombAnimator/BombAnimatorSystem.hpp new file mode 100644 index 00000000..170730dc --- /dev/null +++ b/sources/System/BombAnimator/BombAnimatorSystem.hpp @@ -0,0 +1,14 @@ +// +// Created by hbenjamin on 07/06/2021. +// + +#ifndef BOMBERMAN_BOMBANIMATORSYSTEM_H +#define BOMBERMAN_BOMBANIMATORSYSTEM_H + + +class BombAnimatorSystem { + +}; + + +#endif //BOMBERMAN_BOMBANIMATORSYSTEM_H From 982050cb91de03df272ebd524cea41824dc237cd Mon Sep 17 00:00:00 2001 From: EternalRat <44569175+EternalRat@users.noreply.github.com> Date: Tue, 8 Jun 2021 16:41:59 +0200 Subject: [PATCH 02/82] bombanimatorcomponent created, waiting for model to test --- CMakeLists.txt | 4 +++ .../BombAnimator/BombAnimatorComponent.cpp | 12 ++++++++ .../BombAnimator/BombAnimatorComponent.hpp | 15 +++++++++- sources/Runner/Runner.cpp | 2 ++ .../BombAnimator/BombAnimatorSystem.cpp | 22 ++++++++++++++ .../BombAnimator/BombAnimatorSystem.hpp | 29 ++++++++++++++----- .../System/BombHolder/BombHolderSystem.cpp | 6 +++- 7 files changed, 81 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 588f5096..aa74bf81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,10 @@ set(SOURCES sources/Component/Animator/AnimatorComponent.hpp sources/System/Animator/AnimatorSystem.cpp sources/System/Animator/AnimatorSystem.hpp + sources/Component/BombAnimator/BombAnimatorComponent.cpp + sources/Component/BombAnimator/BombAnimatorComponent.hpp + sources/System/BombAnimator/BombAnimatorSystem.cpp + sources/System/BombAnimator/BombAnimatorSystem.hpp ) add_executable(bomberman sources/main.cpp diff --git a/sources/Component/BombAnimator/BombAnimatorComponent.cpp b/sources/Component/BombAnimator/BombAnimatorComponent.cpp index 3ff7574c..f3b15836 100644 --- a/sources/Component/BombAnimator/BombAnimatorComponent.cpp +++ b/sources/Component/BombAnimator/BombAnimatorComponent.cpp @@ -3,3 +3,15 @@ // #include "BombAnimatorComponent.hpp" + +namespace BBM +{ + BombAnimatorComponent::BombAnimatorComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + + WAL::Component *BombAnimatorComponent::clone(WAL::Entity &entity) const + { + return new BombAnimatorComponent(entity); + } +} \ No newline at end of file diff --git a/sources/Component/BombAnimator/BombAnimatorComponent.hpp b/sources/Component/BombAnimator/BombAnimatorComponent.hpp index 78e8ebc6..3e5145b3 100644 --- a/sources/Component/BombAnimator/BombAnimatorComponent.hpp +++ b/sources/Component/BombAnimator/BombAnimatorComponent.hpp @@ -3,9 +3,22 @@ // #pragma once + +#include "Component/Component.hpp" +#include "Entity/Entity.hpp" +#include + +using namespace std::chrono_literals; + namespace BBM { - class BombAnimatorComponent { + class BombAnimatorComponent : public WAL::Component{ public: + + //! @brief The number of seconds of each animation. This variable is used to reset the nextAnimationRate value. + std::chrono::nanoseconds animationRate = 1000ms; + //! @brief The number of nanosecond before the next animation. + std::chrono::nanoseconds nextAnimationRate = animationRate; + //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 57494e5e..4b8fd421 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "Component/Animation/AnimationsComponent.hpp" #include "System/Animation/AnimationsSystem.hpp" #include "Map/Map.hpp" @@ -52,6 +53,7 @@ namespace BBM .addSystem() .addSystem() .addSystem() + .addSystem() .addSystem() .addSystem() .addSystem() diff --git a/sources/System/BombAnimator/BombAnimatorSystem.cpp b/sources/System/BombAnimator/BombAnimatorSystem.cpp index 3bae8d09..27647a38 100644 --- a/sources/System/BombAnimator/BombAnimatorSystem.cpp +++ b/sources/System/BombAnimator/BombAnimatorSystem.cpp @@ -3,3 +3,25 @@ // #include "BombAnimatorSystem.hpp" +#include +#include + +namespace BBM +{ + BombAnimatorSystem::BombAnimatorSystem(WAL::Wal &wal) + : System(wal) + {} + + void BombAnimatorSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + { + auto &animator = entity.get(); + + animator.nextAnimationRate -= dtime; + if (animator.nextAnimationRate <= 0ns) { + animator.nextAnimationRate = animator.animationRate; + /*auto &animation = entity.get(); + auto ind = animation.getCurrentAnimIndex(); + animation.setAnimIndex(ind++);*/ + } + } +} \ No newline at end of file diff --git a/sources/System/BombAnimator/BombAnimatorSystem.hpp b/sources/System/BombAnimator/BombAnimatorSystem.hpp index 170730dc..83d227ab 100644 --- a/sources/System/BombAnimator/BombAnimatorSystem.hpp +++ b/sources/System/BombAnimator/BombAnimatorSystem.hpp @@ -2,13 +2,28 @@ // Created by hbenjamin on 07/06/2021. // -#ifndef BOMBERMAN_BOMBANIMATORSYSTEM_H -#define BOMBERMAN_BOMBANIMATORSYSTEM_H +#pragma once +#include "Component/Animation/AnimationsComponent.hpp" +#include "Component/BombAnimator/BombAnimatorComponent.hpp" +#include "System/System.hpp" -class BombAnimatorSystem { +namespace BBM +{ + //! @brief A system to handle BombAnimator entities. + class BombAnimatorSystem : public WAL::System + { + public: + //! @inherit + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dTime) override; -}; - - -#endif //BOMBERMAN_BOMBANIMATORSYSTEM_H + //! @brief A default constructor + BombAnimatorSystem(WAL::Wal &wal); + //! @brief An BombAnimator system is copy constructable + BombAnimatorSystem(const BombAnimatorSystem &) = default; + //! @brief A default destructor + ~BombAnimatorSystem() override = default; + //! @brief A BombAnimator system is assignable. + BombAnimatorSystem &operator=(const BombAnimatorSystem &) = default; + }; +} diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 2d46b3b8..76934aea 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -2,6 +2,8 @@ // Created by Zoe Roux on 5/31/21. // +#include +#include #include "Component/Timer/TimerComponent.hpp" #include "System/Event/EventSystem.hpp" #include "Component/Renderer/Drawable3DComponent.hpp" @@ -43,7 +45,9 @@ namespace BBM .addComponent(position) .addComponent(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion) .addComponent("assets/bombs/bomb.obj", - std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png")); + std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png")) + .addComponent() + .addComponent(RAY::ModelAnimations("assets/bombs/bomb.obj"), 0); } void BombHolderSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) From 54bc9ce5ac5a51263b4a14e47b725d91d034b6bf Mon Sep 17 00:00:00 2001 From: HENRY Benjamin Date: Wed, 9 Jun 2021 10:57:55 +0200 Subject: [PATCH 03/82] need to fix explosion.obj --- CMakeLists.txt | 4 - assets/bombs/explosion/blast.png | Bin 0 -> 47275 bytes assets/bombs/explosion/explosion.mtl | 12 + assets/bombs/explosion/explosion.obj | 2071 +++++++++++++++++ assets/bombs/explosion/explosion.png | Bin 0 -> 2200 bytes .../BombAnimator/BombAnimatorComponent.cpp | 17 - .../BombAnimator/BombAnimatorComponent.hpp | 34 - sources/Runner/Runner.cpp | 2 - .../BombAnimator/BombAnimatorSystem.cpp | 27 - .../BombAnimator/BombAnimatorSystem.hpp | 29 - .../System/BombHolder/BombHolderSystem.cpp | 14 +- 11 files changed, 2092 insertions(+), 118 deletions(-) create mode 100644 assets/bombs/explosion/blast.png create mode 100644 assets/bombs/explosion/explosion.mtl create mode 100644 assets/bombs/explosion/explosion.obj create mode 100644 assets/bombs/explosion/explosion.png delete mode 100644 sources/Component/BombAnimator/BombAnimatorComponent.cpp delete mode 100644 sources/Component/BombAnimator/BombAnimatorComponent.hpp delete mode 100644 sources/System/BombAnimator/BombAnimatorSystem.cpp delete mode 100644 sources/System/BombAnimator/BombAnimatorSystem.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a614554..48dcf444 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,10 +81,6 @@ set(SOURCES sources/Component/Animator/AnimatorComponent.hpp sources/System/Animator/AnimatorSystem.cpp sources/System/Animator/AnimatorSystem.hpp - sources/Component/BombAnimator/BombAnimatorComponent.cpp - sources/Component/BombAnimator/BombAnimatorComponent.hpp - sources/System/BombAnimator/BombAnimatorSystem.cpp - sources/System/BombAnimator/BombAnimatorSystem.hpp ) add_executable(bomberman sources/main.cpp diff --git a/assets/bombs/explosion/blast.png b/assets/bombs/explosion/blast.png new file mode 100644 index 0000000000000000000000000000000000000000..037212f67f03826eb9341527a28124a187d1ec56 GIT binary patch literal 47275 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 aiTw{`qE2)k3_^4O0000 - -using namespace std::chrono_literals; - -namespace BBM { - class BombAnimatorComponent : public WAL::Component{ - public: - - //! @brief The number of seconds of each animation. This variable is used to reset the nextAnimationRate value. - std::chrono::nanoseconds animationRate = 1000ms; - //! @brief The number of nanosecond before the next animation. - std::chrono::nanoseconds nextAnimationRate = animationRate; - - //! @inherit - WAL::Component *clone(WAL::Entity &entity) const override; - - //! @brief ctor - explicit BombAnimatorComponent(WAL::Entity &entity); - //! @brief copy ctor - BombAnimatorComponent(const BombAnimatorComponent &) = default; - //! @brief dtor - ~BombAnimatorComponent() override = default; - //! @brief assignment operator - BombAnimatorComponent &operator=(const BombAnimatorComponent &) = delete; - }; -} \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 924fb85e..591ce261 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include "Component/Animation/AnimationsComponent.hpp" #include "System/Animation/AnimationsSystem.hpp" #include "Map/Map.hpp" @@ -53,7 +52,6 @@ namespace BBM .addSystem() .addSystem() .addSystem() - .addSystem() .addSystem() .addSystem() .addSystem() diff --git a/sources/System/BombAnimator/BombAnimatorSystem.cpp b/sources/System/BombAnimator/BombAnimatorSystem.cpp deleted file mode 100644 index 27647a38..00000000 --- a/sources/System/BombAnimator/BombAnimatorSystem.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by hbenjamin on 07/06/2021. -// - -#include "BombAnimatorSystem.hpp" -#include -#include - -namespace BBM -{ - BombAnimatorSystem::BombAnimatorSystem(WAL::Wal &wal) - : System(wal) - {} - - void BombAnimatorSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) - { - auto &animator = entity.get(); - - animator.nextAnimationRate -= dtime; - if (animator.nextAnimationRate <= 0ns) { - animator.nextAnimationRate = animator.animationRate; - /*auto &animation = entity.get(); - auto ind = animation.getCurrentAnimIndex(); - animation.setAnimIndex(ind++);*/ - } - } -} \ No newline at end of file diff --git a/sources/System/BombAnimator/BombAnimatorSystem.hpp b/sources/System/BombAnimator/BombAnimatorSystem.hpp deleted file mode 100644 index 83d227ab..00000000 --- a/sources/System/BombAnimator/BombAnimatorSystem.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// Created by hbenjamin on 07/06/2021. -// - -#pragma once - -#include "Component/Animation/AnimationsComponent.hpp" -#include "Component/BombAnimator/BombAnimatorComponent.hpp" -#include "System/System.hpp" - -namespace BBM -{ - //! @brief A system to handle BombAnimator entities. - class BombAnimatorSystem : public WAL::System - { - public: - //! @inherit - void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dTime) override; - - //! @brief A default constructor - BombAnimatorSystem(WAL::Wal &wal); - //! @brief An BombAnimator system is copy constructable - BombAnimatorSystem(const BombAnimatorSystem &) = default; - //! @brief A default destructor - ~BombAnimatorSystem() override = default; - //! @brief A BombAnimator system is assignable. - BombAnimatorSystem &operator=(const BombAnimatorSystem &) = default; - }; -} diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 76934aea..30d0c80b 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -2,7 +2,6 @@ // Created by Zoe Roux on 5/31/21. // -#include #include #include "Component/Timer/TimerComponent.hpp" #include "System/Event/EventSystem.hpp" @@ -26,7 +25,7 @@ namespace BBM { bomb.scheduleDeletion(); auto &bombPosition = bomb.getComponent(); - wal.getSystem().dispatchEvent([&bombPosition](WAL::Entity &entity){ + wal.getSystem().dispatchEvent([&bombPosition, &wal](WAL::Entity &entity){ auto *health = entity.tryGetComponent(); auto *pos = entity.tryGetComponent(); @@ -34,6 +33,13 @@ namespace BBM return; if (pos->position.distance(bombPosition.position) > BombHolderSystem::explosionRadius) return; + wal.scene->scheduleNewEntity("explosion") + .addComponent(pos->position) + .addComponent(1s, [](WAL::Entity &explosion, WAL::Wal &wal) { + explosion.scheduleDeletion(); + }) + .addComponent("assets/bombs/explosion/explosion.obj", + std::make_pair(MAP_DIFFUSE, "assets/bombs/explosion/explosion.png")); // TODO do a raycast here to only remove health to entities that are not behind others. health->takeDmg(1); }); @@ -45,9 +51,7 @@ namespace BBM .addComponent(position) .addComponent(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion) .addComponent("assets/bombs/bomb.obj", - std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png")) - .addComponent() - .addComponent(RAY::ModelAnimations("assets/bombs/bomb.obj"), 0); + std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png")); } void BombHolderSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) From b552ee3d45462eccad3dccd6a722fefb02a95612 Mon Sep 17 00:00:00 2001 From: Askou Date: Wed, 9 Jun 2021 11:57:25 +0200 Subject: [PATCH 04/82] add collision for bumper and hole --- sources/Map/Map.cpp | 48 ++++++++++++++++++++++++++------------- sources/Map/Map.hpp | 11 +++++++++ sources/Runner/Runner.cpp | 4 ++-- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index 5e8a9a2e..23c14dbe 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -12,6 +12,28 @@ namespace RAY3D = RAY::Drawables::Drawables3D; namespace BBM { + void MapGenerator::bumperCollide(WAL::Entity &entity, + const WAL::Entity &wall, + CollisionComponent::CollidedAxis collidedAxis) + { + auto *movable = entity.tryGetComponent(); + + if (!movable) + return; + movable->_velocity.y = 0.5; + } + + void MapGenerator::holeCollide(WAL::Entity &entity, + const WAL::Entity &wall, + CollisionComponent::CollidedAxis collidedAxis) + { + auto *health = entity.tryGetComponent(); + + if (!health) + return; + health->takeDmg(health->getHealthPoint()); + } + void MapGenerator::wallCollide(WAL::Entity &entity, const WAL::Entity &wall, CollisionComponent::CollidedAxis collidedAxis) @@ -23,7 +45,7 @@ namespace BBM if (collidedAxis & CollisionComponent::CollidedAxis::X) mov->_velocity.x = 0; if (collidedAxis & CollisionComponent::CollidedAxis::Y) - mov->_velocity.x = 0; + mov->_velocity.y = 0; if (collidedAxis & CollisionComponent::CollidedAxis::Z) mov->_velocity.z = 0; } @@ -200,19 +222,16 @@ namespace BBM WAL::Entity &holeEntity = scene->addEntity("Hole Block"); - holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)); - + holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)) + .addComponent( + WAL::Callback(), + &MapGenerator::holeCollide, Vector3f(0.25, 0.25, 0.25),Vector3f(0.75, 1.75, 0.75)); if (coords.y == 0) holeEntity.addComponent(holeObj, std::make_pair(MAP_DIFFUSE, holePng)); else holeEntity.addComponent(secondFloorObj, std::make_pair(MAP_DIFFUSE, secondFloorPng)); - /*.addComponent([](WAL::Entity &other, const WAL::Entity &entity) { - if (other.hasComponent()) { - auto &health = other.getComponent(); - health.takeDmg(health.getHealthPoint()); - } - }, [](WAL::Entity &other, const WAL::Entity &entity){}); */ + } void MapGenerator::createBumper(Vector3f coords, std::shared_ptr scene) @@ -222,13 +241,10 @@ namespace BBM scene->addEntity("Bumper Block") .addComponent(Vector3f(coords.x, coords.y, coords.z)) - .addComponent(bumperObj, std::make_pair(MAP_DIFFUSE, bumperPng)); - /* .addComponent([](const WAL::Entity &entity, WAL::Entity &other) { - if (other.hasComponent()) { - auto &movable = other.getComponent(); - movable.addForce(Vector3f(0, 5, 0)); - } - }); */ + .addComponent(bumperObj, std::make_pair(MAP_DIFFUSE, bumperPng)) + .addComponent( + WAL::Callback(), + &MapGenerator::bumperCollide, Vector3f(0.25, 0.25, 0.25),Vector3f(0.75, 0.75, 0.75)); } void MapGenerator::createStairs(Vector3f coords, std::shared_ptr scene) diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index 4a961cbc..328fa506 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -159,11 +159,22 @@ namespace BBM static const std::string secondFloorHolePath; public: + static void wallCollide(WAL::Entity &entity, const WAL::Entity &wall, CollisionComponent::CollidedAxis collidedAxis); + static void wallDestroyed(WAL::Entity &entity); + static void holeCollide(WAL::Entity &entity, + const WAL::Entity &wall, + CollisionComponent::CollidedAxis collidedAxis); + + static void bumperCollide(WAL::Entity &entity, + const WAL::Entity &wall, + CollisionComponent::CollidedAxis collidedAxis); + + //! @param width Width of the map //! @param height Height of the map diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 591ce261..5e810675 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -87,8 +87,8 @@ namespace BBM animation.setAnimIndex(5); }); scene->addEntity("camera") - .addComponent(8, 20, 7) - .addComponent(Vector3f(8, 0, 8)); + .addComponent(8, 4, -15) + .addComponent(Vector3f(8, 3, 8)); /*scene->addEntity("cube") .addComponent(-5, 0, -5) .addComponent(Vector3f(0, 0, 0), Vector3f(3, 3, 3), RED) From 1470371c10f6b6e14d8cdf962fdf9a4d7b0fa8a4 Mon Sep 17 00:00:00 2001 From: Askou Date: Wed, 9 Jun 2021 11:58:27 +0200 Subject: [PATCH 05/82] reposition camera --- sources/Runner/Runner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 5e810675..591ce261 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -87,8 +87,8 @@ namespace BBM animation.setAnimIndex(5); }); scene->addEntity("camera") - .addComponent(8, 4, -15) - .addComponent(Vector3f(8, 3, 8)); + .addComponent(8, 20, 7) + .addComponent(Vector3f(8, 0, 8)); /*scene->addEntity("cube") .addComponent(-5, 0, -5) .addComponent(Vector3f(0, 0, 0), Vector3f(3, 3, 3), RED) From 9c1190be3034c856b2bcf7fd93dac06e8cd5dc96 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Wed, 9 Jun 2021 12:48:20 +0200 Subject: [PATCH 06/82] using glb model forexplosion --- assets/bombs/explosion/explosion.glb | Bin 0 -> 70836 bytes assets/bombs/explosion/explosion.mtl | 12 - assets/bombs/explosion/explosion.obj | 2071 ----------------- .../System/BombHolder/BombHolderSystem.cpp | 2 +- 4 files changed, 1 insertion(+), 2084 deletions(-) create mode 100644 assets/bombs/explosion/explosion.glb delete mode 100644 assets/bombs/explosion/explosion.mtl delete mode 100644 assets/bombs/explosion/explosion.obj diff --git a/assets/bombs/explosion/explosion.glb b/assets/bombs/explosion/explosion.glb new file mode 100644 index 0000000000000000000000000000000000000000..065ed85c9e431b441dafba8a80ff0a0041df910e GIT binary patch literal 70836 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, [](WAL::Entity &explosion, WAL::Wal &wal) { explosion.scheduleDeletion(); }) - .addComponent("assets/bombs/explosion/explosion.obj", + .addComponent("assets/bombs/explosion/explosion.glb", std::make_pair(MAP_DIFFUSE, "assets/bombs/explosion/explosion.png")); // TODO do a raycast here to only remove health to entities that are not behind others. health->takeDmg(1); From 99729153a32a4b93106e4a7922e4c4ea9a8f1b00 Mon Sep 17 00:00:00 2001 From: HENRY Benjamin Date: Wed, 9 Jun 2021 16:16:48 +0200 Subject: [PATCH 07/82] deleted bad texture --- assets/bombs/explosion/explosion.png | Bin 2200 -> 0 bytes sources/System/BombHolder/BombHolderSystem.cpp | 7 ------- 2 files changed, 7 deletions(-) delete mode 100644 assets/bombs/explosion/explosion.png diff --git a/assets/bombs/explosion/explosion.png b/assets/bombs/explosion/explosion.png deleted file mode 100644 index 9ed5ab29d8312cedd491e59491625c5d0a9095bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2200 zcmV;J2xs?+P)Px#32;bRa{vGfQvd)9Qvv_G*>L~>0H{z*R7C>;0V)av zE(--T3DAo6Phy||7<_UMkjP4623ts|A|kbH5~6+Gyil#x%!+djJ2L|JZ-`UN!&Wg#Y!B z|Cd<*{*)b=QJ(++2YE?EK~z}7t(gl~8e0s7#}{I?_$(+&QHm51s8)pk|Icoco#f;k z7)rZt@G+~8Z|$`wGbfL#%A-kfLeV;wIHWi#g8xkZvelx0$p4}GV<@)OQYdrwiU1nq z6OjL!%A9?U0}i>`&(OO_HY}*3REb|LlrCtH&5W(sNEM}EHbMZ-XeI~AJ7bv&=0ymw zGcrrA^&(-Fs?dvzQ;Hi6x&*r**D4k)#0IKB33qmLCP5d<7STlh1K6=5mK+eOKneFH z1k-PnOqxYMtWueI zOVPRQ&=+4ZThQ!=NG31XMe=6wW-L3vRE83;?;&tP3t7x?uz8$JI0;ztK*W**p!WNd$z(d6j_7+zm&8^w z`CNjNV3o@WmSKfTN{Kld^(;msX0vLL6Bt>MoG7v8K?hWU-cz*c!y)X6Xx<8LstfRz z)F!b^WoVn?rvzUSTFGnRc<&%r%#B#53Ua{l$UlS)vPdq#$>Q9F0?SkaK0bbE(50Y> ztdiHjD!7$g5OWR7)O%1r&O;EIRJYmZ4BTjBPE_WC-Lvb26{cjbzn@=OGr*J;>_q?01-lVd zDR(-8xdF?>7YRl)*}>w33$`3KuI4VgYjPb+S{eHG@&G9B=1Jk{eoM6F{!@-Cuvq6%<YF z5O}eGU^Rj>!X6D6Y}`h?ZECN{6)t1nB?ue@ORAkScQh%uhgEngHgE|m+;f>W&qaJNKK(()^Y+xmi$}PZCHEqGjtB8MhG2d@ ztnh+Z#Pr1rP2Ud>YwriV&*T*9Wk%==!d^VT5*F{BE$_3vbZUl#cnU8x1xqY&(}E3a zx6Qanh%-Ol+Ww+kIvB?VUh9U1T(zOF_b{Aq*SQfYI2}a4{TTA&g5?g11KG~EqwK)& zgGf${aXOAQ{6HRaHD$-ph61AU>g>`_jCMTdrF@X$;qAq#bFQV*acpmO&obqPjDX;Q z*CjaWDKF^r<0X|Pv3%gWrpJ6E)jQS$WM!WfJYGmiC4~wtVYS@J$`a#db)S`~QmPwR z%E@PfzcQ4HRmZ0CEI%}<0Im+BU~w1)rBr@TLn~D0ukvMOs$zep!n&+~kAq-q19}NO z(`tPwF-BP}1-rBu(rlq6$~za~?rHO;-OyxeT}#&+0fDDBK(Y6+amhNZs%W!9gE7z! zgS#Q_T!yJ5@`h*{+KW)Fqt7ZDq8tp(#O8R?HtYPcz?O2g-}E*X-SHj3Wn*Yi6>Her z>%4tC_C7XmIHfb3XnUNxlmh2 zH{iidJF)pr4OqxJjk?$9>DWlbcCtxVG3ZKTIZQkaERr!jBh?snjn>9o8>dFuybl)V zqb?z1FgL+aZqoO$96YESpXtEQz@}Kolbv#q=wn0^%eQPJHVxJTSjVXk7*Xor^IIBw zVutv|2dZ%dygvWcVRf3QVx-EdJ2s@%F)gU#K`l17VlR%XF;|wsvW1V8&tw!XGxn_m zYXu*L@p>ABU;7mN`qHSUI}X^(2|LI(xYzh%WBb#z5ZJP5$hIQB5zv)DS~Q#)^z^S5 z7}*Bnz_%?}jND)=64oLIJ1$(BX+0FSLs;Z^=o+V_)^DDgYa62dw9JZIr*iG|r-jy* zMcLP|B};3v9kB+^7JIhY^VrYVdSPK$M{aIhZ~7*3-?xx)4Y}*;G$Y&Q^e9`JhPCO= zRDc6nHob@0j#r_+jNM_)>yqKKq7@#HDpjakoGm0LazKY@0czC0i9{xJE74oV1hiSz aiTw{`qE2)k3_^4O0000position.distance(bombPosition.position) > BombHolderSystem::explosionRadius) return; - wal.scene->scheduleNewEntity("explosion") - .addComponent(pos->position) - .addComponent(1s, [](WAL::Entity &explosion, WAL::Wal &wal) { - explosion.scheduleDeletion(); - }) - .addComponent("assets/bombs/explosion/explosion.glb", - std::make_pair(MAP_DIFFUSE, "assets/bombs/explosion/explosion.png")); // TODO do a raycast here to only remove health to entities that are not behind others. health->takeDmg(1); }); From 6667344592b5300976d1f7160868fc514dfd175e Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 9 Jun 2021 16:53:27 +0200 Subject: [PATCH 08/82] Making left and right block solids --- sources/Map/Map.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index b5ca0268..44190315 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -72,9 +72,25 @@ namespace BBM static const std::string unbreakableObj = unbreakableWallPath + objExtension; static const std::string unbreakablePnj = unbreakableWallPath + imageExtension; + for (int i = 0; i < height; i++) { + scene->addEntity("Bomb stopper") + .addComponent(-1, 0, i) + .addComponent>(); + scene->addEntity("Bomb stopper") + .addComponent(width + 1, 0, i) + .addComponent>(); + } + for (int i = 0; i < width; i++) { + scene->addEntity("Bomb stopper") + .addComponent(i, 0, -1) + .addComponent>(); + scene->addEntity("Bomb stopper") + .addComponent(i, 0, height + 1) + .addComponent>(); + } + scene->addEntity("Bottom Wall") .addComponent(Vector3f((width + 1) / 2, 0, -1)) - .addComponent>() .addComponent( WAL::Callback(), &MapGenerator::wallCollide, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75)) @@ -83,7 +99,6 @@ namespace BBM RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Upper Wall") .addComponent(Vector3f((width + 1) / 2, 0, height + 1)) - .addComponent>() .addComponent( WAL::Callback(), &MapGenerator::wallCollide, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75)) @@ -92,7 +107,6 @@ namespace BBM RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Left Wall") .addComponent(Vector3f(width + 1, 0, height / 2)) - .addComponent>() .addComponent( WAL::Callback(), &MapGenerator::wallCollide, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1)) From d17a410a656b7932c05209921d89d094983435e6 Mon Sep 17 00:00:00 2001 From: Askou Date: Wed, 9 Jun 2021 17:23:55 +0200 Subject: [PATCH 09/82] basic gravity --- CMakeLists.txt | 2 ++ .../Component/Gravity/GravityComponent.cpp | 17 ++++++++++ .../Component/Gravity/GravityComponent.hpp | 32 +++++++++++++++++++ sources/Runner/Runner.cpp | 4 +++ sources/System/Gravity/GravitySystem.cpp | 21 ++++++++++++ sources/System/Gravity/GravitySystem.hpp | 30 +++++++++++++++++ 6 files changed, 106 insertions(+) create mode 100644 sources/Component/Gravity/GravityComponent.cpp create mode 100644 sources/Component/Gravity/GravityComponent.hpp create mode 100644 sources/System/Gravity/GravitySystem.cpp create mode 100644 sources/System/Gravity/GravitySystem.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d7dc8112..8ae95107 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,8 @@ set(SOURCES sources/System/Sound/PlayerSoundManagerSystem.hpp sources/System/Music/MusicSystem.hpp sources/System/Music/MusicSystem.cpp + sources/Component/Gravity/GravityComponent.cpp + sources/System/Gravity/GravitySystem.cpp ) add_executable(bomberman diff --git a/sources/Component/Gravity/GravityComponent.cpp b/sources/Component/Gravity/GravityComponent.cpp new file mode 100644 index 00000000..a6ee1db4 --- /dev/null +++ b/sources/Component/Gravity/GravityComponent.cpp @@ -0,0 +1,17 @@ +// +// Created by Tom Augier on 2021-05-20. +// + +#include "GravityComponent.hpp" + +namespace BBM +{ + GravityComponent::GravityComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + + WAL::Component *GravityComponent::clone(WAL::Entity &entity) const + { + return new GravityComponent(entity); + } +} \ No newline at end of file diff --git a/sources/Component/Gravity/GravityComponent.hpp b/sources/Component/Gravity/GravityComponent.hpp new file mode 100644 index 00000000..f2b6a368 --- /dev/null +++ b/sources/Component/Gravity/GravityComponent.hpp @@ -0,0 +1,32 @@ +// +// Created by Tom Augier on 2021-05-20. +// + +#pragma once + +#include +#include "Component/Component.hpp" +#include "Entity/Entity.hpp" + +namespace BBM +{ + class GravityComponent : public WAL::Component + { + public: + + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief Constructor + GravityComponent(WAL::Entity &entity); + + //! @brief A Gravity component can't be instantiated, it should be derived. + GravityComponent(const GravityComponent &) = default; + + //! @brief default destructor + ~GravityComponent() override = default; + + //! @brief A Gravity component can't be assigned + GravityComponent &operator=(const GravityComponent &) = delete; + }; +} \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 2ee46062..de4c821f 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -39,6 +39,8 @@ #include "Component/Sound/SoundComponent.hpp" #include "System/Sound/PlayerSoundManagerSystem.hpp" #include "System/Music/MusicSystem.hpp" +#include "Component/Gravity/GravityComponent.hpp" +#include "System/Gravity/GravitySystem.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; namespace RAY2D = RAY::Drawables::Drawables2D; @@ -66,6 +68,7 @@ namespace BBM .addSystem() .addSystem() .addSystem() + .addSystem() .addSystem() .addSystem(); } @@ -101,6 +104,7 @@ namespace BBM .addComponent(BBM::Vector3f{0.25, 0, 0.25}, BBM::Vector3f{.75, 2, .75}) .addComponent() .addComponent(soundPath) + .addComponent() .addComponent() .addComponent(1, [](WAL::Entity &entity) { auto &animation = entity.getComponent(); diff --git a/sources/System/Gravity/GravitySystem.cpp b/sources/System/Gravity/GravitySystem.cpp new file mode 100644 index 00000000..8e0801e1 --- /dev/null +++ b/sources/System/Gravity/GravitySystem.cpp @@ -0,0 +1,21 @@ +// +// Created by Tom Augier on 2021-06-09. +// + +#include "GravitySystem.hpp" + +namespace BBM +{ + GravitySystem::GravitySystem(WAL::Wal &wal) + : System(wal) + {} + + void GravitySystem::onFixedUpdate(WAL::ViewEntity &entity) + { + auto &movable = entity.get(); + auto &position = entity.get(); + + if (position.getY() > 0) + movable.addForce(Vector3f(0, -0.5, 0)); + } +} \ No newline at end of file diff --git a/sources/System/Gravity/GravitySystem.hpp b/sources/System/Gravity/GravitySystem.hpp new file mode 100644 index 00000000..59963ac7 --- /dev/null +++ b/sources/System/Gravity/GravitySystem.hpp @@ -0,0 +1,30 @@ +// +// Created by Tom Augier on 2021-06-09. +// + +#pragma once + +#include "Component/Movable/MovableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Gravity/GravityComponent.hpp" +#include "System/System.hpp" + +namespace BBM +{ + //! @brief A system to handle Gravity entities. + class GravitySystem : public WAL::System + { + public: + //! @inherit + void onFixedUpdate(WAL::ViewEntity &entity) override; + + //! @brief A default constructor + explicit GravitySystem(WAL::Wal &wal); + //! @brief A Gravity system is copy constructable + GravitySystem(const GravitySystem &) = default; + //! @brief A default destructor + ~GravitySystem() override = default; + //! @brief A system is not assignable. + GravitySystem &operator=(const GravitySystem &) = delete; + }; +} \ No newline at end of file From 4a1e7b085fc78b9aa02bf359cb1922a28fb85230 Mon Sep 17 00:00:00 2001 From: Askou Date: Thu, 10 Jun 2021 11:24:47 +0200 Subject: [PATCH 10/82] bumperComponent + fix map --- CMakeLists.txt | 6 +++ .../BumperTimer/BumperTimerComponent.cpp | 17 ++++++++ .../BumperTimer/BumperTimerComponent.hpp | 41 +++++++++++++++++++ .../Component/Gravity/GravityComponent.hpp | 1 - sources/Map/Map.cpp | 32 +++++++++++++-- sources/Runner/Runner.cpp | 6 ++- .../System/BumperTimer/BumperTimerSystem.cpp | 25 +++++++++++ .../System/BumperTimer/BumperTimerSystem.hpp | 29 +++++++++++++ sources/System/Gravity/GravitySystem.cpp | 2 +- 9 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 sources/Component/BumperTimer/BumperTimerComponent.cpp create mode 100644 sources/Component/BumperTimer/BumperTimerComponent.hpp create mode 100644 sources/System/BumperTimer/BumperTimerSystem.cpp create mode 100644 sources/System/BumperTimer/BumperTimerSystem.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae95107..6fc419f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,8 +92,14 @@ set(SOURCES sources/System/Sound/PlayerSoundManagerSystem.hpp sources/System/Music/MusicSystem.hpp sources/System/Music/MusicSystem.cpp + sources/Component/Gravity/GravityComponent.hpp sources/Component/Gravity/GravityComponent.cpp + sources/System/Gravity/GravitySystem.hpp sources/System/Gravity/GravitySystem.cpp + sources/Component/BumperTimer/BumperTimerComponent.hpp + sources/Component/BumperTimer/BumperTimerComponent.cpp + sources/System/BumperTimer/BumperTimerSystem.hpp + sources/System/BumperTimer/BumperTimerSystem.cpp ) add_executable(bomberman diff --git a/sources/Component/BumperTimer/BumperTimerComponent.cpp b/sources/Component/BumperTimer/BumperTimerComponent.cpp new file mode 100644 index 00000000..1d661395 --- /dev/null +++ b/sources/Component/BumperTimer/BumperTimerComponent.cpp @@ -0,0 +1,17 @@ +// +// Created by Tom Augier on 2021-05-20. +// + +#include "BumperTimerComponent.hpp" + +namespace BBM +{ + BumperTimerComponent::BumperTimerComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + + WAL::Component *BumperTimerComponent::clone(WAL::Entity &entity) const + { + return new BumperTimerComponent(entity); + } +} \ No newline at end of file diff --git a/sources/Component/BumperTimer/BumperTimerComponent.hpp b/sources/Component/BumperTimer/BumperTimerComponent.hpp new file mode 100644 index 00000000..dbeba275 --- /dev/null +++ b/sources/Component/BumperTimer/BumperTimerComponent.hpp @@ -0,0 +1,41 @@ +// +// Created by Tom Augier on 2021-05-20. +// + +#pragma once + +#include +#include "Component/Component.hpp" +#include "Entity/Entity.hpp" + +using namespace std::chrono_literals; + +namespace BBM +{ + class BumperTimerComponent : public WAL::Component + { + public: + + + bool _isReseting = false; + //! @brief The number of seconds of each refill. This variable is used to reset the nextBombRefill value. + std::chrono::nanoseconds resetRate = 1500ms; + //! @brief The number of nanosecond before the next bomb refill. + std::chrono::nanoseconds nextReset = resetRate; + + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief Constructor + BumperTimerComponent(WAL::Entity &entity); + + //! @brief A BumperTimer component can't be instantiated, it should be derived. + BumperTimerComponent(const BumperTimerComponent &) = default; + + //! @brief default destructor + ~BumperTimerComponent() override = default; + + //! @brief A BumperTimer component can't be assigned + BumperTimerComponent &operator=(const BumperTimerComponent &) = delete; + }; +} \ No newline at end of file diff --git a/sources/Component/Gravity/GravityComponent.hpp b/sources/Component/Gravity/GravityComponent.hpp index f2b6a368..59f7cc89 100644 --- a/sources/Component/Gravity/GravityComponent.hpp +++ b/sources/Component/Gravity/GravityComponent.hpp @@ -4,7 +4,6 @@ #pragma once -#include #include "Component/Component.hpp" #include "Entity/Entity.hpp" diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index fb26dd2f..9d76bf45 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -7,6 +7,7 @@ #include "System/Collision/CollisionSystem.hpp" #include "Map.hpp" #include +#include namespace RAY3D = RAY::Drawables::Drawables3D; @@ -17,10 +18,14 @@ namespace BBM CollisionComponent::CollidedAxis collidedAxis) { auto *movable = entity.tryGetComponent(); + auto *bumperTimer = entity.tryGetComponent(); - if (!movable) + if (!movable || !bumperTimer) return; - movable->_velocity.y = 0.5; + if (!bumperTimer->_isReseting) { + movable->_velocity.y = 1.5; + bumperTimer->_isReseting = true; + } } void MapGenerator::holeCollide(WAL::Entity &entity, @@ -197,7 +202,10 @@ namespace BBM scene->addEntity("Upper Floor") .addComponent(Vector3f(coords)) - .addComponent(floorObj, std::make_pair(MAP_DIFFUSE, floorPng)); + .addComponent(floorObj, std::make_pair(MAP_DIFFUSE, floorPng)) + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, 0.25, 0.75); } @@ -308,9 +316,25 @@ namespace BBM MapGenerator::MapBlock MapGenerator::createSpawner(MapBlock map, int width, int height) { map[std::make_tuple(0, 0, 0)] = SPAWNER; + map[std::make_tuple(0, 0, 1)] = SPAWNER; + map[std::make_tuple(0, 0, 2)] = SPAWNER; + map[std::make_tuple(1, 0, 0)] = SPAWNER; + map[std::make_tuple(2, 0, 0)] = SPAWNER; map[std::make_tuple(width, 0, 0)] = SPAWNER; + map[std::make_tuple(width - 1, 0, 0)] = SPAWNER; + map[std::make_tuple(width - 2, 0, 0)] = SPAWNER; + map[std::make_tuple(width, 0, 1)] = SPAWNER; + map[std::make_tuple(width, 0, 2)] = SPAWNER; map[std::make_tuple(0, 0, height)] = SPAWNER; + map[std::make_tuple(1, 0, height)] = SPAWNER; + map[std::make_tuple(2, 0, height)] = SPAWNER; + map[std::make_tuple(0, 0, height - 1)] = SPAWNER; + map[std::make_tuple(0, 0, height - 2)] = SPAWNER; map[std::make_tuple(width, 0, height)] = SPAWNER; + map[std::make_tuple(width, 0, height - 1)] = SPAWNER; + map[std::make_tuple(width, 0, height - 2)] = SPAWNER; + map[std::make_tuple(width - 1, 0, height)] = SPAWNER; + map[std::make_tuple(width - 2, 0, height)] = SPAWNER; return map; } @@ -321,6 +345,8 @@ namespace BBM for (int j = 0; j < height; j++) { if (map[std::make_tuple(i, 0, j)] == BREAKABLE && map[std::make_tuple(i, -1, j)] == BUMPER) map[std::make_tuple(i, 0, j)] = NOTHING; + if (map[std::make_tuple(i, 1, j)] == BREAKABLE && isCloseToBlockType(map, i, -1, j, BUMPER)) + map[std::make_tuple(i, 1, j)] = NOTHING; } return (map); } diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index de4c821f..5cdcbd3a 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -41,6 +41,8 @@ #include "System/Music/MusicSystem.hpp" #include "Component/Gravity/GravityComponent.hpp" #include "System/Gravity/GravitySystem.hpp" +#include "Component/BumperTimer/BumperTimerComponent.hpp" +#include "System/BumperTimer/BumperTimerSystem.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; namespace RAY2D = RAY::Drawables::Drawables2D; @@ -69,6 +71,7 @@ namespace BBM .addSystem() .addSystem() .addSystem() + .addSystem() .addSystem() .addSystem(); } @@ -92,7 +95,7 @@ namespace BBM //{SoundComponent::DEATH, "assets/sounds/death.ogg"} }; scene->addEntity("player") - .addComponent() + .addComponent(0, 1.01, 0) .addComponent("assets/player/player.iqm", std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) .addComponent() .addComponent() @@ -106,6 +109,7 @@ namespace BBM .addComponent(soundPath) .addComponent() .addComponent() + .addComponent() .addComponent(1, [](WAL::Entity &entity) { auto &animation = entity.getComponent(); animation.setAnimIndex(5); diff --git a/sources/System/BumperTimer/BumperTimerSystem.cpp b/sources/System/BumperTimer/BumperTimerSystem.cpp new file mode 100644 index 00000000..36c8b93f --- /dev/null +++ b/sources/System/BumperTimer/BumperTimerSystem.cpp @@ -0,0 +1,25 @@ +// +// Created by Tom Augier on 2021-06-09. +// + +#include "BumperTimerSystem.hpp" + +namespace BBM +{ + BumperTimerSystem::BumperTimerSystem(WAL::Wal &wal) + : System(wal) + {} + + void BumperTimerSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + { + auto &bumperTimer = entity.get(); + + if (bumperTimer._isReseting) { + bumperTimer.nextReset -= dtime; + if (bumperTimer.nextReset <= 0ns) { + bumperTimer.nextReset = bumperTimer.resetRate; + bumperTimer._isReseting = false; + } + } + } +} \ No newline at end of file diff --git a/sources/System/BumperTimer/BumperTimerSystem.hpp b/sources/System/BumperTimer/BumperTimerSystem.hpp new file mode 100644 index 00000000..d1bbe2e8 --- /dev/null +++ b/sources/System/BumperTimer/BumperTimerSystem.hpp @@ -0,0 +1,29 @@ +// +// Created by Tom Augier on 2021-06-09. +// + +#pragma once + +#include "Component/Movable/MovableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/BumperTimer/BumperTimerComponent.hpp" +#include "System/System.hpp" + +namespace BBM +{ + //! @brief A system to handle BumperTimer entities. + class BumperTimerSystem : public WAL::System + { + public: + //! @inherit + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; + //! @brief A default constructor + explicit BumperTimerSystem(WAL::Wal &wal); + //! @brief A BumperTimer system is copy constructable + BumperTimerSystem(const BumperTimerSystem &) = default; + //! @brief A default destructor + ~BumperTimerSystem() override = default; + //! @brief A system is not assignable. + BumperTimerSystem &operator=(const BumperTimerSystem &) = delete; + }; +} \ No newline at end of file diff --git a/sources/System/Gravity/GravitySystem.cpp b/sources/System/Gravity/GravitySystem.cpp index 8e0801e1..6459ed79 100644 --- a/sources/System/Gravity/GravitySystem.cpp +++ b/sources/System/Gravity/GravitySystem.cpp @@ -16,6 +16,6 @@ namespace BBM auto &position = entity.get(); if (position.getY() > 0) - movable.addForce(Vector3f(0, -0.5, 0)); + movable.addForce(Vector3f(0, -0.1, 0)); } } \ No newline at end of file From 5878dd46f4b387f2ffcc7ca12dd17d7481f47fbc Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 10 Jun 2021 12:01:35 +0200 Subject: [PATCH 11/82] first commit on branch --- CMakeLists.txt | 2 ++ sources/Runner/Runner.cpp | 49 ++++++++++++++++++++++++++-- sources/Runner/Runner.hpp | 3 ++ sources/System/Lobby/LobbySystem.cpp | 15 +++++++++ sources/System/Lobby/LobbySystem.hpp | 23 +++++++++++++ 5 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 sources/System/Lobby/LobbySystem.cpp create mode 100644 sources/System/Lobby/LobbySystem.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b545bd0e..5cd8e63c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,8 @@ set(SOURCES sources/System/Sound/PlayerSoundManagerSystem.hpp sources/System/Music/MusicSystem.hpp sources/System/Music/MusicSystem.cpp + sources/System/Lobby/LobbySystem.cpp + sources/System/Lobby/LobbySystem.hpp ) add_executable(bomberman diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index ef0ab500..09c5fabb 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -49,6 +49,7 @@ #include "System/Sound/PlayerSoundManagerSystem.hpp" #include "System/Sound/MenuSoundManagerSystem.hpp" #include "System/Music/MusicSystem.hpp" +#include "System/Lobby/LobbySystem.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; namespace RAY2D = RAY::Drawables::Drawables2D; @@ -95,6 +96,7 @@ namespace BBM .addSystem() .addSystem() .addSystem() + .addSystem() .addSystem(); } @@ -171,7 +173,7 @@ namespace BBM }) .addComponent([](WAL::Entity &entity, WAL::Wal &) { - gameState.nextScene = BBM::GameState::SceneID::GameScene; + gameState.nextScene = BBM::GameState::SceneID::LobbyScene; }); auto &settings = scene->addEntity("settings button") .addComponent(1920 / 2.5, 1080 - 360, 0) @@ -237,6 +239,47 @@ namespace BBM return scene; } + std::shared_ptr Runner::loadLobbyScene() + { + static const std::map sounds = { + {SoundComponent::JUMP, "assets/sounds/click.ogg"} + }; + auto scene = std::make_shared(); + + scene->addEntity("Control entity") + .addComponent() + .addComponent() + .addComponent("assets/musics/music_player_select.ogg") + .addComponent(sounds); + scene->addEntity("background") + .addComponent() + .addComponent("assets/plain_menu_background.png"); + auto &play = scene->addEntity("play button") + .addComponent(1920 / 2.5, 1080 - 180, 0) + .addComponent("assets/buttons/button_new_game.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_new_game.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_new_game_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::GameScene; + }); + + auto &p1 = scene->addEntity("player1") + .addComponent(0, 0, 0) + .addComponent(); + return scene; + } + std::shared_ptr Runner::loadPauseMenuScene() { static const std::map sounds = { @@ -310,10 +353,9 @@ namespace BBM }) .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { + //empty scene gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; }); - //needed material - //music play.getComponent().setButtonLinks(nullptr, nullptr, nullptr, &settings); settings.getComponent().setButtonLinks(nullptr, nullptr, &play, &exit); exit.getComponent().setButtonLinks(nullptr, nullptr, &settings, nullptr); @@ -620,6 +662,7 @@ namespace BBM gameState._loadedScenes[GameState::SceneID::PauseMenuScene] = loadPauseMenuScene(); gameState._loadedScenes[GameState::SceneID::TitleScreenScene] = loadTitleScreenScene(); gameState._loadedScenes[GameState::SceneID::CreditScene] = loadCreditScene(); + gameState._loadedScenes[GameState::SceneID::LobbyScene] = loadLobbyScene(); } int Runner::run() diff --git a/sources/Runner/Runner.hpp b/sources/Runner/Runner.hpp index 6c42adfe..4e779d78 100644 --- a/sources/Runner/Runner.hpp +++ b/sources/Runner/Runner.hpp @@ -46,6 +46,9 @@ namespace BBM //! @brief load all data related to credit screen static std::shared_ptr loadCreditScene(); + //! @brief load all data related to lobby screen + static std::shared_ptr loadLobbyScene(); + //! @brief loads all scenes in the game state static void loadScenes(); }; diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp new file mode 100644 index 00000000..6eb2f87f --- /dev/null +++ b/sources/System/Lobby/LobbySystem.cpp @@ -0,0 +1,15 @@ +#include +#include "System/Lobby/LobbySystem.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Entity/Entity.hpp" + +namespace BBM +{ + LobbySystem::LobbySystem(WAL::Wal &wal) + : System(wal) + {} + + void LobbySystem::onSelfUpdate() + { + } +} \ No newline at end of file diff --git a/sources/System/Lobby/LobbySystem.hpp b/sources/System/Lobby/LobbySystem.hpp new file mode 100644 index 00000000..0e88c3e4 --- /dev/null +++ b/sources/System/Lobby/LobbySystem.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "System/System.hpp" + +namespace BBM +{ + //! @brief A system to handle Health entities. + class LobbySystem : public WAL::System<> + { + public: + //! @inherit + void onSelfUpdate() override; + + //! @brief A default constructor + explicit LobbySystem(WAL::Wal &wal); + //! @brief A Lobby system is copy constructable + LobbySystem(const LobbySystem &) = default; + //! @brief A default destructor + ~LobbySystem() override = default; + //! @brief A system is not assignable. + LobbySystem &operator=(const LobbySystem &) = delete; + }; +} \ No newline at end of file From fb805459be97d39f09783c44ef525df429fe3f92 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 10 Jun 2021 12:19:55 +0200 Subject: [PATCH 12/82] lobby --- assets/player/ai_icon.png | Bin 0 -> 19339 bytes assets/player/none_icon.png | Bin 0 -> 2145 bytes sources/Runner/Runner.cpp | 16 ++++++++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 assets/player/ai_icon.png create mode 100644 assets/player/none_icon.png diff --git a/assets/player/ai_icon.png b/assets/player/ai_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ccd108e6195bb0bf28b72205d7d1c5a0cd9e3c09 GIT binary patch literal 19339 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 XuDW9OmP1t600000NkvXXu0mjf2uLx) literal 0 HcmV?d00001 diff --git a/assets/player/none_icon.png b/assets/player/none_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..90adb3c0932020f5fb237d5c4bab0eb980c62ecd GIT binary patch literal 2145 zcma)7i&s)f9EP%tR01+hLpQEBE5l5C!M2JD$YnD{S516ubbw?De)aqL%WlMpv@h$r<04dr%OX|3hsOf z?j6AG2de+;i(ay%bc7gCpgNLd7||V=j1+E|r2j=YX=tP=KNo%<(`9Ti@=zx= zd^j)5oBWMNxo^@(?kS&!Ssb(1cFQV^Wqs8z&-}7s>G(Zs>?>xk9oD5>zj17(t|I_; zc9$B4`u4wEz2{T#WXGr+nG$IyEoHtbF&0^+5R1^h35EBq#38v&3+TVqhqEy()|?$Ot;St zVj^a1SPq01FK+W>ZP`;859HJ_C?nP6;=n>yTP7|$b+_mZUp#AP{ZirXzR1=XmMDFn zdt2LqIWzK+e|jF#{+)O-P+@%b%;Wc4)d4ME5p|1|f_duhy43`?Hcy3JdZ?GWSeo71 z)X%YBn1Gf{kuvT%s*19Xa`aWf>0Mu*yl?Q?;-zSMmg7iVJ+gomrP{J5;sr8sH*MEG znuP5WkgdG^slW*utJ96b{X2;(P&)75WeMp8QM8_TU%Y5MpGVkdh*iTPC)vK}N-qo+fi1`fa z-ZnS==Nd@qmT;?zD&bO(B$T1Wl~q{1s=a4FTqxRo(+$eNGS|U*WS&+S5c)1lxs>Bi z_1;A0pBUl4rV>Phfj}`Z+Jz=R3n|;lyapk+scwXiPF-$?rS@e}^fgnY_MgIo@Nbf- zBnrR4(n3@tLC~qyA5!3Tb)93c3uy94o9XjZgYFc)@8YcdT!w)E14JV>E9dES!#scL zvKMuLf3eDzAgYm?)jvOhDBd;xU}?q$8Ah_qNpzzy&s|p()i+I*GaAuVfU~ukPSN7$ zvSH1kMVh$;(R{aST;=nJ{j)6{PuS~LPn#8JK*#{vj#5!Yf%g006$_TnIJm%$^>0bmLRLZF&BPCa~X|`GqA__=wT&h zWoRgUzxL5U|E-bIHKmLbQnZ^3wT9mz_Vm{CpkG!H9WsuNY6Ha#l49I<=bBkPz0HI! z`ze0)CjBLo?Z?c#(n!;Ga8apS<5H*k12ASm56Dv!(E|^xyVzchs7)gXvoi4<` zWJqJ852y>upP}GyM=dHSUZ4#8maHI)mE1!b~B+hV$K~-9@2=q>W?)nQQhy|OeW;y)8uLeAD#hSH0KXN zJ5Ljm?-X7e(1EQQnJ>{t{6L-zS&J~_C2tv4Cjw~1D*{y79K0*pR ztrsM#9=z`24jZ~vE9X;AZrcpvZ^KU;1e_@zRU|P;&=U$m8!t#jiy%MuSUHV%c-ilbK~QMswPvZ= zuydq_=HjvRYT;f{TQ}o47dFY>2dH<&-l{%=SPSbywv184>b;%6rWbNd$B~(kd^cJW z52`k}xND3i#I^QS8k4AQvaa~yk8haa6PL>${0noGT8QW!9sUlg_R*fFL!OzcTqH*6 z^d&kyVUCP_X*LOEJ=f8a-Zpok zp;i~w!0OnzBBNj@CCoIt>%n-C52~XhzRO; zlDh`0*F5#2=oh(i;5#B%dyr~nytwgf1A-P)RTzn9;{(y;iJ72srqjWlu@3-|ZHJM> zHc|wwJ^UjWRhWSn4z2*!6~MzEm*g_Wqrlr$@1)b(GblV?F37PgAFSC#+DT&6zSK^- zl+%*Ka8%ms#?IG$%xIz!6()$;6J@2JvCu9=BYQokmotJ6g?q_}m~) JrT@m9{{TaddEntity("background") .addComponent() .addComponent("assets/plain_menu_background.png"); + scene->addEntity("lobby text") + .addComponent(1920 / 2.75, 100, 0) + .addComponent("Get Ready", 120, RAY::Vector2(), ORANGE); auto &play = scene->addEntity("play button") .addComponent(1920 / 2.5, 1080 - 180, 0) .addComponent("assets/buttons/button_new_game.png") @@ -275,8 +278,17 @@ namespace BBM }); auto &p1 = scene->addEntity("player1") - .addComponent(0, 0, 0) - .addComponent(); + .addComponent(224, 1080 / 3, 0) + .addComponent("assets/player/none_icon.png"); + auto &p2 = scene->addEntity("player2") + .addComponent(2 * 224 + 200, 1080 / 3, 0) + .addComponent("assets/player/none_icon.png"); + auto &p3 = scene->addEntity("player3") + .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) + .addComponent("assets/player/none_icon.png"); + auto &p4 = scene->addEntity("player4") + .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) + .addComponent("assets/player/none_icon.png"); return scene; } From 3e8e1fe1ecb7ee31ee6ac59dc3bfd60cb11219c3 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 10 Jun 2021 12:43:36 +0200 Subject: [PATCH 13/82] tiles for when a player is ready to play --- sources/Runner/Runner.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 2eca27d3..a34fbfa8 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -277,18 +277,41 @@ namespace BBM gameState.nextScene = BBM::GameState::SceneID::GameScene; }); + auto &p1tile = scene->addEntity("player1 tile") + .addComponent(224, 1080 / 3, 0) + .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p1 = scene->addEntity("player1") .addComponent(224, 1080 / 3, 0) .addComponent("assets/player/none_icon.png"); + auto &p2tile = scene->addEntity("player2 tile") + .addComponent(2 * 224 + 200, 1080 / 3, 0) + .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p2 = scene->addEntity("player2") .addComponent(2 * 224 + 200, 1080 / 3, 0) .addComponent("assets/player/none_icon.png"); + auto &p3tile = scene->addEntity("player3 tile") + .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) + .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p3 = scene->addEntity("player3") .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) .addComponent("assets/player/none_icon.png"); + auto &p4tile = scene->addEntity("player4 tile") + .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) + .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p4 = scene->addEntity("player4") .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) .addComponent("assets/player/none_icon.png"); + scene->addEntity("camera") + .addComponent(8, 20, 7) + .addComponent(Vector3f(8, 0, 8)); + //when a player is ready: + //tiles go green + auto &p1model = scene->addEntity("player1 model") + .addComponent() + .addComponent(224, 1080 / 3, 0) + .addComponent("assets/player/player.iqm", true, std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) + .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 3); + return scene; } From e0b44b84bbaaa6b8f15260ab95370e2391245abe Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 10 Jun 2021 13:51:54 +0200 Subject: [PATCH 14/82] no model will be displayed in the lobby, only matching colors (thx raylib) ' --- assets/player/valid_selection_icon.png | Bin 0 -> 6162 bytes sources/Runner/Runner.cpp | 14 ++++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 assets/player/valid_selection_icon.png diff --git a/assets/player/valid_selection_icon.png b/assets/player/valid_selection_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2f6327803767b2dce2a2e8b3c05a8da2105a8b GIT binary patch literal 6162 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, 20, 7) .addComponent(Vector3f(8, 0, 8)); //when a player is ready: - //tiles go green - auto &p1model = scene->addEntity("player1 model") - .addComponent() - .addComponent(224, 1080 / 3, 0) - .addComponent("assets/player/player.iqm", true, std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) - .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 3); + //p1tile.getComponent().drawable.get()->setColor(BLUE); + //p2tile.getComponent().drawable.get()->setColor(RED); + //p3tile.getComponent().drawable.get()->setColor(GREEN); + //p4tile.getComponent().drawable.get()->setColor(YELLOW); + + //pX + //RAY::Texture *txt = dynamic_cast(entity.getComponent().drawable.get()); + //txt->use("assets/player/valid_selection_icon.png") return scene; } From d328a976ed35b0e388b3bb0e7ae1a205ab94fdde Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 10 Jun 2021 13:54:28 +0200 Subject: [PATCH 15/82] no model will be displayed in the lobby, only matching colors (thx raylib) ' --- sources/Runner/Runner.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index a2d99777..47ee259a 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -314,6 +314,10 @@ namespace BBM //RAY::Texture *txt = dynamic_cast(entity.getComponent().drawable.get()); //txt->use("assets/player/valid_selection_icon.png") + //to do + // quand no player is reaydy, the play button should be diasbled + + //The other non-ready players shoudl be IAs return scene; } From 34f9301ac1c14a7c128f694571da55f315751181 Mon Sep 17 00:00:00 2001 From: Askou Date: Thu, 10 Jun 2021 14:45:35 +0200 Subject: [PATCH 16/82] Player can't walk on breakable and unbreakable --- sources/Map/Map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index 9d76bf45..daab3de5 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -180,7 +180,7 @@ namespace BBM .addComponent(1, &MapGenerator::wallDestroyed) .addComponent( WAL::Callback(), - &MapGenerator::wallCollide, 0.25, .75) + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, 0.25), Vector3f(0.75, 1.5, 0.75)) .addComponent(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng)); } @@ -219,7 +219,7 @@ namespace BBM .addComponent>() .addComponent( WAL::Callback(), - &MapGenerator::wallCollide, 0.25, .75) + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, 0.25), Vector3f(0.75, 1.5, 0.75)) .addComponent(UnbreakableObj, std::make_pair(MAP_DIFFUSE, UnbreakablePng)); } From 57f9d5446af7717b9063cd560cfe02ccb713f6cf Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 10 Jun 2021 15:10:14 +0200 Subject: [PATCH 17/82] add intro animation --- .../IntroAnimationComponent.cpp | 17 +++++++ .../IntroAnimationComponent.hpp | 40 ++++++++++++++++ .../IntroAnimation/IntroAnimationSystem.cpp | 46 +++++++++++++++++++ .../IntroAnimation/IntroAnimationSystem.hpp | 31 +++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 sources/Component/IntroAnimation/IntroAnimationComponent.cpp create mode 100644 sources/Component/IntroAnimation/IntroAnimationComponent.hpp create mode 100644 sources/System/IntroAnimation/IntroAnimationSystem.cpp create mode 100644 sources/System/IntroAnimation/IntroAnimationSystem.hpp diff --git a/sources/Component/IntroAnimation/IntroAnimationComponent.cpp b/sources/Component/IntroAnimation/IntroAnimationComponent.cpp new file mode 100644 index 00000000..261a168e --- /dev/null +++ b/sources/Component/IntroAnimation/IntroAnimationComponent.cpp @@ -0,0 +1,17 @@ +// +// Created by Zoe Roux on 5/24/21. +// + +#include "IntroAnimationComponent.hpp" + +namespace BBM +{ + IntroAnimationComponent::IntroAnimationComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + + WAL::Component *IntroAnimationComponent::clone(WAL::Entity &entity) const + { + return new IntroAnimationComponent(entity); + } +} \ No newline at end of file diff --git a/sources/Component/IntroAnimation/IntroAnimationComponent.hpp b/sources/Component/IntroAnimation/IntroAnimationComponent.hpp new file mode 100644 index 00000000..694b875a --- /dev/null +++ b/sources/Component/IntroAnimation/IntroAnimationComponent.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace BBM +{ + //! @brief A component to slowly center entities to the middle of their current block. + //! This allow flexibility in their movement will preventing them from getting stuck at every corner. + class IntroAnimationComponent : public WAL::Component + { + public: + unsigned int frame = 0; + + enum animationSteps { + init, + boxBlinking, + topLeftgrowing, + bottomRightGrowing, + lettersTyping, + fading, + prompt, + }; + + enum animationSteps currentStep = init; + + //! @inherit + Component *clone(WAL::Entity &entity) const override; + + //! @brief Create a new, default IntroAnimationComponent. + //! @param entity The entity attached to this component. + explicit IntroAnimationComponent(WAL::Entity &entity); + //! @brief A IntroAnimationComponent is copy constructable + //! @param other The other IntroAnimationComponent to copy. + IntroAnimationComponent(const IntroAnimationComponent &other) = default; + //! @brief A default destructor + ~IntroAnimationComponent() override = default; + //! @brief A IntroAnimationComponent is not assignable + IntroAnimationComponent &operator=(const IntroAnimationComponent &) = delete; + }; +} diff --git a/sources/System/IntroAnimation/IntroAnimationSystem.cpp b/sources/System/IntroAnimation/IntroAnimationSystem.cpp new file mode 100644 index 00000000..74f3a89a --- /dev/null +++ b/sources/System/IntroAnimation/IntroAnimationSystem.cpp @@ -0,0 +1,46 @@ + +#include +#include "Component/Button/ButtonComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "System/IntroAnimation/IntroAnimationSystem.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Entity/Entity.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include + +namespace RAY2D = RAY::Drawables::Drawables2D; + +namespace BBM +{ + IntroAnimationSystem::IntroAnimationSystem(WAL::Wal &wal) + : System(wal), wal(wal) + {} + + void IntroAnimationSystem::onFixedUpdate(WAL::ViewEntity &entity) + { + auto &component = entity.get(); + auto &scene = wal.getScene(); + + switch (component.currentStep) + { + case IntroAnimationComponent::animationSteps::init: + scene->addEntity("white background") + .addComponent(BBM::Vector2f(), BBM::Vector2f(1920, 1080), WHITE); + + scene->addEntity("blinking square").addComponent(BBM::Vector2f(), BBM::Vector2f(16, 16), WHITE); + component.currentStep = IntroAnimationComponent::animationSteps::boxBlinking; + break; + case IntroAnimationComponent::animationSteps::boxBlinking: + + if ((component.frame / 15) % 2) + scene->getEntities() + break; + + } + component.frame++; + } + + void IntroAnimationSystem::onSelfUpdate(void) + { + } +} \ No newline at end of file diff --git a/sources/System/IntroAnimation/IntroAnimationSystem.hpp b/sources/System/IntroAnimation/IntroAnimationSystem.hpp new file mode 100644 index 00000000..1a266443 --- /dev/null +++ b/sources/System/IntroAnimation/IntroAnimationSystem.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "Component/IntroAnimation/IntroAnimationComponent.hpp" +#include "System/System.hpp" + +namespace BBM +{ + //! @brief A system to handle Controllable entities in a menu. + class IntroAnimationSystem : public WAL::System + { + private: + //! @brief reference to wal + WAL::Wal &wal; + + public: + //! @inherit + void onSelfUpdate(void) override; + + //! @inherit + void onFixedUpdate(WAL::ViewEntity &entities) override; + + //! @brief A default constructor + IntroAnimationSystem(WAL::Wal &wal); + //! @brief A IntroAnimation system is not copy constructable + IntroAnimationSystem(const IntroAnimationSystem &) = delete; + //! @brief A default destructor + ~IntroAnimationSystem() override = default; + //! @brief A IntroAnimation system is assignable. + IntroAnimationSystem &operator=(const IntroAnimationSystem &) = default; + }; +} \ No newline at end of file From e38c2e56fe2233ed465aabebc35685e215b256ae Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 10 Jun 2021 18:05:56 +0200 Subject: [PATCH 18/82] Making menues selectable by keyboard or controller --- sources/Runner/Runner.cpp | 41 ++++++++------- sources/Runner/Runner.hpp | 2 + sources/System/Gamepad/GamepadSystem.cpp | 2 +- .../MenuControllableSystem.cpp | 51 +++++++++---------- .../MenuControllableSystem.hpp | 27 +++------- 5 files changed, 53 insertions(+), 70 deletions(-) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 47ee259a..a024af9e 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -115,9 +115,8 @@ namespace BBM {SoundComponent::JUMP, "assets/sounds/click.ogg"} }; auto scene = std::make_shared(); + addMenuControl(*scene); scene->addEntity("control") - .addComponent() - .addComponent() .addComponent(sounds) .addComponent("assets/musics/music_title.ogg"); scene->addEntity("background") @@ -145,9 +144,8 @@ namespace BBM }; auto scene = std::make_shared(); + addMenuControl(*scene); scene->addEntity("Control entity") - .addComponent() - .addComponent() .addComponent("assets/musics/music_title.ogg") .addComponent(sounds); scene->addEntity("background") @@ -246,9 +244,8 @@ namespace BBM }; auto scene = std::make_shared(); + addMenuControl(*scene); scene->addEntity("Control entity") - .addComponent() - .addComponent() .addComponent("assets/musics/music_player_select.ogg") .addComponent(sounds); scene->addEntity("background") @@ -328,9 +325,8 @@ namespace BBM }; auto scene = std::make_shared(); + addMenuControl(*scene); scene->addEntity("Control entity") - .addComponent() - .addComponent() .addComponent("assets/musics/music_player_select.ogg") .addComponent(sounds); scene->addEntity("background") @@ -410,9 +406,8 @@ namespace BBM {SoundComponent::JUMP, "assets/sounds/click.ogg"} }; + addMenuControl(*scene); scene->addEntity("Control entity") - .addComponent() - .addComponent() .addComponent("assets/musics/music_title.ogg") .addComponent(sounds); scene->addEntity("background") @@ -599,9 +594,6 @@ namespace BBM std::shared_ptr Runner::loadGameScene() { auto scene = std::make_shared(); - scene->addEntity("control") - .addComponent() - .addComponent(); std::map soundPath ={ {SoundComponent::JUMP, "assets/sounds/jump.wav"}, {SoundComponent::MOVE, "assets/sounds/move.ogg"}, @@ -647,14 +639,6 @@ namespace BBM .addComponent("assets/plain_menu_background.png"); scene->addEntity("Control entity") - /*scene->addEntity("cube") - .addComponent(5, 0, 5) - .addComponent("assets/shaders/glsl330/grayscale.fs") - //.addComponent(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED) - .addComponent(BBM::Vector2f{200,200}, BBM::Vector2f{200, 200}, RED) - .addComponent() - .addComponent() - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, 3); */ .addComponent("assets/musics/music_title.ogg") .addComponent(sounds); @@ -695,6 +679,21 @@ namespace BBM return scene; } + void Runner::addMenuControl(WAL::Scene &scene) + { + scene.addEntity("Keyboard default control") + .addComponent() + .addComponent(); + scene.addEntity("Keyboard second control") + .addComponent() + .addComponent(KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_RIGHT_CONTROL, KEY_ENTER, KEY_BACKSPACE); + for (int i = 0; i < 4; i++) { + scene.addEntity("Gamepad controller") + .addComponent() + .addComponent(i); + } + } + void Runner::loadScenes() { gameState._loadedScenes[GameState::SceneID::MainMenuScene] = loadMainMenuScene(); diff --git a/sources/Runner/Runner.hpp b/sources/Runner/Runner.hpp index 4e779d78..934be51c 100644 --- a/sources/Runner/Runner.hpp +++ b/sources/Runner/Runner.hpp @@ -28,6 +28,8 @@ namespace BBM //! @brief init all raylib-related data & context static void enableRaylib(WAL::Wal &wal); + static void addMenuControl(WAL::Scene &scene); + //! @brief load all data related to title screen static std::shared_ptr loadTitleScreenScene(); diff --git a/sources/System/Gamepad/GamepadSystem.cpp b/sources/System/Gamepad/GamepadSystem.cpp index ee4b8767..6e10a488 100644 --- a/sources/System/Gamepad/GamepadSystem.cpp +++ b/sources/System/Gamepad/GamepadSystem.cpp @@ -30,7 +30,7 @@ namespace BBM }; for (auto key : keyPressedMap) - key.second = gamepad.isPressed(key.first); + key.second = gamepad.isDown(key.first); controllable.move.x = gamepad.getAxisValue(gamepadComponent.LeftStickX) * -1; controllable.move.y = gamepad.getAxisValue(gamepadComponent.LeftStickY) * -1; controllable.move.x -= gamepad.isDown(gamepadComponent.keyRight); diff --git a/sources/System/MenuControllable/MenuControllableSystem.cpp b/sources/System/MenuControllable/MenuControllableSystem.cpp index 551c01dc..bccee926 100644 --- a/sources/System/MenuControllable/MenuControllableSystem.cpp +++ b/sources/System/MenuControllable/MenuControllableSystem.cpp @@ -12,12 +12,13 @@ namespace BBM { MenuControllableSystem::MenuControllableSystem(WAL::Wal &wal) - : System(wal), wal(wal), currentButton() + : System(wal), + _currentButton() {} - void MenuControllableSystem::updateCurrentButton(bool selected) + void MenuControllableSystem::_updateCurrentButton(bool selected, Vector2f move) { - auto buttonComponent = this->currentButton->getComponent(); + auto &buttonComponent = this->_currentButton->getComponent(); WAL::Entity *newButton = nullptr; if (move.y > 0 && buttonComponent._up) @@ -28,42 +29,38 @@ namespace BBM newButton = buttonComponent._right; if (move.x > 0 && buttonComponent._left) newButton = buttonComponent._left; + + if (newButton || selected) { + auto lastTick = std::chrono::steady_clock::now(); + if (lastTick - this->_now < std::chrono::milliseconds(150)) + return; + this->_now = lastTick; + } + if (newButton) { - this->currentButton->getComponent().onEvent(*this->currentButton, wal); - this->currentButton = newButton; - this->currentButton->getComponent().onEvent(*this->currentButton, wal); + this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); + this->_currentButton = newButton; + this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); } if (selected) - this->currentButton->getComponent().onEvent(*this->currentButton, wal); + this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); } void MenuControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) { - auto lastTick = std::chrono::steady_clock::now(); auto &controllable = entity.get(); auto &buttons = _wal.getScene()->view(); - - if (lastTick - this->_now < std::chrono::milliseconds(100)) - return; - this->_now = lastTick; - move = controllable.move; - select = controllable.jump; - if (currentButton && currentButton->_scene.getID() != wal.getScene()->getID()) { - currentButton->getComponent().onEvent(*this->currentButton, wal); - currentButton = nullptr; + if (this->_currentButton && this->_currentButton->_scene.getID() != this->_wal.getScene()->getID()) { + this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); + this->_currentButton = nullptr; } - if (currentButton == nullptr && buttons.size()) { - currentButton = &(**buttons.begin()); - currentButton->getComponent().onEvent(*this->currentButton, wal); + if (this->_currentButton == nullptr && buttons.size()) { + this->_currentButton = &(*buttons.front()); + this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); } - if (!currentButton) + if (!this->_currentButton) return; - this->updateCurrentButton(select); - } - - void MenuControllableSystem::onSelfUpdate(void) - { - + this->_updateCurrentButton(controllable.jump, controllable.move); } } \ No newline at end of file diff --git a/sources/System/MenuControllable/MenuControllableSystem.hpp b/sources/System/MenuControllable/MenuControllableSystem.hpp index 86e16130..068d7192 100644 --- a/sources/System/MenuControllable/MenuControllableSystem.hpp +++ b/sources/System/MenuControllable/MenuControllableSystem.hpp @@ -14,41 +14,26 @@ namespace BBM class MenuControllableSystem : public WAL::System { private: - //! @brief reference to wal - WAL::Wal &wal; - //! @brief index of the current button selected - WAL::Entity *currentButton; - - //! @brief move vector - Vector2f move; - - //! @brief Select action - bool select = false; - - //! @brief Cancel action - bool cancel = false; + WAL::Entity *_currentButton; //! @brief update current button reference //! @param selected lets know if te new selected button is 'pressed' - void updateCurrentButton(bool selected); + void _updateCurrentButton(bool selected, Vector2f move); - //! @brief time (in mili second) since last check + //! @brief time (in millisecond) since last check std::chrono::time_point _now; public: - //! @inherit - void onSelfUpdate(void) override; - //! @inherit void onFixedUpdate(WAL::ViewEntity &entities) override; //! @brief A default constructor - MenuControllableSystem(WAL::Wal &wal); + explicit MenuControllableSystem(WAL::Wal &wal); //! @brief A MenuControllable system is not copy constructable MenuControllableSystem(const MenuControllableSystem &) = delete; //! @brief A default destructor ~MenuControllableSystem() override = default; - //! @brief A MenuControllable system is assignable. - MenuControllableSystem &operator=(const MenuControllableSystem &) = default; + //! @brief A MenuControllable system is not assignable. + MenuControllableSystem &operator=(const MenuControllableSystem &) = delete; }; } From 46491ce367fa41f17ae5fc88762d634b533e2f61 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 10 Jun 2021 19:03:16 +0200 Subject: [PATCH 19/82] Trying things --- sources/Runner/Runner.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index a024af9e..ef6b79f3 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -302,14 +302,13 @@ namespace BBM .addComponent(8, 20, 7) .addComponent(Vector3f(8, 0, 8)); //when a player is ready: - //p1tile.getComponent().drawable.get()->setColor(BLUE); + p1tile.getComponent().drawable.get()->setColor(BLUE); //p2tile.getComponent().drawable.get()->setColor(RED); //p3tile.getComponent().drawable.get()->setColor(GREEN); //p4tile.getComponent().drawable.get()->setColor(YELLOW); //pX - //RAY::Texture *txt = dynamic_cast(entity.getComponent().drawable.get()); - //txt->use("assets/player/valid_selection_icon.png") + p1.getComponent().drawable = std::make_shared("assets/player/valid_selection_icon.png"); //to do // quand no player is reaydy, the play button should be diasbled From 2a82f46e498270ef8ad4a69c2a8536eb02ebf29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Thu, 10 Jun 2021 23:12:47 +0200 Subject: [PATCH 20/82] adding blowable tag to bonuses but the bomb exploded the bonuses instantly --- sources/Map/Map.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index fb9ef9b3..d8522618 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -53,6 +53,7 @@ namespace BBM return; wal.getScene()->scheduleNewEntity("Bonus") .addComponent(position) + .addComponent>() .addComponent(1, [](WAL::Entity &entity, WAL::Wal &wal) { entity.scheduleDeletion(); }) From 74072064ea92277ae2c76a036472641849698eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Fri, 11 Jun 2021 00:11:34 +0200 Subject: [PATCH 21/82] trying to save prevPos but it doesn't work --- .../System/BombHolder/BombHolderSystem.cpp | 31 +++++++++++++------ .../System/BombHolder/BombHolderSystem.hpp | 7 ++++- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 6a5dac6e..4a582b26 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -30,16 +30,16 @@ namespace BBM return MapGenerator::wallCollided( entity, bomb, collidedAxis); } - BombHolderSystem::BombHolderSystem(WAL::Wal &wal) : System(wal) {} - void BombHolderSystem::_dispatchExplosion(Vector3f position, WAL::Wal &wal, int count) + void BombHolderSystem::_dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, const Vector3f &posFrom) { - if (count <= 0) + if (radiusToDo <= 0) return; - wal.getSystem().dispatchEvent([position, count](WAL::Wal &wal) { + std::cout << "exploding at " << position << std::endl; + wal.getSystem().dispatchEvent([position, radiusToDo, posFrom](WAL::Wal &wal) { for (auto &[entity, pos, _] : wal.getScene()->view>()) { if (pos.position.round() == position) { if (auto *health = entity.tryGetComponent()) @@ -47,10 +47,23 @@ namespace BBM return; } } - _dispatchExplosion(position + Vector3f(1, 0, 0), wal, count - 1); - _dispatchExplosion(position + Vector3f(-1, 0, 0), wal, count - 1); - _dispatchExplosion(position + Vector3f(0, 0, 1), wal, count - 1); - _dispatchExplosion(position + Vector3f(0, 0, -1), wal, count - 1); + const Vector3f expandVectors[] = { + {1, 0, 0}, + {-1, 0, 0}, + {0, 0, 1}, + {0, 0, -1}, + }; + + // should be true only at the first iteration + bool alwaysDispatch = position == posFrom; + + for (const auto &expandVector : expandVectors) { + Vector3f newPos = position + expandVector; + if (!alwaysDispatch && newPos == posFrom) { + continue; + } + _dispatchExplosion(newPos, wal, radiusToDo - 1, position); + } }); } @@ -59,7 +72,7 @@ namespace BBM bomb.scheduleDeletion(); auto position = bomb.getComponent().position.round(); auto explosionRadius = bomb.getComponent().explosionRadius; - _dispatchExplosion(position, wal, 3 + (explosionRadius - 3)); + _dispatchExplosion(position, wal, explosionRadius); } void BombHolderSystem::_spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id) diff --git a/sources/System/BombHolder/BombHolderSystem.hpp b/sources/System/BombHolder/BombHolderSystem.hpp index 481d7697..6c872ca8 100644 --- a/sources/System/BombHolder/BombHolderSystem.hpp +++ b/sources/System/BombHolder/BombHolderSystem.hpp @@ -22,7 +22,12 @@ namespace BBM void _spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id); //! @brief Spawn a bomb at the specified position. - static void _dispatchExplosion(Vector3f position, WAL::Wal &, int count); + static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, const Vector3f &posFrom); + + //! @brief Wrapped call to specify default arg value + inline static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo) { + return _dispatchExplosion(position, wal, radiusToDo, position); + }; //! @brief The method triggered when the bomb explode. static void _bombExplosion(WAL::Entity &bomb, WAL::Wal &); From 0e54d833611965eb0b201a8185f6be904aca5078 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 09:21:17 +0200 Subject: [PATCH 22/82] add back button to lobby scene --- sources/Runner/Runner.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 47ee259a..bc56358b 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -257,6 +257,26 @@ namespace BBM scene->addEntity("lobby text") .addComponent(1920 / 2.75, 100, 0) .addComponent("Get Ready", 120, RAY::Vector2(), ORANGE); + + auto &back = scene->addEntity("back to menu") + .addComponent(10, 1080 - 85, 0) + .addComponent("assets/buttons/button_back.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back_hovered.png"); + }); auto &play = scene->addEntity("play button") .addComponent(1920 / 2.5, 1080 - 180, 0) .addComponent("assets/buttons/button_new_game.png") @@ -318,6 +338,8 @@ namespace BBM // quand no player is reaydy, the play button should be diasbled //The other non-ready players shoudl be IAs + play.getComponent().setButtonLinks(nullptr, nullptr, &back, nullptr); + back.getComponent().setButtonLinks(nullptr, nullptr, nullptr, &play); return scene; } From 01e5900bbefba5534f502ee5a44af8af0d3fa36a Mon Sep 17 00:00:00 2001 From: Askou Date: Fri, 11 Jun 2021 09:39:31 +0200 Subject: [PATCH 23/82] check in collision if it's a movable --- sources/Map/Map.cpp | 8 ++--- sources/System/Collision/CollisionSystem.cpp | 31 +++++++++++++------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index daab3de5..acc5b671 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -282,7 +282,7 @@ namespace BBM { double rnd = static_cast(std::rand()) / RAND_MAX; - if (rnd > 0.60) { + if (rnd > 0.01) { for (int i = 0; i < width + 1; i++) { map[std::make_tuple(i, 1, height)] = map[std::make_tuple(i, 0, height)]; map[std::make_tuple(i, 0, height)] = UPPERFLOOR; @@ -295,12 +295,10 @@ namespace BBM map[std::make_tuple(width, -1, 1)] = BUMPER; map[std::make_tuple(width / 2, -1, height - 1)] = BUMPER; map[std::make_tuple(width / 2, -1, 1)] = BUMPER; - } - if (rnd > 0.30) { + } + if (rnd > 0.01) { for (int i = width / 2 - width / 4; i < width / 2 + width / 4 + 1; i++) { for (int j = height / 2 - height / 4; j < height / 2 + height / 4 + 1; j++) { - if (map[std::make_tuple(i, 0, j)] == FLOOR) - continue; map[std::make_tuple(i, 1, j)] = map[std::make_tuple(i, 0, j)]; map[std::make_tuple(i, 0, j)] = UPPERFLOOR; } diff --git a/sources/System/Collision/CollisionSystem.cpp b/sources/System/Collision/CollisionSystem.cpp index db68e3c0..ce924797 100644 --- a/sources/System/Collision/CollisionSystem.cpp +++ b/sources/System/Collision/CollisionSystem.cpp @@ -31,23 +31,30 @@ namespace BBM Vector3f pointAx = pointA; Vector3f pointAy = pointA; Vector3f pointAz = pointA; + bool isMovable = false; + Vector3f minAy; + Vector3f maxAy; + Vector3f minAz; + Vector3f maxAz; if (auto *movable = entity->tryGetComponent()) { auto vel = movable->getVelocity(); pointAx.x += vel.x; pointAy.y += vel.y; pointAz.z += vel.z; + isMovable = true; } Vector3f minAx = Vector3f::min(pointAx, pointAx + colA.bound); Vector3f maxAx = Vector3f::max(pointAx, pointAx + colA.bound); - Vector3f minAy = Vector3f::min(pointAy, pointAy + colA.bound); - Vector3f maxAy = Vector3f::max(pointAy, pointAy + colA.bound); - - Vector3f minAz = Vector3f::min(pointAz, pointAz + colA.bound); - Vector3f maxAz = Vector3f::max(pointAz, pointAz + colA.bound); + if (isMovable) { + minAy = Vector3f::min(pointAy, pointAy + colA.bound); + maxAy = Vector3f::max(pointAy, pointAy + colA.bound); + minAz = Vector3f::min(pointAz, pointAz + colA.bound); + maxAz = Vector3f::max(pointAz, pointAz + colA.bound); + } for (auto &[other, posB, colB] : this->getView()) { if (other.getUid() == entity->getUid()) continue; @@ -60,13 +67,15 @@ namespace BBM Vector3f maxB = Vector3f::max(pointB, pointB + colB.bound); if (boxesCollide(minAx, maxAx, minB, maxB)) { - collidedAxis += CollisionComponent::CollidedAxis::X; + collidedAxis += isMovable ? CollisionComponent::CollidedAxis::X : 7; } - if (boxesCollide(minAy, maxAy, minB, maxB)) { - collidedAxis += CollisionComponent::CollidedAxis::Y; - } - if (boxesCollide(minAz, maxAz, minB, maxB)) { - collidedAxis += CollisionComponent::CollidedAxis::Z; + if (isMovable) { + if (boxesCollide(minAy, maxAy, minB, maxB)) { + collidedAxis += CollisionComponent::CollidedAxis::Y; + } + if (boxesCollide(minAz, maxAz, minB, maxB)) { + collidedAxis += CollisionComponent::CollidedAxis::Z; + } } if (collidedAxis) { colA.onCollide(entity, other, static_cast(collidedAxis)); From bbe543bc1f0acbd12184450e2b6fd249d4147e03 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 10:23:45 +0200 Subject: [PATCH 24/82] add play customization options (to move to lobby --- sources/Runner/Runner.cpp | 74 ++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 1cabcabd..5b5111f8 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -434,11 +434,11 @@ namespace BBM scene->addEntity("background") .addComponent() .addComponent("assets/plain_menu_background.png"); - scene->addEntity("logo") - .addComponent(1920 / 3, 180, 0) - .addComponent("assets/logo_small.png"); + //scene->addEntity("logo") + // .addComponent(180, 180, 0) + // .addComponent("assets/logo_small.png"); auto &music = scene->addEntity("music text") - .addComponent(1920 / 2.5, 1080 - 540, 0) + .addComponent(1920 / 2.5, 180, 0) .addComponent("Music Volume", 70, RAY::Vector2(), BLACK) .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -451,7 +451,7 @@ namespace BBM }); auto &musicUp = scene->addEntity("music up button") - .addComponent(1920 / 1.5, 1080 - 540, 0) + .addComponent(1920 / 1.5, 180, 0) .addComponent("assets/buttons/button_plus.png") .addComponent("assets/musics/music_title.ogg") .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -474,7 +474,7 @@ namespace BBM }); auto &musicDown = scene->addEntity("music down button") - .addComponent(1920 / 3, 1080 - 540, 0) + .addComponent(1920 / 3, 180, 0) .addComponent("assets/buttons/button_minus.png") .addComponent("assets/musics/music_title.ogg") .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -497,7 +497,7 @@ namespace BBM }); auto &sound = scene->addEntity("sound text") - .addComponent(1920 / 2.5, 1080 - 360, 0) + .addComponent(1920 / 2.5, 360, 0) .addComponent("Sound Volume", 70, RAY::Vector2(), BLACK) .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -510,7 +510,7 @@ namespace BBM }); auto &soundUp = scene->addEntity("sound up button") - .addComponent(1920 / 1.5, 1080 - 360, 0) + .addComponent(1920 / 1.5, 360, 0) .addComponent("assets/buttons/button_plus.png") .addComponent(sounds) .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -533,7 +533,7 @@ namespace BBM }); auto &soundDown = scene->addEntity("sound down button") - .addComponent(1920 / 3, 1080 - 360, 0) + .addComponent(1920 / 3, 360, 0) .addComponent("assets/buttons/button_minus.png") .addComponent(sounds) .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -556,7 +556,7 @@ namespace BBM }); auto &debug = scene->addEntity("debug text") - .addComponent(1920 / 2.5, 1080 - 180, 0) + .addComponent(1920 / 2.5, 540, 0) .addComponent("Debug Mode: Off", 70, RAY::Vector2(), BLACK) .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { @@ -578,6 +578,54 @@ namespace BBM { entity.getComponent().drawable->setColor(ORANGE); }); + + auto &lavaOption = scene->addEntity("lava option text") + .addComponent(1920 / 2.5, 720, 0) + .addComponent("Lava: Off", 70, RAY::Vector2(), BLACK) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + if (text->getString().find("Off") != std::string::npos) { + text->setText("Lava: On"); + //do + } else { + text->setText("Lava: Off"); + //do + } + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(ORANGE); + }); + + auto &heightOption = scene->addEntity("Height option text") + .addComponent(1920 / 2.5, 900, 0) + .addComponent("2nd Level: Off", 70, RAY::Vector2(), BLACK) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + if (text->getString().find("Off") != std::string::npos) { + text->setText("2nd Level: On"); + //do + } else { + text->setText("2nd Level: Off"); + //do + } + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(ORANGE); + }); auto &back = scene->addEntity("back to menu") .addComponent(10, 1080 - 85, 0) .addComponent("assets/buttons/button_back.png") @@ -607,8 +655,10 @@ namespace BBM sound.getComponent().setButtonLinks(&music, &debug, &soundDown, &soundUp); soundDown.getComponent().setButtonLinks(&music, &debug, nullptr, &sound); soundUp.getComponent().setButtonLinks(&music, &debug, &sound); - debug.getComponent().setButtonLinks(&sound, &back, &back); - back.getComponent().setButtonLinks(&debug, nullptr, nullptr, &debug); + debug.getComponent().setButtonLinks(&sound, &lavaOption); + lavaOption.getComponent().setButtonLinks(&debug, &heightOption); + heightOption.getComponent().setButtonLinks(&lavaOption, &back, &back); + back.getComponent().setButtonLinks(&heightOption, nullptr, nullptr, &debug); return scene; } From a333de99e54d6de791bc8bcaaf850afcf562ce7b Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 10:39:06 +0200 Subject: [PATCH 25/82] play customization options move to lobby --- sources/Runner/Runner.cpp | 149 +++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 74 deletions(-) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 5b5111f8..ed6d5175 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -254,6 +254,26 @@ namespace BBM scene->addEntity("lobby text") .addComponent(1920 / 2.75, 100, 0) .addComponent("Get Ready", 120, RAY::Vector2(), ORANGE); + auto &play = scene->addEntity("play button") + .addComponent(1920 / 2.5, 1080 - 180, 0) + .addComponent("assets/buttons/button_new_game.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_new_game.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_new_game_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::GameScene; + }); + auto &back = scene->addEntity("back to menu") .addComponent(10, 1080 - 85, 0) @@ -274,24 +294,52 @@ namespace BBM texture->use("assets/buttons/button_back_hovered.png"); }); - auto &play = scene->addEntity("play button") - .addComponent(1920 / 2.5, 1080 - 180, 0) - .addComponent("assets/buttons/button_new_game.png") + auto &lavaOption = scene->addEntity("lava option text") + .addComponent(1920 / 6, 2 * 1080 / 3, 0) + .addComponent("Lava: Off", 70, RAY::Vector2(), BLACK) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + if (text->getString().find("Off") != std::string::npos) { + text->setText("Lava: On"); + //do + } else { + text->setText("Lava: Off"); + //do + } + }) .addComponent([](WAL::Entity &entity, WAL::Wal &) { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_new_game.png"); + entity.getComponent().drawable->setColor(BLACK); }) .addComponent([](WAL::Entity &entity, WAL::Wal &) { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + entity.getComponent().drawable->setColor(ORANGE); + }); - texture->use("assets/buttons/button_new_game_hovered.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) + auto &heightOption = scene->addEntity("Height option text") + .addComponent(1920 / 1.75, 2 * 1080 / 3, 0) + .addComponent("2nd Level: Off", 70, RAY::Vector2(), BLACK) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { - gameState.nextScene = BBM::GameState::SceneID::GameScene; + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + if (text->getString().find("Off") != std::string::npos) { + text->setText("2nd Level: On"); + //do + } else { + text->setText("2nd Level: Off"); + //do + } + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(ORANGE); }); auto &p1tile = scene->addEntity("player1 tile") @@ -334,8 +382,10 @@ namespace BBM // quand no player is reaydy, the play button should be diasbled //The other non-ready players shoudl be IAs - play.getComponent().setButtonLinks(nullptr, nullptr, &back, nullptr); - back.getComponent().setButtonLinks(nullptr, nullptr, nullptr, &play); + play.getComponent().setButtonLinks(&lavaOption, &back, &back, nullptr); + back.getComponent().setButtonLinks(&play, nullptr, nullptr, &play); + lavaOption.getComponent().setButtonLinks(nullptr, &play, nullptr, &heightOption); + heightOption.getComponent().setButtonLinks(nullptr, &play, &lavaOption, nullptr); return scene; } @@ -434,11 +484,11 @@ namespace BBM scene->addEntity("background") .addComponent() .addComponent("assets/plain_menu_background.png"); - //scene->addEntity("logo") - // .addComponent(180, 180, 0) - // .addComponent("assets/logo_small.png"); + scene->addEntity("logo") + .addComponent(1920 / 3, 180, 0) + .addComponent("assets/logo_small.png"); auto &music = scene->addEntity("music text") - .addComponent(1920 / 2.5, 180, 0) + .addComponent(1920 / 2.5, 1080 - 540, 0) .addComponent("Music Volume", 70, RAY::Vector2(), BLACK) .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -451,7 +501,7 @@ namespace BBM }); auto &musicUp = scene->addEntity("music up button") - .addComponent(1920 / 1.5, 180, 0) + .addComponent(1920 / 1.5, 1080 - 540, 0) .addComponent("assets/buttons/button_plus.png") .addComponent("assets/musics/music_title.ogg") .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -474,7 +524,7 @@ namespace BBM }); auto &musicDown = scene->addEntity("music down button") - .addComponent(1920 / 3, 180, 0) + .addComponent(1920 / 3, 1080 - 540, 0) .addComponent("assets/buttons/button_minus.png") .addComponent("assets/musics/music_title.ogg") .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -497,7 +547,7 @@ namespace BBM }); auto &sound = scene->addEntity("sound text") - .addComponent(1920 / 2.5, 360, 0) + .addComponent(1920 / 2.5, 1080 - 360, 0) .addComponent("Sound Volume", 70, RAY::Vector2(), BLACK) .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -510,7 +560,7 @@ namespace BBM }); auto &soundUp = scene->addEntity("sound up button") - .addComponent(1920 / 1.5, 360, 0) + .addComponent(1920 / 1.5, 1080 - 360, 0) .addComponent("assets/buttons/button_plus.png") .addComponent(sounds) .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -533,7 +583,7 @@ namespace BBM }); auto &soundDown = scene->addEntity("sound down button") - .addComponent(1920 / 3, 360, 0) + .addComponent(1920 / 3, 1080 - 360, 0) .addComponent("assets/buttons/button_minus.png") .addComponent(sounds) .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -556,7 +606,7 @@ namespace BBM }); auto &debug = scene->addEntity("debug text") - .addComponent(1920 / 2.5, 540, 0) + .addComponent(1920 / 2.5, 1080 - 180, 0) .addComponent("Debug Mode: Off", 70, RAY::Vector2(), BLACK) .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { @@ -579,53 +629,6 @@ namespace BBM entity.getComponent().drawable->setColor(ORANGE); }); - auto &lavaOption = scene->addEntity("lava option text") - .addComponent(1920 / 2.5, 720, 0) - .addComponent("Lava: Off", 70, RAY::Vector2(), BLACK) - .addComponent([](WAL::Entity &entity, WAL::Wal &wal) - { - RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); - - if (text->getString().find("Off") != std::string::npos) { - text->setText("Lava: On"); - //do - } else { - text->setText("Lava: Off"); - //do - } - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(BLACK); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(ORANGE); - }); - - auto &heightOption = scene->addEntity("Height option text") - .addComponent(1920 / 2.5, 900, 0) - .addComponent("2nd Level: Off", 70, RAY::Vector2(), BLACK) - .addComponent([](WAL::Entity &entity, WAL::Wal &wal) - { - RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); - - if (text->getString().find("Off") != std::string::npos) { - text->setText("2nd Level: On"); - //do - } else { - text->setText("2nd Level: Off"); - //do - } - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(BLACK); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(ORANGE); - }); auto &back = scene->addEntity("back to menu") .addComponent(10, 1080 - 85, 0) .addComponent("assets/buttons/button_back.png") @@ -655,10 +658,8 @@ namespace BBM sound.getComponent().setButtonLinks(&music, &debug, &soundDown, &soundUp); soundDown.getComponent().setButtonLinks(&music, &debug, nullptr, &sound); soundUp.getComponent().setButtonLinks(&music, &debug, &sound); - debug.getComponent().setButtonLinks(&sound, &lavaOption); - lavaOption.getComponent().setButtonLinks(&debug, &heightOption); - heightOption.getComponent().setButtonLinks(&lavaOption, &back, &back); - back.getComponent().setButtonLinks(&heightOption, nullptr, nullptr, &debug); + debug.getComponent().setButtonLinks(&sound, &back, &back); + back.getComponent().setButtonLinks(&debug, nullptr, nullptr, &debug); return scene; } From dc453362a895d19b9037987296b6a80fe9d9ee06 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 10:47:23 +0200 Subject: [PATCH 26/82] lobby system: player connected texture update --- sources/System/Lobby/LobbySystem.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index 6eb2f87f..387daa1e 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -12,4 +12,10 @@ namespace BBM void LobbySystem::onSelfUpdate() { } + + //void LobbySystem::updateEntityConnectedUser(WAL::Entity &entity) + //{ + // RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + // texture->use("assets/player/blue.png"); + //} } \ No newline at end of file From a2e637d66826b6684c82b54853a1761e4aea5c69 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 11:03:19 +0200 Subject: [PATCH 27/82] icons for lobby --- assets/player/{ai_icon.png => icons/ai.png} | Bin assets/player/icons/blue.png | Bin 0 -> 16133 bytes assets/player/icons/green.png | Bin 0 -> 19280 bytes assets/player/{none_icon.png => icons/none.png} | Bin assets/player/icons/red.png | Bin 0 -> 20610 bytes assets/player/icons/yellow.png | Bin 0 -> 18910 bytes assets/player/{ => textures}/blue.png | Bin assets/player/{ => textures}/cyan.png | Bin assets/player/{ => textures}/green.png | Bin assets/player/{ => textures}/purple.png | Bin assets/player/{ => textures}/red.png | Bin assets/player/{ => textures}/yellow.png | Bin assets/player/valid_selection_icon.png | Bin 6162 -> 0 bytes sources/Runner/Runner.cpp | 12 ++++++------ sources/System/Lobby/LobbySystem.cpp | 2 +- 15 files changed, 7 insertions(+), 7 deletions(-) rename assets/player/{ai_icon.png => icons/ai.png} (100%) create mode 100644 assets/player/icons/blue.png create mode 100644 assets/player/icons/green.png rename assets/player/{none_icon.png => icons/none.png} (100%) create mode 100644 assets/player/icons/red.png create mode 100644 assets/player/icons/yellow.png rename assets/player/{ => textures}/blue.png (100%) rename assets/player/{ => textures}/cyan.png (100%) rename assets/player/{ => textures}/green.png (100%) rename assets/player/{ => textures}/purple.png (100%) rename assets/player/{ => textures}/red.png (100%) rename assets/player/{ => textures}/yellow.png (100%) delete mode 100644 assets/player/valid_selection_icon.png diff --git a/assets/player/ai_icon.png b/assets/player/icons/ai.png similarity index 100% rename from assets/player/ai_icon.png rename to assets/player/icons/ai.png diff --git a/assets/player/icons/blue.png b/assets/player/icons/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9ce70c38015841324448be4a1b1de527b273cc GIT binary patch literal 16133 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 literal 0 HcmV?d00001 diff --git a/assets/player/none_icon.png b/assets/player/icons/none.png similarity index 100% rename from assets/player/none_icon.png rename to assets/player/icons/none.png diff --git a/assets/player/icons/red.png b/assets/player/icons/red.png new file mode 100644 index 0000000000000000000000000000000000000000..7fc80d1155bf7ec1cb35cab6320e51f08272b9d1 GIT binary patch literal 20610 zcmeFYRa9J2v@KY;ySo(@+}#Tc1P>nE-5r9vy9bxx7Ti6!yL)igz^lA>-@83VcYoZE z{^&7o4XTP$d!KdAncL=CYwido1!)vSLPP)nfFdgcQUQP0{CmU0fV$ZrMW%N$^Sx=d%LNq%)oi>bcKp z%(U-kqY85D%!cOaeyfiVbjeM2;r`vX9)weOWn32@h&l%V5MeFBH>CMRp5NHsmf6t6 z-pG{M!`14rJWGvWqUUzxuuB^r3Tj*)-MhcrWTemUQVW} zUJ7c)Ue?BZCX^z=h=LycU<0MyY2o7Hz|X?s?(WX)&cST& zWX{6I$H&LQ%Fe>h&IGQ(F|)G#U#q)Vn*G02|5x&#)&HH$uVm?AYNH9V zv^BMJ2H%1ZB^wXd|1|cWrCR?FrT;AP%i0>6n`&5^xLEw>Y5!RuZ)#`$e=AXRvNQ!_ z@b78C=TNfzLz3k`pai!J%l~PbfB5`=|N8HX{FgBPZ@B&&uKyAO|E0?R-Mju9uKyAO z|E0?R-Mjw(1sCFfk~>p7Fr#w^Q#adFp=&VhgLW2|Rf7k=eBe#O0RVDEU>L#JiaY_(UKtyU_-uR6!V7IfBNJ60yX_-Pe#+R?QAeJTnd87;yN67cDk zq9n|&2bPF+2<9>HfLSNebVdDATb98#hwuBD1(TMOed3JsH}7w&D+_1i9gpkI-BYjF z__Yv3|NBpX8Vi=Wm)iJuv#k$Yk9UMW7cPVVf1}LENF!EJ^ftB7Ce-%%$JuWsd3o|& zwej?6Odv=|_+jS|=_m6_9T~u0gbgZi_dIZ8c+?PA7P()67}mwY3%N8a{=Qc%*d76cqd}k&GQ5Y{w(y`#m)s{y&DugJ&K-LSVu|sbOH=Y-G!ZV3 z6%a{{iVq_d64W+HtuyL+{L5obkuwiL^l$`H1>&j#b$)gqYgq4DX^s$QUG`_c!3Vz> zmXKe@aG`m!j=3v2if zLId#SY>^)us~4Zm;LJCh@m82?D^Sf6gM%7F*pZg60gfy|&{=Uo}v!Sxgg8oD&QG-~D88Z5P9`;8C^6QIx$u{IiH$iHv6I!Hjszjg=R?2yunF zoUvk^TpKhL1-Z%3uQ{;u@28W(QfF4T84!^zp62BXuPB4Q@`mf)ztiU_pq1pohqAm+ zx-I10y5bzCWhWYW_yBt{Hc91VrnO&=Q$mlmfuHn@MC?{s(Ea~bmWG-yLuI%7#6Vp6 zA&FMdMMAQgjG!NmXF!QU#B_+WiTNCnbX1gYb9`!pEYPo1LoR~&X0q+(TQhgUN*Du@ zmTs_E&|oY~bmYYkMt~4Ha=WICo`RZZj}zZ4;`EV+LP&>lV=ocHZOKVZP9Df{-yF4V z-hl1VUm3&v4L|LL+Del>t_33bZZ5*2I%`j3`OTL6{x4a@3lER=>uxJGCf7O%UE#`*0c;^45xG>EeN$iQkwV&oFnMAX|kyQS~z>xBMd&B^CZhtpS30Jgi*d4fczve*FMd7hrJbdfks^R43 zq*E=Ce_jl9>6!Az%@ay{z4H*XS*{K6ygg*|eQ~ktdN#A+CYqU<0kmvf*ljIYHGu?( z<+HeBT3TAFFGB2NP%Jj*Y9AilsPU0!*VpA)@qyTg7>FTC*wi<rG4y2+6`=;|HENyKE&)u+aa2C$f zbNyZ{Z*Fg&&l;wZ!6Qf$t)ikrm5_*N<(DmytE(#~509#bhP10I*S`a9?p?R`ljCD@ zeB^?q(}>8(z8!~c2VMvM9Nrv-f`WqD6`O=}@PlYpssH}{+XD=z=j(a1=SAyLI;W+| zezUQ$@#x4%UU_*$Nl6LmHcZQ9*XzjCRB2mVCivR;fSQh*$a=>;DYJ=8Ni8h`uTIh* zQ|^qlifv@2b1UbadNpxxwhb%O7M$QaNlZ%%Td*oFEQCrL1wT85uyAg2GWO4kit?%| zY9XP{;rFBQjDCU3j{e=jsP3<40^3LDlCzT;9B^^N6287d)YR1T3k&%Hx4F0kBv=x9 zcFgqj^qP#gH#axn&J{z%qw?+BgreUKmR;*X>fZZzCnt6s9GtC8HWC9poLYeUhAW=+ zQuRUSd;D`ewu#kcfMLB#KosEKAN>AFIkg{V4N4yux1AZn_o{0U+h}w23 zKHBAOae00~ll796pDGVynylmX{L(_5_oH1X3XznJ4P!(^1dy8AkkgH2h{tgkB>Z+I z0iL1kVf;fNrp4{-m|?J?wkBDQaS+oa9)2z1;VN=Qiw89UgGpv^V7-W~KIT7J|)*nGY0*7y8-zvOL0 z7C2(zBHug7m5x7K#op?K5lSuiaf4Nm4S<8MMIsyYumFnUh;d`_f3iHBG<`T*c{?)~ zIlU7^=A7(OJ8N3fQ`Pf(KCo*`WY&Gr=WQh+S~-5b^L&cu^Z((~QCSe8VM&Dp!Gm~V zKZF0Bp=WJ#v%2H`<+S7P!y3l6+d{J?e1`&|@r>~W55?pTZ2(!wr@;L^Q~EC*>%|76 zY^0cmfR4Yi^Px~$nq5A8-=D|ymm4irVhZ@pkHs5Cv3@k8@9T3fmYo9HkE|DZdP?}}0qFd4Hc z`Ny$1+*+kU((o(2rNM`DrBPZ4oL}wq`@Ec#`rI#QB-rNk_#!hrV#(DXfq&y3~Shg zu@j)t8qBQxwA=};6&se)SQm}^P;S*7b#a+STi!Y^x@HOPQQ!$Ff9=;K!m0#sMs!3q zMJ*yC6I~-^1x#)~-f(O%g4l%evAr>|Fd7sl5Beb8T~Yqt<-8+)@oAuZcXR|gGuO1+ zYL3RL#?*j9Oo{e4FwOY5dfZWlT%Y4mfz8FX^erNUBh6Mp0d@u3Nm77>CC@_92(>- zY4NC3>l~qQUH)>$>PL-m%D+Xqyod4Y<-x$0cE7eE9zk5?&O{f6WlWg8zbtj%fENU# zI!*8_1zwZ)T=*SZbuBnI6pgpKe6jKH9S_T-G;H^3wIJTN_$-kJ`XMwKt|$@#!r~0qA0Jc15lU* zj(8+k4l8n;V?S0(0)iWGV<+sMpcLMdma(#{`dL!u@$xPGB=M_x#_e6dxu1B9#L62Oz}H1f`PnxyE|thyOU!4;AoUv*&% zW@rmzU$zKOzj`%S=qx~h$$NmZHbo`2C9elJl(dAVq< zxd_V)3t*_t#`S>6%}d2@T#t->w<|wxfg>tzluk`vI9;ZNV9Zh6wo(JQiXXbEc!tgh z_T!r+%F}R<<3r?l(ItAd^6U4pT@H>s0vkbv=J4tz=u^7v1Q9vKRw0*#tw>@We_k0~ zz9qVN36qe77Zn^tsoGF4c=}z#7Zvm`#JxO_UJ`<+5@Q1HIaTNWx_$q%2GE1)iAGm0 zZjjxzl;TK}AHs@)BGN{lW?DNPN7WaN!Vq%AAMG2TC}PJZ8l0brmS?IZU}*ImK$txMx_$o9!{Qu0sQno?5lzOWgQ6A)>o(Y^V`A7L#YX1Eo^f57@r09U4(Z ze_i>3NACw1hyc#UmH^27oYX?pAz>JU6J4n0+c-zit%Or+n!J;&D5(FLr4(ngnE=rS@K{0ziWDl-MrATcqio>&=vZP6kCT37;=suT-5 zB&CLtR0s4=3rqBHu>py2`>RLUXYy?8?Z{w>i&WN}6X4Hvpnl_=bwS8?r5=$Lxtum= z8)!Y+h_$+$J504*b6R14QZ)6c_1v5wwtO11ELtY41j|Ww(!)I5!+<5cS59m z&zA6shjekrR7h`eMvUI+vDhR>R7a+SkOgO?B>^EXPoihK(8==yq6UhUvM%sp1iGoF zw&qY5uoNx|hnVDW<37ZeshRTqbqH|GdIK*3NT0GpyuN1B+jZoC&&j0rxqI~!XDkX? zDl_Nv3va$1hgxEFw4q^hWAMrep292YKP}x?V$!do-#&0(nq!9d$#bdALN)S-CP$DF zrHt}WnMsIF^(bPty!)-CpgmPeUzDeTXZW)Db4@G2{bIe9(eIT+kZznZ;0J4RUCRsf z9_g#WwDF-I><;xn%?fId(W*>O56etB7B2)r#<|BcN6H!GMcawfMW-tyRVejdtqv~<2cZg{P=Qn48vMR{4yghjtChBzz$15(!1J&cf)OZ{01sWD z5hW}NDyT9c|Jd3ecT{Yc%)#|r$1#@Q7Dplq6BAS9jK$mES!%g5ODjr@h#&F8RYep= zc{SCX1Z;`^uuznz<%Kw!k^)OcG+)oFo#Dxl%670I$I}zX;>cPu>9Il$;u`W(=7+l~ z{mIEcQ+j0uEYo43wr5Dnb&0|5+L(2@zk*7lCyYR5f;@4P`+v$MBHDad7pPP;Gco)1 z57a*s{Vp#~;3u@835SE|*8VE3WQ-i!hQ*S)uM{pWDz$TefyAqL&v5va!KuM~iZs{f zW_09%j4e9@NNI@b4gFdfGSW9X@dS43Ps{q5dp_uzkf~wd#1OBp1<#{L<#yf$XxKgb z$X%p_o&tyUqFIZ4#BAKK=1LE5eu%UueDA#F(s?A!&tK{H$jTT%#tX&{Rti6)L0fRO z`&5z1$H^A9TkjRyB4lHEe`Bi35X6v`(e(je=&wdxWJCeW1PgKrw?LnV5SaP2|BS9j z$UftUL#TdFah=CUvJDAl{kNOmmy(bML&kgBiL#U>aZr!P#tw{ZZ`p>G##|GK9g=Wy zKZX2w%Fo#S)L?lg31bv00=8u*<$3sl4PPNN^y53r7L50BmT=}ZjyCruD_V?zA0QN*^tvI1eNJZocfw7t( zVhdJ^hk827Y`ljiO7<{(_41sZR}>F{03u{qdKQ)=mhaDU`wd&Hp@L_3Kk~2%P|Sw* z_U&dpqWS?oQb=E*Go%@sH&{~z?1;lgi=f29YtJHJdGHZuF3?yHZfvYhbv)ivYSO(1 z$)#dt&L_{y| zu0_%^(?c#_gjLL}hy{yMR>$72;+>?8|t4m>esG4lSmPUEI}` zYr7WvaNCASn}!j^ojAU%FHZr%ftG{?afzvI@s&g@h+`L@haXE>5N7)`Wid5Z$9pd< zss^WuS5fY2Xzk9SOr(3}I5JK}%X*#y;{f+ZaO zz}LgEtX-=}`r|@EFJM+pY*6=0{%FiutWwj^7;eApBJ%v8laTH45OY~-eH1;$mqg}C z8n^niT>d$?g7%1&p9Q920+64?SS^F;$~95B;p8v!_LxXYhKK!CNmoTe*M~D$oYt$+ zl}cI+dpeS^kzXvO`ID45`{=csQ-|1F0J)yNzni^(?2pNkg}vgg83~DsFo~2HVn%y| z=U*yr7fi<7@g?kTjLHLs)Cf$DGQd3QaB&3Thwb8cz^mm!6)A$UGz8X};`rKVm%h(+ zNWIg+?~z}l0~Ggbyy_50{C2cKMwyl>5`dZ(#;A_$BGq;nAl;|(osBqd_qF%w4OKdR z&9Sk|YV)^aWEy?8C*%(A&x*frMN5|oILeS1An6h_Pl(}XHV;etPYa8Sq1?05N{EJ3 z*Oou~%E28p*)66l)ZHbaOkW(r;S+?$Fg88~eDQdyAcULs4W0J&6fI!bw@MFxuv1<}XW-Gt}ta)QjG?npPQhToqPV zWk||I7eq&dz@D9Y{?BpqVFdIJcl<@g1Bv)#6N;oQp*O#2P>FwoR@g9RQqxqr<}&wJhEqr=3iajSad{T!B7uSn>~m(^usj$+ZUDJ?5{+1=dztQmN= zq0#$8|1J8&U3i%1_4mo88~=EP%Vsh^Fp=%i`A`UPn*x+jR=uUM)Lw3DLB+@S5PVc3 z0~t1U>iL*dB_teGPf$B3nUHcwxoT#3`w+B#z2S)Gr^gWN>S!$oNA~?!PR$~At=sK8 zss8HT6@#hP2}(c?KW>$-Wm-~z7!J|s0HUG zNWAr!^&%s^v)Z`6twF_O?zi_PeIvsk&vPsC_*t@ER>;cgSZ0N}8?V1DEpM+6!-yQ= zuc8xWuqbdFT=okAZ7Mv=nK+*7J3kIwq)9XHlv9fC0A*+S3idVX$$54$%!VV^qvlacx*&4Uo zu#b0af9smx#)~PQ$WyXFF1}C?b8NGA3=jk;!O#hlqlS1Wi_8vG2xhg0KrbT)!_tf+ zhet&Xt8B}6nQMl&=0?2R^tgEY(ifx4K_5ns111I;Dz%d&Ev;|uO@g=zUrF%0b+5 zfsRNyb`x>rfjH08xb5cdzJJCNXT|(l?1Zk#%ic0mKxpBuEtM8>3c@OJGZ#K zKKLp0cAJ7zxv4gecA49kqOs3vtj)|;_e(}TWLhpSAup*Gzkk9cFfdRGgOYg=Mj1*%7v#K25fg86DmHeDm!5x-X(J=dnz5oK#^_->hgV z8=*@yX~vMW+%Js8sTz^>Qy4tf~)(I-el zrBfUTYakS8$bWEnuF^E#BJRtca< z{z4&59y;DB4>wYj;vl#mZ!_c7t08-%n6&&R90QW5%4!zb9Dj{!u0LKFZm|IoI@WP> zdVNV7j7r+-BIzQJVKSuWjG!xGUcM_(S|RDc%js1h>d+JSfOo_5PXl=T{p4}3Od~J# z7Xenc_XtJ#>)gf{+|%0lj6cZI;Uud0pQ#Y!I~b!x$%93(L9{tpT3H1PN~$v>colA{ zD%xZExg9YWt@O)hR<-jdBiIo99e!3s+OkkL^F<$%NnjFk^_0}~4zX$WHcwV6Zv35# z48rHn+`vh#K{H{TKu=`lw&mllMpHfzJ{UWMt|FlkD9syvgMSy9C^MM{-9h3P2tlyX z8g4o(!>PvA;OETNKkT&Z)|p{wR6UZu|wnWHAgn4MMnHi^H^XH0|5#! zU=41siy0c??$|VVgzJW%xNsBR(w4`JC)5f?{1Kdm&hV=Fes$unar}0prw!l!^Yvqv zRg{l3bG}qIx?jGr-)UVnNdgh&3+dZtAyh`j89CERz@o?7=Y&K$^u5}U`#UX2%~Vri z{Z^tFsofH-LIO@sj9xt6UbZo4U$M`htvwIUT^V(nvJ6<~zx+ak$as-L^XA58ho}7& zE={kCm?sWX4ZJ5&oFiaDdxck)6JWN{MZ88CY*eX&)gKONr}V zo{TP+Xf^wzWP>_3vo5HdS6&xWziJi=VI1ce!G*OOj;I&bFD564B>bc1dqDG?HiD82 z2Q%Z{#|V4If?7i+VRbfZFsPJ7vQP{j+S}AhOWC3M*WM!>rOsTUk&L2SHg>W(mk=KG z8;Ka0G|I?0#AB1itW*jxTO^pGrY+tK{^_h-(;Z(VDaKA&yb04^AJ~@HcpS~9Q&CZLP46xG|KvfQ>yqwK~@$)=a^ZNnd# zY(5jo#F$uT@U#X>lFDUO_WAwZE{EsQb&2TTbCZ;CV6>EL(@~ZyX^^FwDwLOuaiFnt zLJzHYp4;PUt@?#=zt;tIN~QqToo^42f4dmg;6U4d1 zaJLQDTO8$c1v7$!p&u?bqK5ZQzK`n!#__BS@9pm%H&YA2kPnzyS$@60xLP;iiV_#T z=pLyb&!@U?**H&_a8zJ0tGK??RV|JA22-UzV8~M#aeR2uBdN@*t2Q|FhPkQVkus=% zarP@tr=~l4pyinKQ8RBsPF4%*OmKW!CQ)qpEtrn#Em>ApcBg)fc`rYV)MzY~sZyu8 z`lAR!Y`L2h5*5RQ0cE@ofPehGToh67&1W3LZQE>ogp*w*2mhRQI^Lg=;cP=+*3y$# z;wjZyItd#urT_=S=jf6UKF}YCu!A8GY76nUNgg)#$78Sm%iGCwaYEd1+-Gway-yL> zZbNaSJ!TyK#D5+>!eTjVYYGB>KuOHFduAdgWA5i6ZWa{*VbKVK=_3EZB;@@ty}rKw zJ)LJ>lD0#E&Dfz#i28--6qc?i1ST19b?mEwdD%#j4gEd9ApFZ|9IQ(majJOWSS-2< z^SscKv4pg@|KGu{Z)fF?&tAq9G&vwWJ4C(}1o;-mq|rS%HckQ3@}#=BmEjBDgUU}o z_tElH|EB$KEx@siNXeuwn;!Qr4LCbSArXpx?f|$N=a{NB9m7?x)?E>CT8?dU=N*Sa zKFoxFeZV_sn3aL6Q6XMo_w?ab2)lnexd`;fOulY>w)j(kr>bfc9@CU9Xn5FpMuXb4@ zXcxJk!LzXqE)`*wgPPV|y#qLBw(Oo4`Ryx;AaW6@>d-d8@Av$(C^%Z%ABuANE9ze+ z&}O48l8YTx_Dp6Syk z@(4-T-kQzzy$6^@0}}sHm>xUgK`hs4TOX-QM=n__VC( zF~fd?`JY(4&reTfJ0JbKS^3%TVyI`sj5cZ!9RJumApR{cLgK_8D#AdUdON>S>0+ zq==wbJ(4l3sl5Pp@R3fBGA~$sezEo01q|?(hUBM}jjma-_?VUz(QwZty|o}$ zf%B8nA2cE&Kc<9VEA43wNUg=t3ow$ua9#Mv9ulqzyMnZ#gqs{AEuHhj*V>^9?vg-u+8xrd<2&BnM=86fNzyt7f8 zemM$1sc8J(kp!xUxHyrE{0;XlUz@dGF`1c}e*GN)&U|=6(7`v7#lk zpAJR(8b@@0X%jqm11eII$3)S=+@XH-ThC}XK2(r*5u0?}hg5v^bcvD3)kG@BnL z3f%aG)B4o2^Oo{1Y79~a!&naJP>Yu@yV0w;9t0_!jN%C!hUxByeO z15T`M6q=++k{1w<3&hnebFtts>93jb8b=2x^(OPoKDBYq#J)>CZB)AOf}XOSa$lMA z@MMyodpUzTPYXYUfn4;NOCp+4!$johDzO3@Z+}0!0>lU$U36elK-!tBE3M7hHC?Oy zlq&NsKMF^fDSEcl9+&6oRTW0savrYw(QYSrwv@hpbrq9-$o8f%Pw3%@HgqWx863GcAoEux?DXJ_CJfZsfAu7@TL+bzS(XS+%IjKd)og8WJb+o{luwbyOP7?Z8mJ zE=R*5(-)j_@hyBx#6s+lHKt>VVzZDJQxo!vPW^%=l!4U^!hyH0-k%$H@38ZlIKK~^bo)?E!Dgv|wUA?~)BHnaT5V}h9>t8W#?bQ_>wLuYmyYdplr6nktK=s z|4J_7L3bP#&Nq<<-cU$e^eLj~RReQ-LH&I88(wF=bY&a|>Nl4A9KWAg9^$jJ$GiO= zc@h&7pZ1d!(|NuNR|Pv@_2Z<6N4j{S3&QnST;l>}L*tgq7B6F5SHolK5)=2yhwNxJO{J%0q-k>l{m;YAXHgh+jru&4^*`YcPmeplV}wW|2}SMBs&ngbsOsevMrMNxnS?a z>RaO&ooe@@T|Dt7G2#Wph$zF;oK{yvNp6>?y#BO&yuY@BQ?eQSuAjgfkn^?X+vlSn zx9_i)RM=;GJU~{0q)a{swbzjN6)7TX`n{`Tv7#*(fV{kH7j@c;5prUS zOG}-fu6AxwH*XIyEu{T^`(M41$176Rs00Q^lQ5}+?l3|e+cqfL{WK61@vfDF!cx?( zd5Js&C}F<|1$bYyhOOCm=VWl08#QSs03*Q5y^5-8L`+Pv7^Y{*6%lqIu%JIQZ)gM| z93E(Bz=&E&BnIv!_5XEqA2$h0GK+$gUkMhq>h zwAdxH_nR1FsoAzKVnuM~*;H`g_v+#$m*=sHKNLd^J=rLh>w51Y>b+8A~osW7Y z^0~waK)%HeJr)7CGlSkh7@MuGoVPchLyRe#%Az~?Tjb&Q)LnBN*S9QOPA%E-E^l_@ z;i9CR9Yhw4iX(i#dlYHO9nf9`{V;Fd9#1dwV+)F$c@Az}eg%cXhO5?4)sFC`8<~ z2ECA}EV?6{F6%PLONJB_PO7f%i7)Z=G(B#meNNu-Zyrc954Vubf z&e}dlB5|!?0b~oBM*A~kLIgSN35XuBZ`HjamyA`px@J!f_gOf}-%cD4*F9-7GBSe2 zDfs#MubzEI>Z7F+r%&$jV}?{yF&{U*S?oLSagS7A^|1Xkf7xWzdt4hGPGrFad*7lC zM!>LA8i~hYplCNa`Nxr;Lt73@Lvd9~Q%swFZ?ixNM61qrLb*MfqGe(_Z%pqyy`NoO z{cLDRF_y++{v35nFgM+6s+k@c!FYFPQ}Jm}qJ%^Q1)4WJb(Y>O(kMnv@Sb#6MmN#)a8;vbR~3177_?4yDo zgy5Vu@HqsXWp4cDq(8&$_6tZ-Qdvt&_Ul)ie5G&$R{RXsP}&$TBd~a9a*~FLDP}x6 zdQW(ToOoPSMa5~8)lHeu`b!2o%#W$zH_zMnfKTFT$`h5R(irnHm7gl|xw{+3zD~1# zVhiF-i&{??ELo8Uww?i73S<<*&Fl?f9^al!@4SSV(@q=79ASe3z$&v1JM)ov3bidS zES9c2%<11~0b~9NE%<>b0&OD$3UT42Ofw@uETjEZSZ#~aTv)=0Azx2K7%kK;M{Nto z^jb}1AV?>?Da%pw3up~l^NUxd85L{;YOynchPtRy><}(Prwr{qF;yq6kC@fZ4Prsv z;fsP#xV8d4OP7^Lk3BZ^_|fX$B$1$+QveJWN2Y(Sc)0V{S`rQq%~Bb)oMum5H(Zy% z0vAaY6-+HHEo4%`bg>{y=sMc`b z&i$O~_Yh!AecsV2OrT+02oYiw#B1h^=B;N=xt1AW!E7~@4l9cX$8iv4iWR&@y#KxY z9%j9rJD{zjQ(jY3T344aG$dtZZEa~~RRBK7jFcE5q2}E?J7$u~%oGY2_&uWCnMABx zWIzoImLh$l$=-lQfDq^0Ee@a|w9JRK0EoB5cO}Ip{}IJ952C};Zcm`gB4`kck}d7E zm^M^1#stqw3=uK~;Xp(>Q92+N;wUsEg`l1Y6DbSW-H(i&zdcDc`XszQ;2vNJWXD8` z_{Q0hMhI={_afk zB@?8efC?T=$1c)Xyv|Nebc~GH%mjxpGBPsTLqzsxuzKwi10(Bd@(R}OB387wE^UnM z!cG$GBqW9yh7BtUWut+;2pJu<Mt6tuK(Vf_K*@bWqQDM4^( zp8`ZhTTFVaxwArk{`_>{z4c03)A>LMxMW%t|C|`)sH{~=N(OGf%q!QrwewCtYHY-v z$5(m=2IJ?OgN~cu44gd43CZXarmd(nF%w32S8A~413NA&=y%$|G6w`O8reC${i>}- z@~|}D{kLkE4Pb23F-8VQWEl5<(sR;VuvMT`!z_HPH;uYt!xpf{2XrFUg2chxqo-3q zX6}O0%CZ!J=Zh$o5{w$)o%zoij0wPfn=(VKemXH0m!iNr&gzam@C~g=Fo+0(#64jI zd$%PObg$_$e0>(YrgMVezBE2CsD{mNVa#!l+&lEiYDJC&JTIERzdgU5>VNF6TGvqX z@nxjxc}4u2^TBJNGijrI`ShlnWUPAG)upqqJd=8A=T>&%ZSh<2+UP$1m>R<@OTT*5+Fdp z@e?19^nh9*tY-=Iw2H@aak}zzM3g2}xEOYSMDM!IIvN#PIn7 zXFDWKI2RHkPY~U23pMEi?#%sRXy&Vpme@Er81T^lTAY(GBsCTHpd`!AXl7TEn2~QJ zGe*+Hyd|C0al{ev`<=^pRy6-jy%AU*iLtWn);_xRD<-8vJ>ka>MR4e-x(waE>xvv} z$Si)lzHlaT=cOqJt78wlRP~OK@Kfe;2bEyN8=HEGQD1m4Nr(rhJmkgjkh2xZnw2>A z-Vw(t-Cz)s5EWZODEBP?LadAYrt;iVpnz3in1@oCnr;KtS>f>?h>9616WX@O=OV`Msg$jB)I^NPV@0m4^tO>J= z?hik3KxwQuF{tD1f?w*On3aYFrE>=xRS`Bxd2FNu`^`@TtZu@_#;$c9M*Veg^e;*6 z_&25hxgSe|%}JBJT9b&o0z#RAN$WiXa*iy=dT(#RrPlf6W1qoN^KiL*9w@5 zt`#>|hBp^3PK+s`WTBDKN+R$j_=;jKaGbfLvEn9mBiF*wW3W*1)f}NA;^61Fu+l+J+R7nPe9|4?PKbZ)eNNFLaQB3tMJMtDmJZlM-6#@ndMqM+!$kT3<}e2kNg% zku+NzD9RCL1h4xEbU8ff_N0ojvan;&1yK#Y9tqcrdxJBtG-xmB{ACR3lSVA@0uc?4d?q} z>rF#LWne@T@dRI&MR=BmVh-lc#DX4IvyLew4K|Em<@i7KwotqK?R9~q&9ak!js}V0 zS@<3EL5x?s9wL83Y%(;Qh9YqwW#4#t>$+P%Z#}!Np}|Yw@U;Wd2nB(@cYNxi8zLgZ zv(;aS&p%P33ArLyn&oN1-2HLu`wtC$j{rwtqNDn^i4kDj`~WvS?{lu|t{1D> zxj9Ae{Nf5=3>8k1nV0nf<bg%jjH^p%PLZ-~$p;va%Y2hy zU|7PtS?v3Qozir>9fWqXk7f_#;lUF_Uv4l*13MJkc)YD|g7-g&B63eGo+ANZu{5=S zKvo16ZSG80W>%I~yBiY{9`imIjU&pa?uf@1G{i!CfBNU&n@G(^OsYw=v=gBNjlwr;U`!F@hkd>HJkdBbSt!gmIUJ_aiz7VvnNvX%4U~(QQJ#+yz8mv=5UfsP#S`{AcKxaPWHXcIud)p(sjr;x< zgs1;a)~qcmKL`sQnE%M>+~neyyddM2i4_C9A4tbXoo8k$H``c*s@zZ;$o-46?zBV& zc430RE@MGqA(h-%J)^3!a&Ih&KucY1YA^5P%laP#%%C!6N@Ag&-s6bg;i|$0d}7lA zmk$N?O3mK0l?FvQVQ5GQaO`$en#^~ge_W}dB?Sp(^*u$%r+S4)NGRv>`^PI-LR)V# zido{58#n5}ccSG;TM0=e1F7t$y1caZOri`8L3pY&y5$;-vW0znuvF}G)b8B!8kRKr z`!^*UTb*>PmsYA)vmHrDNXQ!*V^L0!)Q-+EISNzjPpq@Detjc+W$drqiJY7fZ2h+X zx*2##hYk!3s6y5Bh7t)cJ9*zVp?#Sm0o96eiUi?N}ywF$+Z_ zn~d|jqXKLF2kk%V!%g)si`xp=1R(@^i!rIM%kac75j=v3>3;4;rL;fCiTH^IiR27_ ze+K?j-p`eMp`xZPUJ^#CVq#*{s)xRO`GPDJ_CQ>8ZC{e(ZkeB)%kZVp0lm|RM@-hl zMGvtzRU8bTn2ydG{kZ@>vWl7-$l98rL5A{O5LfuEMmdb_mLk{=x;gHVThrA zj8y;K$y|APIR!fW)kw{IOkiI&(NKsSV~&M*4KDI^;}acS^?uCbqH~`1l)L?Re=q^f z0LS^Uq;j8qgdgy5Zywg{Zy_D6xH1}`0t4m2^q9;RSxk{#+a-ZW+>q642tqn@4gNR# zR<|>IxAz0RR2=CSJG%>6qJJ(Xcteas`^J7^;I-iKtw@~UxWN2fhLs-SORa3;KsKK< zrQevy+c}lCcBi1r6sHY$|20`@q_}EQm}$i$>th|vy2oD3+cw;zBiK{959d3d(AL%l zJEa5)rAgPWL(D=RQ$F)Q;b#Mo9cz`!d$kzYk#zQ*g$Sk42QP$hh{xrQGG!&wxgFuj zn03SNU$%^h zeC!%Ny{sy&E06gh#EDhf&~T}h7A&D$q&U3Bgd>^rRAdS z)C0UBB?C;ag!R#Xhzv-$E1F*A@q%)2OAW220i7Oek3K;0_ydaf1n70e-1aaZ`XFXnJ&&dm9sw-2(x6o5ZM%(PC4-gPP75 z%4ui?a*51iO-7|_jGNb5|NN|oePsa4^V@C^Z}1~87-L&8GOo2M_*{KV3qK{V zEa@xi>aJUIby-_jY=e0fIc&r={!DJ&QK>io2fwz`RU$sx9!pTxMX>%{Us|L4a~BA8 zbiKAApqRlu2%w=z@Vksc>fhinG~7Wj4T2sp<}dVujTtd9uNt84l#-Q=aOhHT?{Xbq zvvhQH{5N@N=y`^SykEzGcWh|1=&Y4nTS!nvy!pPfhsNZL2Dz{IK3(rkjg0E+=!{v{ zbPjP@j7rsPZv3{aV+@wd^8m20Hw9}3hMiW!H6R#aZbv$@x;3Vy{aP{-8;A`@g(0XV zwmAqg6=?BXq=QBIyq!re;d#1eTdCa?+1S{qXZ=Y=MRWal0sTp}>0@iN6;AqVuHl>e zLux0j9QTT@3~m54JSI6g0)n9^9sMsAV(X|yg0exk)iTYfq+g4UjU*(lFVd&jjZKS@ zDlt{d?5fbeCDHo;1x^wBG|(eL0cX_SB1d;|8v`K7BA^-%-_-b|4NcNUcG8xxXZNLd z_t7o6Dk~qqA_KS2eLxJ6$LmtpUy`RuflDAUs;bsAZjJiI;ll4A05~5R`?W${SyR*F zTPK8FGdTaj3@`vmzW9%?T0;&)NC;`SdqNz1tNM6KxDvlaYVp-d}-rE&sw`U=QJ&o9~VTKEf3y z!7OVPQHBnU^jMILFR(f*=iK{s04PO7nlB; zNRzA?crwY}kU9i?-b*u6uW9hlCn92o8m#mHy#I*O89I<=NnS4%+?UQ_5D zh=d?zw00`!unbW*{V0lKAE|yCi=<UX?JG<(-cVAGYP4zthruA}edRkO)zM*i@^HmC*j2|2v{FinTcuV3H z;O7VL48oF|9*Sip5%l{bNbzfL2fZpA49xfl)mDN+;$R>R?sUFNc{~u|$5Pn0qn%TC z{|VSYT%+fpV;9zLc=dJIw6^W1TracDPw{6XqV}8#9MoamfB(Y6a3~mYpNx*zJ8x}B zg0sKwo^RJu<7OOSJwo%0KxzO4sra(dwpV;c7SRS3etAqZqQxHKX0O$j-u)Cjezk7( zF~NZPeBIZk_Xb$ZFVN+E!^)W}A(@5FM{E;z!}&akc?$&>%~rJVkiB_7e*LmzcQP0? zYO%>K4upnUZ^G1G+cx<^HDO*@W9VFz&x1cgKe2Pr9LK>tIuKdEVq#8vJ3uwI(za); z=Y6_0pKW_IL&ma~@4Zz2Xn^v4z57SQQ76#A(D0&H8R5LlVKX6l>vDMSdH~j1ymB)} zd`&8N4w?@nz=E+o-gvTKQmmYr9xg^^3!P}{DauOnDZqghbQ*z6lh&8LlDEL_FvIX5 zC`8m%N4&babKgve9*>SL^I4XfLn!6jk#0xpJ-%5|Zv7xf3m*$sgYs|zj4HZh#JmZT zEG|_bxkCr_c$|F9{L&?1)ASHYhlcZ3g44z(4L(KyDNq|>Mm)XKV_6jMUY6cOK2yxm zim;@p=r~+IF&-8nGZmDOwmcnYp*;uzTxq&NaWm#%EVkknhB7NucXekOgD0gTrx!pNT+b2Fxn}6^R&4me1orBniFALg6=Oa`?zm7Jd79-hA-^ zp8EZ6YHMr99JGq_4g#+zikF$<&BY5yb~s2#FbsK}O_pWMRx6IIEV{bdIp5sP+gqXl z-+v!uI6)XBJSHMRC;|dH^hVQVDeDHKkwxCTCa zpOlNqYDKHl^`*KG6<)PQLsD`IGv^g^uAz?R`Z}KZEhHzy%G+W5BoKmM_yC0=7yuO- z)H)rqBq7I=))O=uYL8TnshU=C-XTh*QuVD^*&G?z(=)N!#-Y}zFP}*m>dn<^u_W1; zkUJHV$xQtx^*sNa2df2^>mem0y4uz|BNvWDJI+MB9BOU?!$tDUCWO`&>gwtUg+dCn z@ec2ea9^!f+qcl6)oRh{^{CV;uJ>(vdk@rVHD+rfp+FGX*+pBUhnF`;ONiT+gTeUu z08SLa9|4JrJQ+x%Qgl=I(T57Oit}Dwy~#5WZE^_(1JT)p|FOZRx4aNVk+3Kd5F>bl z0Yc#r3(;U!>)2K$@`hc+o(v00ptoaFjDV{rlWBR0{JQp2r92p|@Q$?m_C_TE_}m_X zK3{ZzCJ50m>mk;-*ph^my>Ny9b>1cCGRt5)R{Wb@N$g2c0b~Om%s<+izka zI&zpy2AWu>t-vh8B%osb2W_Okki)?vdg|)x2n0?j(2f;&N7{WI4hLmrWo+NRov=SZ zFdQU7cX{KtEC{Ft0ZEeZdOg&2b<*C^0e(NvTo5Ti!(>vip+Sc#)>!%Z8OP(%vLaBnV8MvF zZ)RpDd3kvNg#3Oy7cXM6S`h?IY(N#k@9W``+f8*_3*W1)VKF*plTHqHENJ`O_44dq zHERkI_($zYyq|a#Xcc%z)_pA&3zH^IB0oQ$6DLm4(b`1H_$*W^k#I1G*W>1F(>eU7 zPxDh?1=$o~MBf)mGI-eZcM6Pbtv*TMnBue}S~iZB3mGZ*ZE0y?%a$#amzM)jxNJFs zAkf*;O#ShXnE`wYI}c(b^{V-00*@4!_)~2)Ua#V`imvXy@<_<%^T~Vm?CG^p*_@Ip z>rECJkZ(eepC(lfFjbbxyTW6-{F8!tve|5wmA{HoHVjE6B_%hc=fT_2-uL`|?382c z+YtXnl^2+KrTVy19{iuA8ci3oW5C_e^mF8?LtScw(uAfNYN&9P#&oM*$a!$KgS zfU7v~b*QYYY}oF5C3po~BrtA3jr;RCRyNe0!t1#fmTucz*|vKAun3ANKQ&hQlM279{_LLwoP8Tbg68!*%W9M#Sgsq+;fittRh8< k6e&`qNRc8%isDB91!MI3{JIJ?4gdfE07*qoM6N<$g2T7hU;qFB literal 0 HcmV?d00001 diff --git a/assets/player/icons/yellow.png b/assets/player/icons/yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..f6a83fd0fc4807f7429c29d604628e35c5d8355e GIT binary patch literal 18910 zcmeIabx>VFus(>py9Rf6cXxLP?(XjH?(P;K1a}SYZb5=O1P!_;@AqooZtd#o? zt$MeBd+wb%eP()QdcN-dhG=C)DMUCtI1msJL>XyuRp5Q_-!BXl@E3oNkOg=P_fgk& zQ#JM^c5-pFu(mTNcJp>JCpP!8wg3U~+Hg;pgav0o5WlV`r8qfG)=*^bN<(o|_+9MbFXZWqDZlXTRTv~qTYHRes3;t*5oL9z!>iSWlE+<52b3l6f?#9OvD0MN z!&Pc@IIVfIyhfi*!o1vvEWykn`s4HoTSzXN-mB%;f+7eA9F#TCAZ-PCUQC!;4Dqoa!@ z6AKRy4-+#h6DunNP=mqM+riD)i^0K_?4OALB}3fY)zrn>$<5l)f%uXEx|_Ad|3meECI40Z-_5+r)?Vgz+Tzys z<_@kv69h+ zTb2K3cK!cLU2y*e?#vwkMCS=Wx78ab902w~xQfcC!vHTo7_%r45MmG+aS?T|jmvyb zZ452!kwCEqQsN>vRB_No(`(668Tku}#;0wL5v zq(wnR_pM!b?~R@9V6sdW+sC)wTjm}|Gd)i|m0PZ}ps;A<(n-W3ArSvBFT%r!-9=zM z>WQOra&pEFU0SX=I5?8W%~U_-#Jws>WKBs>MRML2vZTe6q>1C>#UY|WI!eeC+l?ZS z@XShfdr?MlS=8}}qG7H%VFiDNeq9;?hqq&qM6SdBMPJj&mrq|JO&L^4K$eBLB_1q_ zM-~l(SqQ;qJ%Yktt&k4pc}9lDGv$8-Qz?UXxWFwVUgbq@6--EXB8~nnb}M_2{0E%l zii-vw9dKJDjH%TanyzVrNTYyoLdZ`0sO1|;e5QEVAEl5}c5{}xd8sb(FCHn%oi}n0 z8KLYJ6d;Jz@NkMDBuj^My6HHuAiOI1LMLPo-M}r;8+cfL3VH~0G`E)iQEWT&B!(lM z5YaH@w1}ECysC($stbCMBg%ypYqF)psKswZTn=u-jp~Iuum(qqs%L)DFo)3l)=`?c zZaR7wRSeqFXUXDWKeS@=Akn+4G%4emg(F!^z^&QINz()*V-V$*Cz3bBm$z7Mx_nsZG@-`{WB7VktdBlG#zvP^s^twKGsq<}ym? z$VuN;lcV#bQ_2&nio{V2|7sN{2Y-_pd?xS@4x261zY>raPJaH72sIty(hVe|X>fPohJ1AeklD)K!!1m7^< z=h#L^AI%QkhcDCx&hb>uBlSy#J%z&76&V>PO!Tl@knk0;3f7?l30XzSvw9Y!qlJ|O zlu_Y%bT+TDc%;HaTk8sKs`0{zdpsQ4Ow|&HK`os7OcRL1rv1) zxG-jFu~xn8;=G@T#;bZ;VYyH`rF=T8k&5DO0=F2^DzuX$m2$Pj$b*4M$v6k${heFc%Ngr`p95G{L=W9Q>YzPkJM$m}kNKP^IfI zjzTVI3S}uxTq;iVh&_O?ue5x8IGMRvZ@_mdtVn}SvWg@m%@pxlr-b(hzQ%L>6}KuQ z_!LBtz%xrI8^w=tO0Yn*;mEg)o@cvt(Zvb{>xDAdk&zKJT-kZavH5kr=d56_G~FRa zG!ePhOxyhqd=4EMsXP{jjNA$`Q?|D3epn6}X7dS*=H@h{UQYXso9n($Sz1*Z=`aHF zEIB!-UCkOq+hB&;Q}uf6q@k@*g|&Xgs}ymIWNr6cD=25}c!-_A&mKHjkQ`3?nCj|k za!gqf(kgcsgMk>f-$5n{wpoVcNg~i5&SL&rZTxi+HN7^{8Wr&D)fS8Bz8VVGtmcC#;2#8Pf%u=zFKZ(B=vH>uz

qDisSC7n2kIcHpPKVjee% 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 literal 0 HcmV?d00001 diff --git a/assets/player/blue.png b/assets/player/textures/blue.png similarity index 100% rename from assets/player/blue.png rename to assets/player/textures/blue.png diff --git a/assets/player/cyan.png b/assets/player/textures/cyan.png similarity index 100% rename from assets/player/cyan.png rename to assets/player/textures/cyan.png diff --git a/assets/player/green.png b/assets/player/textures/green.png similarity index 100% rename from assets/player/green.png rename to assets/player/textures/green.png diff --git a/assets/player/purple.png b/assets/player/textures/purple.png similarity index 100% rename from assets/player/purple.png rename to assets/player/textures/purple.png diff --git a/assets/player/red.png b/assets/player/textures/red.png similarity index 100% rename from assets/player/red.png rename to assets/player/textures/red.png diff --git a/assets/player/yellow.png b/assets/player/textures/yellow.png similarity index 100% rename from assets/player/yellow.png rename to assets/player/textures/yellow.png diff --git a/assets/player/valid_selection_icon.png b/assets/player/valid_selection_icon.png deleted file mode 100644 index 1c2f6327803767b2dce2a2e8b3c05a8da2105a8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6162 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::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p1 = scene->addEntity("player1") .addComponent(224, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/icons/none.png"); auto &p2tile = scene->addEntity("player2 tile") .addComponent(2 * 224 + 200, 1080 / 3, 0) .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p2 = scene->addEntity("player2") .addComponent(2 * 224 + 200, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/icons/none.png"); auto &p3tile = scene->addEntity("player3 tile") .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p3 = scene->addEntity("player3") .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/icons/none.png"); auto &p4tile = scene->addEntity("player4 tile") .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p4 = scene->addEntity("player4") .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/icons/none.png"); scene->addEntity("camera") .addComponent(8, 20, 7) .addComponent(Vector3f(8, 0, 8)); @@ -376,7 +376,7 @@ namespace BBM //p4tile.getComponent().drawable.get()->setColor(YELLOW); //pX - p1.getComponent().drawable = std::make_shared("assets/player/valid_selection_icon.png"); + //p1.getComponent().drawable = std::make_shared("assets/player/icvalid_selection_icon.png"); //to do // quand no player is reaydy, the play button should be diasbled @@ -674,7 +674,7 @@ namespace BBM }; scene->addEntity("player") .addComponent() - .addComponent("assets/player/player.iqm", true, std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) + .addComponent("assets/player/player.iqm", true, std::make_pair(MAP_DIFFUSE, "assets/player/textures/blue.png")) .addComponent() .addComponent() .addComponent() diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index 387daa1e..5498cfa2 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -16,6 +16,6 @@ namespace BBM //void LobbySystem::updateEntityConnectedUser(WAL::Entity &entity) //{ // RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - // texture->use("assets/player/blue.png"); + // texture->use("assets/player/icons/blue.png"); //} } \ No newline at end of file From cf1a64bb7c63d49489c98f52d17e79708776c5f6 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 11:18:06 +0200 Subject: [PATCH 28/82] when the game is exited via pause, scene is unloaded --- sources/Runner/Runner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 177c02b7..7bec4177 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -271,6 +271,7 @@ namespace BBM }) .addComponent([](WAL::Entity &entity, WAL::Wal &) { + gameState._loadedScenes[GameState::SceneID::GameScene] = loadGameScene(); gameState.nextScene = BBM::GameState::SceneID::GameScene; }); @@ -461,7 +462,7 @@ namespace BBM }) .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { - //empty scene + gameState._loadedScenes[GameState::SceneID::GameScene].reset(); gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; }); play.getComponent().setButtonLinks(nullptr, nullptr, nullptr, &settings); @@ -769,7 +770,6 @@ namespace BBM void Runner::loadScenes() { gameState._loadedScenes[GameState::SceneID::MainMenuScene] = loadMainMenuScene(); - gameState._loadedScenes[GameState::SceneID::GameScene] = loadGameScene(); gameState._loadedScenes[GameState::SceneID::SettingsScene] = loadSettingsMenuScene(); gameState._loadedScenes[GameState::SceneID::PauseMenuScene] = loadPauseMenuScene(); gameState._loadedScenes[GameState::SceneID::TitleScreenScene] = loadTitleScreenScene(); From 36355f2d78365c746aa4959a55924f17f476e0c8 Mon Sep 17 00:00:00 2001 From: Askou Date: Fri, 11 Jun 2021 11:21:29 +0200 Subject: [PATCH 29/82] only use one collision for each floor instead of each upperfloor block +40fps --- sources/Map/Map.cpp | 55 ++++++++++++++++++++++++++++++++++----- sources/Map/Map.hpp | 9 ++++++- sources/Runner/Runner.cpp | 2 +- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index acc5b671..7381fccc 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -113,7 +113,7 @@ namespace BBM .addComponent>() .addComponent( WAL::Callback(), - &MapGenerator::wallCollide, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75)) + &MapGenerator::wallCollide, Vector3f(-(width) / 2 , 0.25, 0.25), Vector3f(width, 2, 0.75)) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(width + 3, 1, 1)); @@ -130,7 +130,7 @@ namespace BBM .addComponent(Vector3f(-1, 0, height / 2)) .addComponent( WAL::Callback(), - &MapGenerator::wallCollide, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1)) + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height - 1)) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(1, 1, height + 1)); @@ -180,7 +180,7 @@ namespace BBM .addComponent(1, &MapGenerator::wallDestroyed) .addComponent( WAL::Callback(), - &MapGenerator::wallCollide, Vector3f(0.25, 0.25, 0.25), Vector3f(0.75, 1.5, 0.75)) + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, 0.25), Vector3f(0.75, 0.75, 0.75)) .addComponent(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng)); } @@ -202,10 +202,10 @@ namespace BBM scene->addEntity("Upper Floor") .addComponent(Vector3f(coords)) - .addComponent(floorObj, std::make_pair(MAP_DIFFUSE, floorPng)) - .addComponent( + .addComponent(floorObj, std::make_pair(MAP_DIFFUSE, floorPng)); + /*.addComponent( WAL::Callback(), - &MapGenerator::wallCollide, 0.25, 0.75); + &MapGenerator::wallCollide, 0.25, 0.75);*/ } @@ -381,8 +381,49 @@ namespace BBM return (map); } + void MapGenerator::generateHeightCollision(MapBlock map, int width, int height, std::shared_ptr scene) + { + int floor = 2; + + for (int i = 0; i < width + 1; i++) { + if (map[std::make_tuple(i, 1, height)] != UPPERFLOOR && map[std::make_tuple(i, 1, height)] != UPPERFLOOR) { + floor -= 1; + break; + } + } + for (int i = width / 2 - width / 4; i < width / 2 + width / 4 + 1; i++) { + for (int j = height / 2 - height / 4; j < height / 2 + height / 4 + 1; j++) { + if (map[std::make_tuple(i, 1, i)] != UPPERFLOOR) { + floor -= -1; + break; + } + } + if (floor <= -1) + break; + } + if (floor >= 1) { + scene->addEntity("FloorBot Hitbox") + .addComponent(Vector3f(0, 0, 0)) + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, 0.25), Vector3f(width, 0.75, 0.75)); + scene->addEntity("FloorUp Hitbox") + .addComponent(Vector3f(0, 0, height)) + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, 0.25),Vector3f(width, 0.75, 0.75)); + } + if (floor >= 2) + scene->addEntity("Middle Hitbox") + .addComponent(Vector3f(width / 2 - width / 4, 0, height / 2 - height / 4)) + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, 0.25),Vector3f(width, 0.75, height / 2 + height / 4)); + } + void MapGenerator::loadMap(int width, int height, MapBlock map, const std::shared_ptr &scene) - { + { + generateHeightCollision(map, width, height, scene); generateWall(width, height, scene); generateFloor(map, width, height, scene); for (int x = 0; x < width + 1; x++) diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index 2d7b4a56..f27a1f12 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -28,6 +28,7 @@ namespace BBM class MapGenerator { private: + //! @brief Enum of the block available. enum BlockType { @@ -108,6 +109,13 @@ namespace BBM //! @brief Create upper floor of the map static void createUpperFloor(Vector3f coords, std::shared_ptr scene); + //! @param width Width of the map + //! @param height Height of the map + //! @param scene Scene where the map is instanced + //! @brief Generate the height hitbox of the map + static void generateHeightCollision(MapBlock map, int width, int height, + std::shared_ptr scene); + //! @param map Map to load with block declared inside //! @param width Width of the map //! @param height Height of the map @@ -180,6 +188,5 @@ namespace BBM //! @param scene Scene where the map is instanced //! @brief Generate the map static void loadMap(int width, int height, MapBlock map, const std::shared_ptr &scene); - }; } // namespace BBM \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 5cdcbd3a..1425748c 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -115,7 +115,7 @@ namespace BBM animation.setAnimIndex(5); }); scene->addEntity("camera") - .addComponent(8, 20, 7) + .addComponent(8, 25, 7) .addComponent(Vector3f(8, 0, 8)); /*scene->addEntity("cube") .addComponent(5, 0, 5) From 5d478d8aabe8d5c1b72ce355d88d1b951731b1e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Fri, 11 Jun 2021 11:29:33 +0200 Subject: [PATCH 30/82] collision system is now updating only movable entities --- sources/Models/Vector3.hpp | 5 +++ sources/System/Collision/CollisionSystem.cpp | 40 +++++++++++++------- sources/System/Collision/CollisionSystem.hpp | 5 ++- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/sources/Models/Vector3.hpp b/sources/Models/Vector3.hpp index a2266e07..8e8b4093 100644 --- a/sources/Models/Vector3.hpp +++ b/sources/Models/Vector3.hpp @@ -173,6 +173,11 @@ namespace BBM return Vector3(std::round(this->x), std::round(this->y), std::round(this->z)); } + [[nodiscard]] bool isNull() const + { + return this->x == 0 && this->y == 0 && this->z == 0; + } + operator RAY::Vector3() const requires(std::is_same_v) { return RAY::Vector3(this->x, this->y, this->z); diff --git a/sources/System/Collision/CollisionSystem.cpp b/sources/System/Collision/CollisionSystem.cpp index 0a321133..f2604254 100644 --- a/sources/System/Collision/CollisionSystem.cpp +++ b/sources/System/Collision/CollisionSystem.cpp @@ -23,7 +23,7 @@ namespace BBM return (overlapX && overlapY && overlapZ); } - void CollisionSystem::onFixedUpdate(WAL::ViewEntity &entity) + void CollisionSystem::onFixedUpdate(WAL::ViewEntity &entity) { unsigned int entityUid = entity->getUid(); auto &posA = entity.get(); @@ -33,8 +33,10 @@ namespace BBM Vector3f pointAy = pointA; Vector3f pointAz = pointA; - if (auto *movable = entity->tryGetComponent()) { - auto vel = movable->getVelocity(); + auto &movable = entity.get(); + const auto &vel = movable.getVelocity(); + + if (!vel.isNull()) { pointAx.x += vel.x; pointAy.y += vel.y; pointAz.z += vel.z; @@ -43,13 +45,21 @@ namespace BBM Vector3f minAx = Vector3f::min(pointAx, pointAx + colA.bound); Vector3f maxAx = Vector3f::max(pointAx, pointAx + colA.bound); - Vector3f minAy = Vector3f::min(pointAy, pointAy + colA.bound); - Vector3f maxAy = Vector3f::max(pointAy, pointAy + colA.bound); + Vector3f minAy; + Vector3f maxAy; - Vector3f minAz = Vector3f::min(pointAz, pointAz + colA.bound); - Vector3f maxAz = Vector3f::max(pointAz, pointAz + colA.bound); + Vector3f minAz; + Vector3f maxAz; - for (auto &[other, posB, colB] : this->getView()) { + if (!vel.isNull()) { + minAy = Vector3f::min(pointAy, pointAy + colA.bound); + maxAy = Vector3f::max(pointAy, pointAy + colA.bound); + + minAz = Vector3f::min(pointAz, pointAz + colA.bound); + maxAz = Vector3f::max(pointAz, pointAz + colA.bound); + } + + for (auto &[other, posB, colB] : this->_wal.getScene()->view()) { if (other.getUid() == entityUid) continue; @@ -60,13 +70,15 @@ namespace BBM Vector3f maxB = Vector3f::max(pointB, pointB + colB.bound); if (boxesCollide(minAx, maxAx, minB, maxB)) { - collidedAxis += CollisionComponent::CollidedAxis::X; + collidedAxis += vel.isNull() ? 7 : CollisionComponent::CollidedAxis::X; } - if (boxesCollide(minAy, maxAy, minB, maxB)) { - collidedAxis += CollisionComponent::CollidedAxis::Y; - } - if (boxesCollide(minAz, maxAz, minB, maxB)) { - collidedAxis += CollisionComponent::CollidedAxis::Z; + if (!vel.isNull()) { + if (boxesCollide(minAy, maxAy, minB, maxB)) { + collidedAxis += CollisionComponent::CollidedAxis::Y; + } + if (boxesCollide(minAz, maxAz, minB, maxB)) { + collidedAxis += CollisionComponent::CollidedAxis::Z; + } } if (collidedAxis) { colA.onCollide(entity, other, static_cast(collidedAxis)); diff --git a/sources/System/Collision/CollisionSystem.hpp b/sources/System/Collision/CollisionSystem.hpp index e1e75ede..d7d31595 100644 --- a/sources/System/Collision/CollisionSystem.hpp +++ b/sources/System/Collision/CollisionSystem.hpp @@ -10,16 +10,17 @@ #include "System/System.hpp" #include "Models/Vector3.hpp" #include "Component/Collision/CollisionComponent.hpp" +#include "Component/Movable/MovableComponent.hpp" #include "Component/Position/PositionComponent.hpp" namespace BBM { //! @brief A system to handle collisions. - class CollisionSystem : public WAL::System + class CollisionSystem : public WAL::System { public: //! @inherit - void onFixedUpdate(WAL::ViewEntity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor explicit CollisionSystem(WAL::Wal &wal); From 804361c763baf0f67d3dda6b3aa0c0f4ebacf87d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Fri, 11 Jun 2021 11:31:31 +0200 Subject: [PATCH 31/82] Adding a lobby system --- CMakeLists.txt | 2 +- .../Controllable/ControllableComponent.hpp | 13 +++++++ sources/Component/Lobby/LobbyComponent.cpp | 18 +++++++++ sources/Component/Lobby/LobbyComponent.hpp | 37 +++++++++++++++++++ sources/Runner/Runner.cpp | 13 +++++-- sources/System/Lobby/LobbySystem.cpp | 20 +++++++++- sources/System/Lobby/LobbySystem.hpp | 5 ++- 7 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 sources/Component/Lobby/LobbyComponent.cpp create mode 100644 sources/Component/Lobby/LobbyComponent.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cd8e63c..583bd1c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,7 @@ set(SOURCES sources/System/Music/MusicSystem.cpp sources/System/Lobby/LobbySystem.cpp sources/System/Lobby/LobbySystem.hpp -) + sources/Component/Lobby/LobbyComponent.cpp sources/Component/Lobby/LobbyComponent.hpp) add_executable(bomberman sources/main.cpp diff --git a/sources/Component/Controllable/ControllableComponent.hpp b/sources/Component/Controllable/ControllableComponent.hpp index 8376d43f..89110cee 100644 --- a/sources/Component/Controllable/ControllableComponent.hpp +++ b/sources/Component/Controllable/ControllableComponent.hpp @@ -14,6 +14,17 @@ namespace BBM class ControllableComponent : public WAL::Component { public: + enum Layout + { + NONE, + KEYBOARD_0, + KEYBOARD_1, + GAMEPAD_0, + GAMEPAD_1, + GAMEPAD_2, + GAMEPAD_3 + }; + //! @brief The X and Z abscis of the movement. Vector2f move; //! @brief input value for jump @@ -22,6 +33,8 @@ namespace BBM bool bomb = false; //! @brief input value for pause bool pause = false; + //! @brief The layout used for this controllable. + Layout layout = NONE; //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; diff --git a/sources/Component/Lobby/LobbyComponent.cpp b/sources/Component/Lobby/LobbyComponent.cpp new file mode 100644 index 00000000..e2f7c839 --- /dev/null +++ b/sources/Component/Lobby/LobbyComponent.cpp @@ -0,0 +1,18 @@ +// +// Created by Zoe Roux on 6/11/21. +// + +#include "LobbyComponent.hpp" + +namespace BBM +{ + LobbyComponent::LobbyComponent(WAL::Entity &entity, int playerID) + : WAL::Component(entity), + playerID(playerID) + {} + + WAL::Component *LobbyComponent::clone(WAL::Entity &entity) const + { + return new LobbyComponent(entity, this->playerID); + } +} \ No newline at end of file diff --git a/sources/Component/Lobby/LobbyComponent.hpp b/sources/Component/Lobby/LobbyComponent.hpp new file mode 100644 index 00000000..0f5e6ff8 --- /dev/null +++ b/sources/Component/Lobby/LobbyComponent.hpp @@ -0,0 +1,37 @@ +// +// Created by Zoe Roux on 6/11/21. +// + +#pragma once + +#include +#include +#include +#include + +namespace BBM +{ + class LobbyComponent : public WAL::Component + { + public: + //! @brief The layout used for this player. + ControllableComponent::Layout layout = ControllableComponent::NONE; + //! @brief The ID of the lobby player (from 0 to 3) + int playerID; + //! @brief The color of the player + RAY::Color color = RED; + //! @brief Is this player ready + bool ready = false; + + Component * clone(WAL::Entity &entity) const override; + + //! @brief Create a new lobby component. + explicit LobbyComponent(WAL::Entity &entity, int playerID); + //! @brief A lobby component is copyable. + LobbyComponent(const LobbyComponent &) = default; + //! @brief A default destructor + ~LobbyComponent() override = default; + //! @brief A lobby component is not assignable. + LobbyComponent &operator=(const LobbyComponent &) = delete; + }; +} diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 1cabcabd..13c2e94e 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -50,6 +50,7 @@ #include "System/Sound/MenuSoundManagerSystem.hpp" #include "System/Music/MusicSystem.hpp" #include "System/Lobby/LobbySystem.hpp" +#include "Component/Lobby/LobbyComponent.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; namespace RAY2D = RAY::Drawables::Drawables2D; @@ -299,25 +300,29 @@ namespace BBM .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p1 = scene->addEntity("player1") .addComponent(224, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/none_icon.png") + .addComponent(0); auto &p2tile = scene->addEntity("player2 tile") .addComponent(2 * 224 + 200, 1080 / 3, 0) .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p2 = scene->addEntity("player2") .addComponent(2 * 224 + 200, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/none_icon.png") + .addComponent(1); auto &p3tile = scene->addEntity("player3 tile") .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p3 = scene->addEntity("player3") .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/none_icon.png") + .addComponent(2); auto &p4tile = scene->addEntity("player4 tile") .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); auto &p4 = scene->addEntity("player4") .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) - .addComponent("assets/player/none_icon.png"); + .addComponent("assets/player/none_icon.png") + .addComponent(3); scene->addEntity("camera") .addComponent(8, 20, 7) .addComponent(Vector3f(8, 0, 8)); diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index 6eb2f87f..61bddebd 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -1,7 +1,7 @@ #include +#include #include "System/Lobby/LobbySystem.hpp" #include "Component/Controllable/ControllableComponent.hpp" -#include "Entity/Entity.hpp" namespace BBM { @@ -9,7 +9,23 @@ namespace BBM : System(wal) {} - void LobbySystem::onSelfUpdate() + void LobbySystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) { + auto &lobby = entity.get(); + if (lobby.layout == ControllableComponent::NONE) { + for (auto &[_, controller] : this->_wal.getScene()->view()) { + if (controller.jump) { + lobby.layout = controller.layout; + return; + } + } + } + for (auto &[_, controller] : this->_wal.getScene()->view()) { + if (controller.layout == lobby.layout && controller.jump) { + lobby.ready = !lobby.ready; + if (lobby.ready) { + } + } + } } } \ No newline at end of file diff --git a/sources/System/Lobby/LobbySystem.hpp b/sources/System/Lobby/LobbySystem.hpp index 0e88c3e4..884259f5 100644 --- a/sources/System/Lobby/LobbySystem.hpp +++ b/sources/System/Lobby/LobbySystem.hpp @@ -1,15 +1,16 @@ #pragma once #include "System/System.hpp" +#include "Component/Lobby/LobbyComponent.hpp" namespace BBM { //! @brief A system to handle Health entities. - class LobbySystem : public WAL::System<> + class LobbySystem : public WAL::System { public: //! @inherit - void onSelfUpdate() override; + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; //! @brief A default constructor explicit LobbySystem(WAL::Wal &wal); From 0108002bb5bfe2487c7cb8b1aac9584fbf290b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Fri, 11 Jun 2021 14:45:44 +0200 Subject: [PATCH 32/82] testing bombs --- .../System/BombHolder/BombHolderSystem.cpp | 33 ++++++++----------- .../System/BombHolder/BombHolderSystem.hpp | 21 ++++++++++-- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 4a582b26..42750d19 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -34,12 +34,12 @@ namespace BBM : System(wal) {} - void BombHolderSystem::_dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, const Vector3f &posFrom) + void BombHolderSystem::_dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, ExpansionDirection expansionDirections) { if (radiusToDo <= 0) return; std::cout << "exploding at " << position << std::endl; - wal.getSystem().dispatchEvent([position, radiusToDo, posFrom](WAL::Wal &wal) { + wal.getSystem().dispatchEvent([position, radiusToDo, expansionDirections](WAL::Wal &wal) { for (auto &[entity, pos, _] : wal.getScene()->view>()) { if (pos.position.round() == position) { if (auto *health = entity.tryGetComponent()) @@ -47,22 +47,17 @@ namespace BBM return; } } - const Vector3f expandVectors[] = { - {1, 0, 0}, - {-1, 0, 0}, - {0, 0, 1}, - {0, 0, -1}, - }; - - // should be true only at the first iteration - bool alwaysDispatch = position == posFrom; - - for (const auto &expandVector : expandVectors) { - Vector3f newPos = position + expandVector; - if (!alwaysDispatch && newPos == posFrom) { - continue; - } - _dispatchExplosion(newPos, wal, radiusToDo - 1, position); + if (expansionDirections & ExpansionDirection::FRONT) { + _dispatchExplosion(position + Vector3f{1, 0, 0}, wal, radiusToDo - 1, ExpansionDirection::FRONT); + } + if (expansionDirections & ExpansionDirection::BACK) { + _dispatchExplosion(position + Vector3f{-1, 0, 0}, wal, radiusToDo - 1, ExpansionDirection::BACK); + } + if (expansionDirections & ExpansionDirection::LEFT) { + _dispatchExplosion(position + Vector3f{0, 0, 1}, wal, radiusToDo - 1, ExpansionDirection::LEFT); + } + if (expansionDirections & ExpansionDirection::RIGHT) { + _dispatchExplosion(position + Vector3f{0, 0, -1}, wal, radiusToDo - 1, ExpansionDirection::RIGHT); } }); } @@ -72,7 +67,7 @@ namespace BBM bomb.scheduleDeletion(); auto position = bomb.getComponent().position.round(); auto explosionRadius = bomb.getComponent().explosionRadius; - _dispatchExplosion(position, wal, explosionRadius); + _dispatchExplosion(position, wal, 2); } void BombHolderSystem::_spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id) diff --git a/sources/System/BombHolder/BombHolderSystem.hpp b/sources/System/BombHolder/BombHolderSystem.hpp index 6c872ca8..e7245eae 100644 --- a/sources/System/BombHolder/BombHolderSystem.hpp +++ b/sources/System/BombHolder/BombHolderSystem.hpp @@ -14,6 +14,15 @@ namespace BBM { + enum ExpansionDirection { + UP = 1, + DOWN = 2, + LEFT = 4, + RIGHT = 8, + FRONT = 16, + BACK = 32 + }; + //! @brief The system that allow one to place bombs. class BombHolderSystem : public WAL::System { @@ -22,11 +31,19 @@ namespace BBM void _spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id); //! @brief Spawn a bomb at the specified position. - static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, const Vector3f &posFrom); + static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, ExpansionDirection expansionDirections); //! @brief Wrapped call to specify default arg value inline static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo) { - return _dispatchExplosion(position, wal, radiusToDo, position); + return _dispatchExplosion(position, + wal, + radiusToDo, + static_cast(ExpansionDirection::DOWN + | ExpansionDirection::UP + | ExpansionDirection::FRONT + | ExpansionDirection::BACK + | ExpansionDirection::LEFT + | ExpansionDirection::RIGHT)); }; //! @brief The method triggered when the bomb explode. From 58f0ef48c27e6a42fdc8256fff3767f58db8be74 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 15:13:21 +0200 Subject: [PATCH 33/82] add controll entity in credit scene --- sources/Runner/Runner.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 02060b64..4e4167d2 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -712,6 +712,8 @@ namespace BBM .addComponent("assets/plain_menu_background.png"); scene->addEntity("Control entity") + .addComponent() + .addComponent() .addComponent("assets/musics/music_title.ogg") .addComponent(sounds); From dde64c99ab0cee8bf77376d6483d97d3e7d3f06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Fri, 11 Jun 2021 15:32:03 +0200 Subject: [PATCH 34/82] bonuses are collidable but the explosion is called multiple times --- sources/Map/Map.cpp | 2 ++ sources/System/BombHolder/BombHolderSystem.cpp | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index d8522618..0fa7b832 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "Component/Movable/MovableComponent.hpp" #include #include @@ -54,6 +55,7 @@ namespace BBM wal.getScene()->scheduleNewEntity("Bonus") .addComponent(position) .addComponent>() + .addComponent() .addComponent(1, [](WAL::Entity &entity, WAL::Wal &wal) { entity.scheduleDeletion(); }) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 42750d19..6ad0ac60 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -38,7 +38,6 @@ namespace BBM { if (radiusToDo <= 0) return; - std::cout << "exploding at " << position << std::endl; wal.getSystem().dispatchEvent([position, radiusToDo, expansionDirections](WAL::Wal &wal) { for (auto &[entity, pos, _] : wal.getScene()->view>()) { if (pos.position.round() == position) { @@ -67,7 +66,7 @@ namespace BBM bomb.scheduleDeletion(); auto position = bomb.getComponent().position.round(); auto explosionRadius = bomb.getComponent().explosionRadius; - _dispatchExplosion(position, wal, 2); + _dispatchExplosion(position, wal, explosionRadius); } void BombHolderSystem::_spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id) From fb1cfa3654b32ce041ff54fc9274cbc6bcb62171 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Fri, 11 Jun 2021 15:32:49 +0200 Subject: [PATCH 35/82] Adding ready handling for players --- assets/player/icons/ready.png | Bin 0 -> 6162 bytes lib/Ray/sources/Drawables/2D/Rectangle.hpp | 4 +- lib/Ray/sources/Drawables/Texture.cpp | 9 ++- lib/Ray/sources/Drawables/Texture.hpp | 7 ++- sources/Component/Lobby/LobbyComponent.cpp | 7 ++- sources/Component/Lobby/LobbyComponent.hpp | 4 +- sources/Runner/Runner.cpp | 66 +++++++++------------ sources/System/Lobby/LobbySystem.cpp | 5 +- 8 files changed, 53 insertions(+), 49 deletions(-) create mode 100644 assets/player/icons/ready.png diff --git a/assets/player/icons/ready.png b/assets/player/icons/ready.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2f6327803767b2dce2a2e8b3c05a8da2105a8b GIT binary patch literal 6162 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 Texture::_texturesCache(LoadTexture, UnloadTexture); + Cache<::Texture> Texture::_texturesCache(LoadTexture, UnloadTexture); + + Texture::Texture() + : Rectangle(Vector2(0, 0), Vector2(0, 0), WHITE) + {} Texture::Texture(const std::string &filename, bool lonely): Rectangle(Vector2(0, 0), Vector2(0, 0), WHITE), @@ -44,6 +48,9 @@ namespace RAY { void Texture::drawOn(RAY::Window &) { + if (!this->_texture) + return; + float scale = this->_dimensions.x / this->_texture->width; DrawTextureEx(*this, this->_position, 0, scale, this->_color); diff --git a/lib/Ray/sources/Drawables/Texture.hpp b/lib/Ray/sources/Drawables/Texture.hpp index 931699e2..74eab4c8 100644 --- a/lib/Ray/sources/Drawables/Texture.hpp +++ b/lib/Ray/sources/Drawables/Texture.hpp @@ -21,7 +21,10 @@ namespace RAY //! @brief Create an texture, loading a file //! @param filename: path to file to load //! @param lonely: should be set to true if the entity's loaded data must be independant from others - Texture(const std::string &filename, bool lonely = false); + explicit Texture(const std::string &filename, bool lonely = false); + + //! @brief Create an empty texture + Texture(); //! @brief A texture is copy constructable Texture(const Texture &) = default; @@ -33,7 +36,7 @@ namespace RAY Texture &operator=(const Texture &) = default; //! @brief Texture destructor, will not unload ressources - ~Texture() = default; + ~Texture() override = default; //! @brief draw texture on a window void drawOn(RAY::Window &) override; diff --git a/sources/Component/Lobby/LobbyComponent.cpp b/sources/Component/Lobby/LobbyComponent.cpp index e2f7c839..9f46bfb4 100644 --- a/sources/Component/Lobby/LobbyComponent.cpp +++ b/sources/Component/Lobby/LobbyComponent.cpp @@ -6,13 +6,14 @@ namespace BBM { - LobbyComponent::LobbyComponent(WAL::Entity &entity, int playerID) + LobbyComponent::LobbyComponent(WAL::Entity &entity, int playerID, WAL::Entity &readyButton) : WAL::Component(entity), - playerID(playerID) + playerID(playerID), + readyButton(readyButton) {} WAL::Component *LobbyComponent::clone(WAL::Entity &entity) const { - return new LobbyComponent(entity, this->playerID); + return new LobbyComponent(entity, this->playerID, this->readyButton); } } \ No newline at end of file diff --git a/sources/Component/Lobby/LobbyComponent.hpp b/sources/Component/Lobby/LobbyComponent.hpp index 0f5e6ff8..76146d6c 100644 --- a/sources/Component/Lobby/LobbyComponent.hpp +++ b/sources/Component/Lobby/LobbyComponent.hpp @@ -22,11 +22,13 @@ namespace BBM RAY::Color color = RED; //! @brief Is this player ready bool ready = false; + //! @brief The entity containing the ready display. + WAL::Entity &readyButton; Component * clone(WAL::Entity &entity) const override; //! @brief Create a new lobby component. - explicit LobbyComponent(WAL::Entity &entity, int playerID); + explicit LobbyComponent(WAL::Entity &entity, int playerID, WAL::Entity &readyButton); //! @brief A lobby component is copyable. LobbyComponent(const LobbyComponent &) = default; //! @brief A default destructor diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 02060b64..557a0905 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -258,20 +258,35 @@ namespace BBM auto &play = scene->addEntity("play button") .addComponent(1920 / 2.5, 1080 - 180, 0) .addComponent("assets/buttons/button_new_game.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); texture->use("assets/buttons/button_new_game.png"); + auto &lobby = wal.getScene()->view(); + if (std::any_of(lobby.begin(), lobby.end(), [](WAL::ViewEntity &entity) { + return !entity.get().ready; + })) + texture->setColor(GRAY); }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); texture->use("assets/buttons/button_new_game_hovered.png"); + auto &lobby = wal.getScene()->view(); + if (std::any_of(lobby.begin(), lobby.end(), [](WAL::ViewEntity &entity) { + return !entity.get().ready; + })) + texture->setColor(GRAY); }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { + auto &lobby = wal.getScene()->view(); + if (std::any_of(lobby.begin(), lobby.end(), [](WAL::ViewEntity &entity) { + return !entity.get().ready; + })) + return; gameState._loadedScenes[GameState::SceneID::GameScene] = loadGameScene(); gameState.nextScene = BBM::GameState::SceneID::GameScene; }); @@ -344,45 +359,18 @@ namespace BBM entity.getComponent().drawable->setColor(ORANGE); }); -// auto &p1tile = scene->addEntity("player1 tile") -// .addComponent(224, 1080 / 3, 0) -// .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); - auto &p1 = scene->addEntity("player1") - .addComponent(224, 1080 / 3, 0) - .addComponent("assets/player/icons/none.png") - .addComponent(0); -// auto &p2tile = scene->addEntity("player2 tile") -// .addComponent(2 * 224 + 200, 1080 / 3, 0) -// .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); - auto &p2 = scene->addEntity("player2") - .addComponent(2 * 224 + 200, 1080 / 3, 0) - .addComponent("assets/player/icons/none.png") - .addComponent(1); -// auto &p3tile = scene->addEntity("player3 tile") -// .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) -// .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); - auto &p3 = scene->addEntity("player3") - .addComponent(3 * 224 + 2 * 200, 1080 / 3, 0) - .addComponent("assets/player/icons/none.png") - .addComponent(2); -// auto &p4tile = scene->addEntity("player4 tile") -// .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) -// .addComponent(RAY::Vector2(), RAY::Vector2(200, 200), WHITE); - auto &p4 = scene->addEntity("player4") - .addComponent(4 * 224 + 3 * 200, 1080 / 3, 0) - .addComponent("assets/player/icons/none.png") - .addComponent(3); + for (int i = 0; i < 4; i++) { + auto &player = scene->addEntity("player") + .addComponent(224 * (i + 1) + 200 * i, 1080 / 3, 0) + .addComponent("assets/player/icons/none.png"); + auto &ready = scene->addEntity("ready") + .addComponent(224 * (i + 1) + 200 * i, 1080 / 3, 0) + .addComponent(); + player.addComponent(i, ready); + } scene->addEntity("camera") .addComponent(8, 20, 7) .addComponent(Vector3f(8, 0, 8)); - - //pX - //p1.getComponent().drawable = std::make_shared("assets/player/icvalid_selection_icon.png"); - - //to do - // quand no player is reaydy, the play button should be diasbled - - //The other non-ready players shoudl be IAs play.getComponent().setButtonLinks(&lavaOption, &back, &back, nullptr); back.getComponent().setButtonLinks(&play, nullptr, nullptr, &play); lavaOption.getComponent().setButtonLinks(nullptr, &play, nullptr, &heightOption); diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index a17d91cc..bef333a8 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -33,8 +33,11 @@ namespace BBM } for (auto &[_, controller] : this->_wal.getScene()->view()) { if (controller.layout == lobby.layout && controller.jump) { - lobby.ready = !lobby.ready; + lobby.ready = true; if (lobby.ready) { + auto *texture = dynamic_cast(lobby.readyButton.getComponent().drawable.get()); + if (texture) + texture->use("assets/player/icons/ready.png"); } } } From a1eb7be98be0ed94088e73d2830b33a5201429e7 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 15:58:43 +0200 Subject: [PATCH 36/82] lobby: add background tiles with color code --- sources/Runner/Runner.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index b5aadd18..8933ec03 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -359,7 +359,11 @@ namespace BBM entity.getComponent().drawable->setColor(ORANGE); }); + static const std::vector colors = { BLUE, RED, GREEN, YELLOW }; for (int i = 0; i < 4; i++) { + auto &playerTile = scene->addEntity("player tile") + .addComponent(224 * (i + 1) + 200 * i, 1080 / 3, 0) + .addComponent(RAY::Vector2(224 * (i + 1) + 200 * i, 1080 / 3), RAY::Vector2(200, 200), colors[i]); auto &player = scene->addEntity("player") .addComponent(224 * (i + 1) + 200 * i, 1080 / 3, 0) .addComponent("assets/player/icons/none.png"); From 3b7d81beb1faafb733cea34eeffa9cf4968e6b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Fri, 11 Jun 2021 16:43:49 +0200 Subject: [PATCH 37/82] static cast added --- sources/System/Gamepad/GamepadSystem.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sources/System/Gamepad/GamepadSystem.cpp b/sources/System/Gamepad/GamepadSystem.cpp index ee4b8767..5dd30a34 100644 --- a/sources/System/Gamepad/GamepadSystem.cpp +++ b/sources/System/Gamepad/GamepadSystem.cpp @@ -33,9 +33,9 @@ namespace BBM key.second = gamepad.isPressed(key.first); controllable.move.x = gamepad.getAxisValue(gamepadComponent.LeftStickX) * -1; controllable.move.y = gamepad.getAxisValue(gamepadComponent.LeftStickY) * -1; - controllable.move.x -= gamepad.isDown(gamepadComponent.keyRight); - controllable.move.x += gamepad.isDown(gamepadComponent.keyLeft); - controllable.move.y += gamepad.isDown(gamepadComponent.keyUp); - controllable.move.y -= gamepad.isDown(gamepadComponent.keyDown); + controllable.move.x -= static_cast(gamepad.isDown(gamepadComponent.keyRight)); + controllable.move.x += static_cast(gamepad.isDown(gamepadComponent.keyLeft)); + controllable.move.y += static_cast(gamepad.isDown(gamepadComponent.keyUp)); + controllable.move.y -= static_cast(gamepad.isDown(gamepadComponent.keyDown)); } } \ No newline at end of file From 73b8cc5ccd4a4a7905c958fdf74ed6d647a52cd0 Mon Sep 17 00:00:00 2001 From: Askou Date: Fri, 11 Jun 2021 19:25:43 +0200 Subject: [PATCH 38/82] fix floor hitbox on no floor map --- sources/Map/Map.cpp | 9 +++++---- sources/Map/Map.hpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index af76ec99..f158d81b 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -381,7 +381,7 @@ namespace BBM return (map); } - MapGenerator::MapBlock MapGenerator::createMap(int width, int height) + MapGenerator::MapBlock MapGenerator::createMap(int width, int height, bool isHeight) { MapBlock map; @@ -408,7 +408,8 @@ namespace BBM for (int j = 0; j < height + 1; j++) if (!((i + 1) % 2) && !((j + 1) % 2)) map[std::make_tuple(i, 0, j)] = UNBREAKABLE; - map = createHeight(map, width, height); + if (isHeight) + map = createHeight(map, width, height); map = cleanBreakable(map, width, height); return (map); } @@ -426,11 +427,11 @@ namespace BBM for (int i = width / 2 - width / 4; i < width / 2 + width / 4 + 1; i++) { for (int j = height / 2 - height / 4; j < height / 2 + height / 4 + 1; j++) { if (map[std::make_tuple(i, 1, i)] != UPPERFLOOR) { - floor -= -1; + floor -= 1; break; } } - if (floor <= -1) + if (floor <= 0) break; } if (floor >= 1) { diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index 8161364d..562bfb40 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -181,7 +181,7 @@ namespace BBM //! @param width Width of the map //! @param height Height of the map //! @brief Generate map of block to be loaded - static MapBlock createMap(int width, int height); + static MapBlock createMap(int width, int height, bool isHeight = false); //! @param width Width of the map //! @param height Height of the map From a9edacd41bdb95073591dc8c3d2986f269ecb8f7 Mon Sep 17 00:00:00 2001 From: Askou Date: Fri, 11 Jun 2021 19:27:02 +0200 Subject: [PATCH 39/82] remove debug print in bombHolderSystem --- sources/System/BombHolder/BombHolderSystem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 4a582b26..a6993e36 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -38,7 +38,6 @@ namespace BBM { if (radiusToDo <= 0) return; - std::cout << "exploding at " << position << std::endl; wal.getSystem().dispatchEvent([position, radiusToDo, posFrom](WAL::Wal &wal) { for (auto &[entity, pos, _] : wal.getScene()->view>()) { if (pos.position.round() == position) { From 0a0501a044286f40fd41d537f759fec4514d1477 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Fri, 11 Jun 2021 20:13:27 +0200 Subject: [PATCH 40/82] splash screen has a scene on its own --- sources/Models/GameState.hpp | 5 +++-- sources/Runner/Runner.cpp | 12 +++++++++++- sources/Runner/Runner.hpp | 3 +++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sources/Models/GameState.hpp b/sources/Models/GameState.hpp index 61f7f309..4bb271b5 100644 --- a/sources/Models/GameState.hpp +++ b/sources/Models/GameState.hpp @@ -18,6 +18,7 @@ namespace BBM //! @brief The list of scenes available. enum SceneID { + SplashScreen, MainMenuScene, GameScene, SettingsScene, @@ -29,10 +30,10 @@ namespace BBM //! @brief The currently loaded scene - SceneID currentScene = TitleScreenScene; + SceneID currentScene = SplashScreen; //! @brief The next scene to load (if smae as currentScene, nothing to do) - SceneID nextScene = TitleScreenScene; + SceneID nextScene = SplashScreen; //! @brief The list of loaded scenes. std::unordered_map> _loadedScenes = {}; diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 8b5f68ac..bd8204c1 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -602,6 +602,15 @@ namespace BBM return scene; } + std::shared_ptr Runner::loadSplashScreenScene() + { + auto scene = std::make_shared(); + + auto &background = scene->addEntity("background") + .addComponent(Runner::updateState, Runner::gameState); diff --git a/sources/Runner/Runner.hpp b/sources/Runner/Runner.hpp index 6c42adfe..b7d21729 100644 --- a/sources/Runner/Runner.hpp +++ b/sources/Runner/Runner.hpp @@ -46,6 +46,9 @@ namespace BBM //! @brief load all data related to credit screen static std::shared_ptr loadCreditScene(); + //! @brief load all data related to splash screen + static std::shared_ptr loadSplashScreenScene(); + //! @brief loads all scenes in the game state static void loadScenes(); }; From fd391d869e500cf91ff6e6adefdeab2e84c0de60 Mon Sep 17 00:00:00 2001 From: Askou Date: Sat, 12 Jun 2021 11:09:24 +0200 Subject: [PATCH 41/82] remove ugly 20lines createSpawner --- sources/Map/Map.cpp | 45 ++++++++++++++++++++++++--------------------- sources/Map/Map.hpp | 14 +++++++++++++- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index f158d81b..8b5d8206 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -346,25 +346,9 @@ namespace BBM MapGenerator::MapBlock MapGenerator::createSpawner(MapBlock map, int width, int height) { map[std::make_tuple(0, 0, 0)] = SPAWNER; - map[std::make_tuple(0, 0, 1)] = SPAWNER; - map[std::make_tuple(0, 0, 2)] = SPAWNER; - map[std::make_tuple(1, 0, 0)] = SPAWNER; - map[std::make_tuple(2, 0, 0)] = SPAWNER; map[std::make_tuple(width, 0, 0)] = SPAWNER; - map[std::make_tuple(width - 1, 0, 0)] = SPAWNER; - map[std::make_tuple(width - 2, 0, 0)] = SPAWNER; - map[std::make_tuple(width, 0, 1)] = SPAWNER; - map[std::make_tuple(width, 0, 2)] = SPAWNER; map[std::make_tuple(0, 0, height)] = SPAWNER; - map[std::make_tuple(1, 0, height)] = SPAWNER; - map[std::make_tuple(2, 0, height)] = SPAWNER; - map[std::make_tuple(0, 0, height - 1)] = SPAWNER; - map[std::make_tuple(0, 0, height - 2)] = SPAWNER; map[std::make_tuple(width, 0, height)] = SPAWNER; - map[std::make_tuple(width, 0, height - 1)] = SPAWNER; - map[std::make_tuple(width, 0, height - 2)] = SPAWNER; - map[std::make_tuple(width - 1, 0, height)] = SPAWNER; - map[std::make_tuple(width - 2, 0, height)] = SPAWNER; return map; } @@ -381,7 +365,26 @@ namespace BBM return (map); } - MapGenerator::MapBlock MapGenerator::createMap(int width, int height, bool isHeight) + MapGenerator::MapBlock MapGenerator::createClassicUnbreakable(MapBlock map, int width, int height) + { + for (int i = 0; i < width + 1; i++) + for (int j = 0; j < height + 1; j++) + if (!((i + 1) % 2) && !((j + 1) % 2)) + map[std::make_tuple(i, 0, j)] = UNBREAKABLE; + return (map); + } + + MapGenerator::MapBlock MapGenerator::createLongClassicUnbreakable(MapBlock map, int width, int height) + { + for (int i = 0; i < width + 1; i++) + for (int j = 0; j < height + 1; j++) + if ((i % 3) && !((j + 1) % 2)) + map[std::make_tuple(i, 0, j)] = UNBREAKABLE; + return (map); + } + + + MapGenerator::MapBlock MapGenerator::createMap(int width, int height, bool isHeight, bool isNotClassic) { MapBlock map; @@ -404,10 +407,10 @@ namespace BBM map[std::make_tuple(i, 0, j)] = BREAKABLE; } } - for (int i = 0; i < width + 1; i++) - for (int j = 0; j < height + 1; j++) - if (!((i + 1) % 2) && !((j + 1) % 2)) - map[std::make_tuple(i, 0, j)] = UNBREAKABLE; + if (!isNotClassic) + map = createClassicUnbreakable(map, width, height); + else + map = createLongClassicUnbreakable(map, width, height); if (isHeight) map = createHeight(map, width, height); map = cleanBreakable(map, width, height); diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index 562bfb40..f7eef37c 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -119,6 +119,18 @@ namespace BBM static void generateHeightCollision(MapBlock map, int width, int height, std::shared_ptr scene); + //! @param map Map to load with block declared inside + //! @param width Width of the map + //! @param height Height of the map + //! @brief Generate unbreakable block on the map + static MapBlock createClassicUnbreakable(MapBlock map, int width, int height); + + //! @param map Map to load with block declared inside + //! @param width Width of the map + //! @param height Height of the map + //! @brief Generate unbreakable block on map + static MapBlock createLongClassicUnbreakable(MapBlock map, int width, int height); + //! @param map Map to load with block declared inside //! @param width Width of the map //! @param height Height of the map @@ -181,7 +193,7 @@ namespace BBM //! @param width Width of the map //! @param height Height of the map //! @brief Generate map of block to be loaded - static MapBlock createMap(int width, int height, bool isHeight = false); + static MapBlock createMap(int width, int height, bool isHeight = false, bool isNotClassic = false); //! @param width Width of the map //! @param height Height of the map From b5d33751afe5bd2967592a1eac90bee87261a225 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Sat, 12 Jun 2021 14:18:42 +0200 Subject: [PATCH 42/82] square drwing --- CMakeLists.txt | 4 ++ lib/Ray/sources/Drawables/2D/Rectangle.cpp | 36 ++++++++++- lib/Ray/sources/Drawables/2D/Rectangle.hpp | 24 ++++++- .../IntroAnimationComponent.hpp | 5 +- sources/Runner/Runner.cpp | 9 ++- .../IntroAnimation/IntroAnimationSystem.cpp | 62 ++++++++++++++----- 6 files changed, 119 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7e8b9ed..b4aa8778 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,10 @@ set(SOURCES sources/System/Music/MusicSystem.cpp sources/System/Bomb/BombSystem.cpp sources/System/Bomb/BombSystem.hpp + sources/Component/IntroAnimation/IntroAnimationComponent.hpp + sources/Component/IntroAnimation/IntroAnimationComponent.cpp + sources/System/IntroAnimation/IntroAnimationSystem.hpp + sources/System/IntroAnimation/IntroAnimationSystem.cpp ) add_executable(bomberman sources/main.cpp diff --git a/lib/Ray/sources/Drawables/2D/Rectangle.cpp b/lib/Ray/sources/Drawables/2D/Rectangle.cpp index 9f623bee..284e9b27 100644 --- a/lib/Ray/sources/Drawables/2D/Rectangle.cpp +++ b/lib/Ray/sources/Drawables/2D/Rectangle.cpp @@ -33,13 +33,47 @@ namespace RAY::Drawables::Drawables2D return *this; } - Rectangle &Rectangle::setDimensions(int x, int y) + Rectangle &Rectangle::setDimensions(float x, float y) { this->_dimensions.x = x; this->_dimensions.y = y; return *this; } + float Rectangle::getHeight(void) const + { + return this->_dimensions.y; + } + + float Rectangle::getWidth(void) const + { + return this->_dimensions.x; + } + + Rectangle &Rectangle::incrementWidth(float width) + { + this->_dimensions.x += width; + return *this; + } + + Rectangle &Rectangle::incrementHeight(float height) + { + this->_dimensions.y += height; + return *this; + } + + Rectangle &Rectangle::setWidth(float width) + { + this->_dimensions.x = width; + return *this; + } + + Rectangle &Rectangle::setHeight(float height) + { + this->_dimensions.y = height; + return *this; + } + void Rectangle::drawOn(RAY::Window &) { DrawRectangleV(this->_position, this->_dimensions, this->_color); diff --git a/lib/Ray/sources/Drawables/2D/Rectangle.hpp b/lib/Ray/sources/Drawables/2D/Rectangle.hpp index e0d32dff..6442a7f1 100644 --- a/lib/Ray/sources/Drawables/2D/Rectangle.hpp +++ b/lib/Ray/sources/Drawables/2D/Rectangle.hpp @@ -42,11 +42,33 @@ namespace RAY::Drawables::Drawables2D { //! @return the dimensions of the rectangle const Vector2 &getDimensions(void); + //! @return the width of the rectangle + float getWidth(void) const; + + //! @return the height of the rectangle + float getHeight(void) const; + //! @brief set dimensions Rectangle &setDimensions(const Vector2 &dimensions); + //! @brief increment width of the rectangle + //! @param width incrementer + Rectangle &incrementWidth(float width); + + //! @brief increment height of the rectangle + //! @param height incrementer + Rectangle &incrementHeight(float height); + + //! @brief set rectangle's height + //! @param height height of the rectangle + Rectangle &setHeight(float height); + + //! @brief set rectangle's width + //! @param width width of the rectangle + Rectangle &setWidth(float width); + //! @brief set dimensions - Rectangle &setDimensions(int x, int y); + Rectangle &setDimensions(float x, float y); //! @brief Draw point on window virtual void drawOn(RAY::Window &) override; diff --git a/sources/Component/IntroAnimation/IntroAnimationComponent.hpp b/sources/Component/IntroAnimation/IntroAnimationComponent.hpp index 694b875a..0def3a25 100644 --- a/sources/Component/IntroAnimation/IntroAnimationComponent.hpp +++ b/sources/Component/IntroAnimation/IntroAnimationComponent.hpp @@ -9,10 +9,9 @@ namespace BBM class IntroAnimationComponent : public WAL::Component { public: - unsigned int frame = 0; + unsigned int frameCounter = 0; enum animationSteps { - init, boxBlinking, topLeftgrowing, bottomRightGrowing, @@ -21,7 +20,7 @@ namespace BBM prompt, }; - enum animationSteps currentStep = init; + enum animationSteps currentStep = boxBlinking; //! @inherit Component *clone(WAL::Entity &entity) const override; diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index bd8204c1..80f057cc 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -90,6 +92,7 @@ namespace BBM .addSystem() .addSystem() .addSystem() + .addSystem() .addSystem(); } @@ -606,8 +609,12 @@ namespace BBM { auto scene = std::make_shared(); + + auto &splashComponent = scene->addEntity("animation component") + .addComponent(); auto &background = scene->addEntity("background") - .addComponent(0, 0, 0) + .addComponent(RAY::Vector2(), RAY::Vector2(1920, 1080)); return scene; } diff --git a/sources/System/IntroAnimation/IntroAnimationSystem.cpp b/sources/System/IntroAnimation/IntroAnimationSystem.cpp index 74f3a89a..10243eae 100644 --- a/sources/System/IntroAnimation/IntroAnimationSystem.cpp +++ b/sources/System/IntroAnimation/IntroAnimationSystem.cpp @@ -1,9 +1,7 @@ -#include #include "Component/Button/ButtonComponent.hpp" #include "Component/Position/PositionComponent.hpp" #include "System/IntroAnimation/IntroAnimationSystem.hpp" -#include "Component/Controllable/ControllableComponent.hpp" #include "Entity/Entity.hpp" #include "Component/Renderer/Drawable2DComponent.hpp" #include @@ -18,26 +16,60 @@ namespace BBM void IntroAnimationSystem::onFixedUpdate(WAL::ViewEntity &entity) { + static const RAY::Vector2 logoPos(1920 / 2 - 128, 1080 / 2 - 128); auto &component = entity.get(); - auto &scene = wal.getScene(); + auto scene = wal.getScene(); + RAY2D::Rectangle *rectangle = nullptr; + static auto &bottomRectangle = scene->addEntity("bottom Rectangle") + .addComponent(1920 / 2 - 128, 1080 / 2 - 128, 0) + .addComponent(logoPos, RAY::Vector2(16, 16), BLACK); + static auto &leftRectangle = scene->addEntity("left Rectangle") + .addComponent(1920 / 2 - 128, 1080 / 2 - 128, 0) + .addComponent(logoPos, RAY::Vector2(16, 16), BLACK); + static auto &rightRectangle = scene->addEntity("right Rectangle") + .addComponent(1920 / 2 - 128, 1080 / 2 - 128, 0) + .addComponent(logoPos, RAY::Vector2(16, 16), BLACK); + static auto &topRectangle = scene->addEntity("top Rectangle") + .addComponent(1920 / 2 - 128, 1080 / 2 - 128, 0) + .addComponent(logoPos, RAY::Vector2(16, 16), BLACK); switch (component.currentStep) { - case IntroAnimationComponent::animationSteps::init: - scene->addEntity("white background") - .addComponent(BBM::Vector2f(), BBM::Vector2f(1920, 1080), WHITE); - - scene->addEntity("blinking square").addComponent(BBM::Vector2f(), BBM::Vector2f(16, 16), WHITE); - component.currentStep = IntroAnimationComponent::animationSteps::boxBlinking; - break; case IntroAnimationComponent::animationSteps::boxBlinking: - - if ((component.frame / 15) % 2) - scene->getEntities() + if ((component.frameCounter / 15) % 2) + topRectangle.getComponent().drawable->setColor(BLACK); + else + topRectangle.getComponent().drawable->setColor(WHITE); + if (component.frameCounter == 120) { + component.currentStep = IntroAnimationComponent::animationSteps::topLeftgrowing; + component.frameCounter = -1; + topRectangle.getComponent().drawable->setColor(BLACK); + leftRectangle.getComponent().drawable->setColor(BLACK); + } + break; + case IntroAnimationComponent::animationSteps::topLeftgrowing: + rectangle = dynamic_cast(leftRectangle.getComponent().drawable.get()); + rectangle->incrementHeight(4); + rectangle = dynamic_cast(topRectangle.getComponent().drawable.get()); + rectangle->incrementWidth(4); + if (rectangle->getWidth() == 256) { + component.currentStep = IntroAnimationComponent::animationSteps::bottomRightGrowing; + bottomRectangle.getComponent().position = Vector3f(1920 / 2 - 128, 1080 / 2 - 128 + 240, 0); + rightRectangle.getComponent().position = Vector3f(1920 / 2 - 128 + 240, 1080 / 2 - 128, 0); + } + break; + case IntroAnimationComponent::animationSteps::bottomRightGrowing: + rectangle = dynamic_cast(bottomRectangle.getComponent().drawable.get()); + rectangle->incrementWidth(4); + rectangle = dynamic_cast(rightRectangle.getComponent().drawable.get()); + rectangle->incrementHeight(4); + if (rectangle->getHeight() == 256) + component.currentStep = IntroAnimationComponent::animationSteps::lettersTyping; + break; + default: break; - } - component.frame++; + component.frameCounter++; } void IntroAnimationSystem::onSelfUpdate(void) From 5b45158d26cf935e28cdc3f524fbeb7769db3438 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Sat, 12 Jun 2021 14:59:40 +0200 Subject: [PATCH 43/82] sound playing at end of intro --- assets/sounds/splash_sound.ogg | Bin 0 -> 6361 bytes sources/Runner/Runner.cpp | 18 ++++++++--- .../IntroAnimation/IntroAnimationSystem.cpp | 29 ++++++++++++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 assets/sounds/splash_sound.ogg diff --git a/assets/sounds/splash_sound.ogg b/assets/sounds/splash_sound.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d9092e5300ff3475036d398a91b032aced870a0b GIT binary patch literal 6361 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 { - if (component.pause) { + if (component.pause && gameState.currentScene == GameState::SceneID::GameScene) { gameState.nextScene = GameState::SceneID::PauseMenuScene; break; + } else if (gameState.currentScene == GameState::SceneID::SplashScreen && component.jump) { + gameState.nextScene = GameState::SceneID::TitleScreenScene; + break; } } } @@ -609,12 +612,19 @@ namespace BBM { auto scene = std::make_shared(); - auto &splashComponent = scene->addEntity("animation component") - .addComponent(); + .addComponent() + .addComponent() + .addComponent(); auto &background = scene->addEntity("background") .addComponent(0, 0, 0) .addComponent(RAY::Vector2(), RAY::Vector2(1920, 1080)); + auto &text = scene->addEntity("powered by text") + .addComponent(1920 / 2 - 200, 1080 / 2 - 180, 0) + .addComponent("powered by", 30, RAY::Vector2(), BLACK); + auto &skipText = scene->addEntity("Press space to skip") + .addComponent(1920 - 250, 1080 - 30, 0) + .addComponent("Press space to skip", 20, RAY::Vector2(), BLACK); return scene; } diff --git a/sources/System/IntroAnimation/IntroAnimationSystem.cpp b/sources/System/IntroAnimation/IntroAnimationSystem.cpp index 10243eae..c5671987 100644 --- a/sources/System/IntroAnimation/IntroAnimationSystem.cpp +++ b/sources/System/IntroAnimation/IntroAnimationSystem.cpp @@ -4,7 +4,11 @@ #include "System/IntroAnimation/IntroAnimationSystem.hpp" #include "Entity/Entity.hpp" #include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" #include +#include +#include "Runner/Runner.hpp" +#include "Component/Music/MusicComponent.hpp" namespace RAY2D = RAY::Drawables::Drawables2D; @@ -20,6 +24,10 @@ namespace BBM auto &component = entity.get(); auto scene = wal.getScene(); RAY2D::Rectangle *rectangle = nullptr; + RAY2D::Text *text = nullptr; + static auto &rayText = scene->addEntity("raylibtext Rectangle") + .addComponent(1920 / 2 - 44, 1080 / 2 + 48, 0) + .addComponent("", 50, RAY::Vector2(), BLACK); static auto &bottomRectangle = scene->addEntity("bottom Rectangle") .addComponent(1920 / 2 - 128, 1080 / 2 - 128, 0) .addComponent(logoPos, RAY::Vector2(16, 16), BLACK); @@ -32,6 +40,7 @@ namespace BBM static auto &topRectangle = scene->addEntity("top Rectangle") .addComponent(1920 / 2 - 128, 1080 / 2 - 128, 0) .addComponent(logoPos, RAY::Vector2(16, 16), BLACK); + static short letterCounter = 0; switch (component.currentStep) { @@ -40,7 +49,7 @@ namespace BBM topRectangle.getComponent().drawable->setColor(BLACK); else topRectangle.getComponent().drawable->setColor(WHITE); - if (component.frameCounter == 120) { + if (component.frameCounter == 60) { component.currentStep = IntroAnimationComponent::animationSteps::topLeftgrowing; component.frameCounter = -1; topRectangle.getComponent().drawable->setColor(BLACK); @@ -63,8 +72,24 @@ namespace BBM rectangle->incrementWidth(4); rectangle = dynamic_cast(rightRectangle.getComponent().drawable.get()); rectangle->incrementHeight(4); - if (rectangle->getHeight() == 256) + if (rectangle->getHeight() == 256) { component.currentStep = IntroAnimationComponent::animationSteps::lettersTyping; + component.frameCounter = 0; + } + break; + case IntroAnimationComponent::animationSteps::lettersTyping: + if ((component.frameCounter / 15) % 2) { + letterCounter++; + text = dynamic_cast(rayText.getComponent().drawable.get()); + if (letterCounter == 2) { + scene->addEntity("startup sound") + .addComponent("assets/sounds/splash_sound.ogg") + .getComponent().playMusic(); + } + text->setText(std::string("raylib").substr(0, letterCounter)); + } + if (component.frameCounter == 60) + Runner::gameState.nextScene = Runner::gameState.TitleScreenScene; break; default: break; From 230b611b698830e5396dcc28d9c3dbe56cef199d Mon Sep 17 00:00:00 2001 From: Askou Date: Mon, 14 Jun 2021 10:01:56 +0200 Subject: [PATCH 44/82] Add another flat map type --- sources/Map/Map.cpp | 21 +++++++++++++++------ sources/Runner/Runner.cpp | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index 8b5d8206..90de3fec 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -303,10 +303,10 @@ namespace BBM { double rnd = static_cast(std::rand()) / RAND_MAX; - if (rnd > 0.95) + if (rnd > 0.98) return HOLE; if (rnd > 0.25) - return BREAKABLE; + return NOTHING; return NOTHING; } @@ -376,10 +376,19 @@ namespace BBM MapGenerator::MapBlock MapGenerator::createLongClassicUnbreakable(MapBlock map, int width, int height) { - for (int i = 0; i < width + 1; i++) - for (int j = 0; j < height + 1; j++) - if ((i % 3) && !((j + 1) % 2)) + int placedSpace = 0; + + for (int i = 1; i < width; i++) { + placedSpace = 0; + for (int j = 1; j < height; j++) { + if (!(j % 2)) + continue; + if (i < (width / 2 - width / 10) || i > (width / 2 + width / 10)) map[std::make_tuple(i, 0, j)] = UNBREAKABLE; + else + placedSpace++; + } + } return (map); } @@ -399,7 +408,7 @@ namespace BBM if (map[std::make_tuple(i, 0, j)] == SPAWNER) continue; if (isCloseToBlockType(map, i, 0, j, SPAWNER)) { - map[std::make_tuple(i, 0, j)] = NOTHING; + map[std::make_tuple(i, isNotClassic ? -1 : 0, j)] = isNotClassic ? BUMPER : NOTHING; } else { map[std::make_tuple(i, 0, j)] = getRandomBlockType(); } diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 613b6a58..687fcc1d 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -551,7 +551,7 @@ namespace BBM scene->addEntity("camera") .addComponent(8, 25, 7) .addComponent(Vector3f(8, 0, 8)); - MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16), scene); + MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16, false, true), scene); return scene; } From ae68d5ab6883336940376e30c703c6260f713eb2 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Mon, 14 Jun 2021 10:07:08 +0200 Subject: [PATCH 45/82] add wires + bounding box drawing for 3D shapes/Models --- lib/Ray/sources/Drawables/3D/Cube.cpp | 5 +++++ lib/Ray/sources/Drawables/3D/Cube.hpp | 3 +++ lib/Ray/sources/Drawables/3D/Cylinder.cpp | 5 +++++ lib/Ray/sources/Drawables/3D/Cylinder.hpp | 2 ++ lib/Ray/sources/Drawables/3D/Sphere.cpp | 5 +++++ lib/Ray/sources/Drawables/3D/Sphere.hpp | 3 +++ lib/Ray/sources/Drawables/ADrawable3D.cpp | 3 +++ lib/Ray/sources/Drawables/ADrawable3D.hpp | 3 +++ lib/Ray/sources/Model/Model.cpp | 14 ++++++++++++++ lib/Ray/sources/Model/Model.hpp | 3 +++ sources/System/Renderer/RenderSystem.cpp | 4 +++- 11 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/Ray/sources/Drawables/3D/Cube.cpp b/lib/Ray/sources/Drawables/3D/Cube.cpp index 6f651a15..7875e99a 100644 --- a/lib/Ray/sources/Drawables/3D/Cube.cpp +++ b/lib/Ray/sources/Drawables/3D/Cube.cpp @@ -30,4 +30,9 @@ namespace RAY::Drawables::Drawables3D { DrawCubeV(this->_position, this->_dimensions, this->_color); } + + void Cube::drawWiresOn(RAY::Window &) + { + DrawCubeWiresV(this->_position, this->_dimensions, GREEN); + } } \ No newline at end of file diff --git a/lib/Ray/sources/Drawables/3D/Cube.hpp b/lib/Ray/sources/Drawables/3D/Cube.hpp index d1fff6f9..96347a95 100644 --- a/lib/Ray/sources/Drawables/3D/Cube.hpp +++ b/lib/Ray/sources/Drawables/3D/Cube.hpp @@ -41,6 +41,9 @@ namespace RAY::Drawables::Drawables3D { //! @brief Draw circle on window void drawOn(RAY::Window &) override; + + //! @brief Draw cube's wires on window + void drawWiresOn(RAY::Window &) override; private: //! @brief Dimensions of the cube Vector3 _dimensions; diff --git a/lib/Ray/sources/Drawables/3D/Cylinder.cpp b/lib/Ray/sources/Drawables/3D/Cylinder.cpp index 64db931d..6dfb2a1f 100644 --- a/lib/Ray/sources/Drawables/3D/Cylinder.cpp +++ b/lib/Ray/sources/Drawables/3D/Cylinder.cpp @@ -52,4 +52,9 @@ namespace RAY::Drawables::Drawables3D { DrawCylinder(this->_position, this->_topRadius, this->_bottomRadius, this->_height, 0, this->_color); } + + void Cylinder::drawWiresOn(RAY::Window &) + { + DrawCylinderWires(this->_position, this->_topRadius, this->_bottomRadius, this->_height, 0, GREEN); + } } \ No newline at end of file diff --git a/lib/Ray/sources/Drawables/3D/Cylinder.hpp b/lib/Ray/sources/Drawables/3D/Cylinder.hpp index dc09fb5d..32871514 100644 --- a/lib/Ray/sources/Drawables/3D/Cylinder.hpp +++ b/lib/Ray/sources/Drawables/3D/Cylinder.hpp @@ -55,6 +55,8 @@ namespace RAY::Drawables::Drawables3D { //! @brief Draw point on window void drawOn(RAY::Window &) override; + //! @brief Draw cylinder's wires on window + void drawWiresOn(RAY::Window &) override; private: //! @brief Radius of the cylinder float _topRadius; diff --git a/lib/Ray/sources/Drawables/3D/Sphere.cpp b/lib/Ray/sources/Drawables/3D/Sphere.cpp index 7d23fc48..2949606e 100644 --- a/lib/Ray/sources/Drawables/3D/Sphere.cpp +++ b/lib/Ray/sources/Drawables/3D/Sphere.cpp @@ -30,4 +30,9 @@ namespace RAY::Drawables::Drawables3D { DrawSphere(this->_position, this->_radius, this->_color); } + + void Sphere::drawWiresOn(RAY::Window &) + { + DrawSphereWires(this->_position, this->_radius, 10, 10, GREEN); + } } \ No newline at end of file diff --git a/lib/Ray/sources/Drawables/3D/Sphere.hpp b/lib/Ray/sources/Drawables/3D/Sphere.hpp index d053ccf9..24c31a8b 100644 --- a/lib/Ray/sources/Drawables/3D/Sphere.hpp +++ b/lib/Ray/sources/Drawables/3D/Sphere.hpp @@ -40,6 +40,9 @@ namespace RAY::Drawables::Drawables3D { //! @brief Draw point on window void drawOn(RAY::Window &) override; + //! @brief Draw sphere's wires on window + void drawWiresOn(RAY::Window &) override; + private: //! @brief Radius of the sphere int _radius; diff --git a/lib/Ray/sources/Drawables/ADrawable3D.cpp b/lib/Ray/sources/Drawables/ADrawable3D.cpp index 0fff69f8..fabc12fd 100644 --- a/lib/Ray/sources/Drawables/ADrawable3D.cpp +++ b/lib/Ray/sources/Drawables/ADrawable3D.cpp @@ -36,4 +36,7 @@ namespace RAY::Drawables this->_position = position; return *this; } + + void ADrawable3D::drawWiresOn(RAY::Window &) + {} } \ No newline at end of file diff --git a/lib/Ray/sources/Drawables/ADrawable3D.hpp b/lib/Ray/sources/Drawables/ADrawable3D.hpp index cc989fed..4c82ded6 100644 --- a/lib/Ray/sources/Drawables/ADrawable3D.hpp +++ b/lib/Ray/sources/Drawables/ADrawable3D.hpp @@ -30,6 +30,9 @@ namespace RAY::Drawables { //! @brief Draw drawble on window void drawOn(RAY::Window &) override = 0; + //! @brief Draw drawble's wires on window + virtual void drawWiresOn(RAY::Window &); + //! @return the color of the ADrawable const RAY::Color &getColor(void) const; diff --git a/lib/Ray/sources/Model/Model.cpp b/lib/Ray/sources/Model/Model.cpp index 9fd5b31e..2239c359 100644 --- a/lib/Ray/sources/Model/Model.cpp +++ b/lib/Ray/sources/Model/Model.cpp @@ -114,6 +114,20 @@ namespace RAY::Drawables::Drawables3D this->_color); } + void Model::drawWiresOn(RAY::Window &) + { + if (this->_model->meshCount) { + ::BoundingBox box = GetMeshBoundingBox(*this->_model->meshes); + box.min.x += this->_position.x; + box.min.y += this->_position.y; + box.min.z += this->_position.z; + box.max.x += this->_position.x; + box.max.y += this->_position.y; + box.max.z += this->_position.z; + DrawBoundingBox(box, GREEN); + } + } + void Model::setShader(const RAY::Shader &shader) { this->_originalShader = this->_model->materials[0].shader; diff --git a/lib/Ray/sources/Model/Model.hpp b/lib/Ray/sources/Model/Model.hpp index d67706be..2bf6cf47 100644 --- a/lib/Ray/sources/Model/Model.hpp +++ b/lib/Ray/sources/Model/Model.hpp @@ -87,6 +87,9 @@ namespace RAY::Drawables::Drawables3D { void drawOn(RAY::Window &) override; + //! @brief Draw model's wires on window + void drawWiresOn(RAY::Window &) override; + private: //! @brief Raw data from raylib std::shared_ptr<::Model> _model; diff --git a/sources/System/Renderer/RenderSystem.cpp b/sources/System/Renderer/RenderSystem.cpp index 07b64134..d901b115 100644 --- a/sources/System/Renderer/RenderSystem.cpp +++ b/sources/System/Renderer/RenderSystem.cpp @@ -40,6 +40,8 @@ namespace BBM modelShader->model->setShader(modelShader->getShader()); drawable.drawable->setPosition(pos.position); drawable.drawable->drawOn(this->_window); + if (this->_debugMode) + drawable.drawable->drawWiresOn(this->_window); if (modelShader) modelShader->model->resetShader(); } @@ -59,7 +61,7 @@ namespace BBM } } if (this->_debugMode) - this->_window.drawFPS(Vector2f()); + this->_window.drawFPS(Vector2f(10, 10)); this->_window.endDrawing(); } From ce8ce3b4a9095cf7242dc45aaf3657a44d4d3276 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Mon, 14 Jun 2021 10:26:08 +0200 Subject: [PATCH 46/82] split runner file: splash, title + credit --- CMakeLists.txt | 3 + sources/Runner/CreditScene.cpp | 73 +++++++++++++++++++ sources/Runner/Runner.cpp | 103 --------------------------- sources/Runner/SplashScreenScene.cpp | 37 ++++++++++ sources/Runner/TitleScreenScene.cpp | 47 ++++++++++++ 5 files changed, 160 insertions(+), 103 deletions(-) create mode 100644 sources/Runner/CreditScene.cpp create mode 100644 sources/Runner/SplashScreenScene.cpp create mode 100644 sources/Runner/TitleScreenScene.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b4aa8778..072f19b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,9 @@ set(SOURCES sources/Component/IntroAnimation/IntroAnimationComponent.cpp sources/System/IntroAnimation/IntroAnimationSystem.hpp sources/System/IntroAnimation/IntroAnimationSystem.cpp + sources/Runner/SplashScreenScene.cpp + sources/Runner/TitleScreenScene.cpp + sources/Runner/CreditScene.cpp ) add_executable(bomberman sources/main.cpp diff --git a/sources/Runner/CreditScene.cpp b/sources/Runner/CreditScene.cpp new file mode 100644 index 00000000..38c9b77e --- /dev/null +++ b/sources/Runner/CreditScene.cpp @@ -0,0 +1,73 @@ + +#include +#include +#include "Runner.hpp" +#include +#include "Component/Music/MusicComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Button/ButtonComponent.hpp" +#include "Drawables/2D/Text.hpp" + +namespace RAY2D = RAY::Drawables::Drawables2D; + +namespace BBM +{ + std::shared_ptr Runner::loadCreditScene() + { + auto scene = std::make_shared(); + static const std::map sounds = { + {SoundComponent::JUMP, "assets/sounds/click.ogg"} + }; + + scene->addEntity("background") + .addComponent() + .addComponent("assets/plain_menu_background.png"); + + scene->addEntity("Control entity") + .addComponent() + .addComponent() + .addComponent("assets/musics/music_title.ogg") + .addComponent(sounds); + + auto &raylibLogo = scene->addEntity("raylib logo") + .addComponent(1920 / 4, 1080 / 1.75, 0) + .addComponent("assets/raylib.png"); + auto &raylibText = scene->addEntity("raylib text") + .addComponent(1920 / 4, 1080 / 2, 0) + .addComponent("Powered by:", 35, RAY::Vector2(), BLACK); + auto &otherRepoText = scene->addEntity("other repo text") + .addComponent(1920 / 4, 1080 / 4, 0) + .addComponent("Many Thanks to:", 35, RAY::Vector2(), BLACK); + auto &BriansRepo = scene->addEntity("thx brian") + .addComponent(1920 / 3.5, 1080 / 3.5, 0) + .addComponent("Brian Guitteny (and his team)", 35, RAY::Vector2(), BLACK); + auto &team = scene->addEntity("team") + .addComponent(1920 / 1.5, 1080 / 3.5, 0) + .addComponent("Team:\n Zoe Roux\n Clément Le Bihan\n Arthur Jamet\n Louis Auzuret\n Benjamin Henry\n Tom Augier", 35, RAY::Vector2(), BLACK); + auto &back = scene->addEntity("back to menu") + .addComponent(10, 1080 - 85, 0) + .addComponent("assets/buttons/button_back.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back_hovered.png"); + }); + return scene; + } + +} \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index d9410f21..364f90e4 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -108,35 +108,6 @@ namespace BBM .addSystem(window); } - std::shared_ptr Runner::loadTitleScreenScene() - { - static const std::map sounds = { - {SoundComponent::JUMP, "assets/sounds/click.ogg"} - }; - auto scene = std::make_shared(); - scene->addEntity("control") - .addComponent() - .addComponent() - .addComponent(sounds) - .addComponent("assets/musics/music_title.ogg"); - scene->addEntity("background") - .addComponent() - .addComponent("assets/plain_menu_background.png"); - scene->addEntity("logo") - .addComponent(320, 180, 0) - .addComponent("assets/logo_big.png"); - scene->addEntity("text_prompt") - .addComponent(1920 / 2.5, 1080 - 130, 0) - .addComponent("Press space", 70, RAY::Vector2(), BLACK) - .addComponent() - .addComponent() - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; - }); - return scene; - } - std::shared_ptr Runner::loadMainMenuScene() { static const std::map sounds = { @@ -554,80 +525,6 @@ namespace BBM return scene; } - std::shared_ptr Runner::loadCreditScene() - { - auto scene = std::make_shared(); - static const std::map sounds = { - {SoundComponent::JUMP, "assets/sounds/click.ogg"} - }; - - scene->addEntity("background") - .addComponent() - .addComponent("assets/plain_menu_background.png"); - - scene->addEntity("Control entity") - .addComponent() - .addComponent() - .addComponent("assets/musics/music_title.ogg") - .addComponent(sounds); - - auto &raylibLogo = scene->addEntity("raylib logo") - .addComponent(1920 / 4, 1080 / 1.75, 0) - .addComponent("assets/raylib.png"); - auto &raylibText = scene->addEntity("raylib text") - .addComponent(1920 / 4, 1080 / 2, 0) - .addComponent("Powered by:", 35, RAY::Vector2(), BLACK); - auto &otherRepoText = scene->addEntity("other repo text") - .addComponent(1920 / 4, 1080 / 4, 0) - .addComponent("Many Thanks to:", 35, RAY::Vector2(), BLACK); - auto &BriansRepo = scene->addEntity("thx brian") - .addComponent(1920 / 3.5, 1080 / 3.5, 0) - .addComponent("Brian Guitteny (and his team)", 35, RAY::Vector2(), BLACK); - auto &team = scene->addEntity("team") - .addComponent(1920 / 1.5, 1080 / 3.5, 0) - .addComponent("Team:\n Zoe Roux\n Clément Le Bihan\n Arthur Jamet\n Louis Auzuret\n Benjamin Henry\n Tom Augier", 35, RAY::Vector2(), BLACK); - auto &back = scene->addEntity("back to menu") - .addComponent(10, 1080 - 85, 0) - .addComponent("assets/buttons/button_back.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_back.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_back_hovered.png"); - }); - return scene; - } - - std::shared_ptr Runner::loadSplashScreenScene() - { - auto scene = std::make_shared(); - - auto &splashComponent = scene->addEntity("animation component") - .addComponent() - .addComponent() - .addComponent(); - auto &background = scene->addEntity("background") - .addComponent(0, 0, 0) - .addComponent(RAY::Vector2(), RAY::Vector2(1920, 1080)); - auto &text = scene->addEntity("powered by text") - .addComponent(1920 / 2 - 200, 1080 / 2 - 180, 0) - .addComponent("powered by", 30, RAY::Vector2(), BLACK); - auto &skipText = scene->addEntity("Press space to skip") - .addComponent(1920 - 250, 1080 - 30, 0) - .addComponent("Press space to skip", 20, RAY::Vector2(), BLACK); - return scene; - } - void Runner::loadScenes() { gameState._loadedScenes[GameState::SceneID::MainMenuScene] = loadMainMenuScene(); diff --git a/sources/Runner/SplashScreenScene.cpp b/sources/Runner/SplashScreenScene.cpp new file mode 100644 index 00000000..455a0e95 --- /dev/null +++ b/sources/Runner/SplashScreenScene.cpp @@ -0,0 +1,37 @@ + +#include +#include +#include "Runner.hpp" +#include "Component/Music/MusicComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Button/ButtonComponent.hpp" +#include "Drawables/2D/Text.hpp" +#include "Component/IntroAnimation/IntroAnimationComponent.hpp" + +namespace RAY2D = RAY::Drawables::Drawables2D; + +namespace BBM +{ + std::shared_ptr Runner::loadSplashScreenScene() + { + auto scene = std::make_shared(); + + auto &splashComponent = scene->addEntity("animation component") + .addComponent() + .addComponent() + .addComponent(); + auto &background = scene->addEntity("background") + .addComponent(0, 0, 0) + .addComponent(RAY::Vector2(), RAY::Vector2(1920, 1080)); + auto &text = scene->addEntity("powered by text") + .addComponent(1920 / 2 - 200, 1080 / 2 - 180, 0) + .addComponent("powered by", 30, RAY::Vector2(), BLACK); + auto &skipText = scene->addEntity("Press space to skip") + .addComponent(1920 - 250, 1080 - 30, 0) + .addComponent("Press space to skip", 20, RAY::Vector2(), BLACK); + return scene; + } +} \ No newline at end of file diff --git a/sources/Runner/TitleScreenScene.cpp b/sources/Runner/TitleScreenScene.cpp new file mode 100644 index 00000000..0cbbf488 --- /dev/null +++ b/sources/Runner/TitleScreenScene.cpp @@ -0,0 +1,47 @@ + +#include +#include +#include "Runner.hpp" +#include +#include "Component/Music/MusicComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Button/ButtonComponent.hpp" +#include "Drawables/2D/Text.hpp" + +namespace RAY2D = RAY::Drawables::Drawables2D; + +namespace BBM +{ + std::shared_ptr Runner::loadTitleScreenScene() + { + static const std::map sounds = { + {SoundComponent::JUMP, "assets/sounds/click.ogg"} + }; + auto scene = std::make_shared(); + scene->addEntity("control") + .addComponent() + .addComponent() + .addComponent(sounds) + .addComponent("assets/musics/music_title.ogg"); + scene->addEntity("background") + .addComponent() + .addComponent("assets/plain_menu_background.png"); + scene->addEntity("logo") + .addComponent(320, 180, 0) + .addComponent("assets/logo_big.png"); + scene->addEntity("text_prompt") + .addComponent(1920 / 2.5, 1080 - 130, 0) + .addComponent("Press space", 70, RAY::Vector2(), BLACK) + .addComponent() + .addComponent() + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; + }); + return scene; + } +} \ No newline at end of file From ad71799c529fad33561db8c88e9cb3c22d46891a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Mon, 14 Jun 2021 10:31:49 +0200 Subject: [PATCH 47/82] fixing unit tests --- tests/CollisionTest.cpp | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/CollisionTest.cpp b/tests/CollisionTest.cpp index bf5a31dc..6c0795c4 100644 --- a/tests/CollisionTest.cpp +++ b/tests/CollisionTest.cpp @@ -17,6 +17,8 @@ using namespace WAL; using namespace BBM; +// WARN THE COLLISION SYSTEM IS ONLY CHECKING/LOOPING ON MOVABLE ENTITIES + TEST_CASE("Collision test", "[Component][System]") { @@ -25,6 +27,7 @@ TEST_CASE("Collision test", "[Component][System]") wal.changeScene(std::make_shared()); wal.getScene()->addEntity("player") .addComponent() + .addComponent() .addComponent([](Entity &actual, const Entity &, int _) { try { auto &pos = actual.getComponent(); @@ -118,6 +121,7 @@ TEST_CASE("Collision test callbacks calls", "[Component][System]") wal.getScene()->addEntity("block") .addComponent(0, 0, 0) + .addComponent() .addComponent( [&nbCallbacksCalled](Entity &actual, const Entity &, int) { nbCallbacksCalled++; }, [&nbCallbacksCalled](Entity &actual, const Entity &, int) { @@ -156,6 +160,7 @@ TEST_CASE("Collision test callbacks args", "[Component][System]") wal.getScene()->addEntity("player") .addComponent() + .addComponent() .addComponent( [&nbCallbacksCalled](Entity &actual, const Entity &other, int) { nbCallbacksCalled++; @@ -170,6 +175,7 @@ TEST_CASE("Collision test callbacks args", "[Component][System]") wal.getScene()->addEntity("block") .addComponent(0, 0, 0) + .addComponent() .addComponent( [&nbCallbacksCalled](Entity &actual, const Entity &other, int) { nbCallbacksCalled++; @@ -193,6 +199,57 @@ TEST_CASE("Collision test callbacks args", "[Component][System]") REQUIRE(nbCallbacksCalled == 4); } +TEST_CASE("Collision test callbacks args with only one movable entity", "[Component][System]") +{ + int nbCallbacksCalled = 0; + Wal wal; + CollisionSystem collision(wal); + MovableSystem movable(wal); + + wal.changeScene(std::make_shared()); + + wal.getScene()->addEntity("player") + .addComponent() + .addComponent() + .addComponent( + [&nbCallbacksCalled](Entity &actual, const Entity &other, int) { + nbCallbacksCalled++; + REQUIRE(actual.getName() == "player"); + REQUIRE(other.getName() == "block"); + }, + [&nbCallbacksCalled](Entity &actual, const Entity &other, int) { + // lambda should not be called + nbCallbacksCalled++; + REQUIRE(other.getName() == "plfayer"); + REQUIRE(actual.getName() == "blofck"); + }, 0, 5.0); + + wal.getScene()->addEntity("block") + .addComponent(0, 0, 0) + .addComponent( + [&nbCallbacksCalled](Entity &actual, const Entity &other, int) { + // lambda should not be called + nbCallbacksCalled++; + REQUIRE(other.getName() == "playefr"); + REQUIRE(actual.getName() == "blocfk"); + }, + [&nbCallbacksCalled](Entity &actual, const Entity &other, int) { + nbCallbacksCalled++; + REQUIRE(actual.getName() == "player"); + REQUIRE(other.getName() == "block"); + }, 0, 1); + Entity &entity = wal.getScene()->getEntities().front(); + REQUIRE(entity.getComponent().position == Vector3f()); + + entity.getComponent().bound.x = 5; + entity.getComponent().bound.y = 5; + entity.getComponent().bound.z = 5; + + collision.update(std::chrono::nanoseconds(1)); + collision.fixedUpdate(); + REQUIRE(nbCallbacksCalled == 2); +} + TEST_CASE("Vector round", "[Vector]") { Vector3f v(1.3, 1.5, 1.7); From de579ccda69af2a7cce9913ded6450c6434f4224 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 14 Jun 2021 10:42:50 +0200 Subject: [PATCH 48/82] Handling ready buttons --- lib/Ray/sources/Drawables/Texture.cpp | 1 + sources/Component/Lobby/LobbyComponent.hpp | 5 ++++- sources/System/Lobby/LobbySystem.cpp | 22 +++++++++++----------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/Ray/sources/Drawables/Texture.cpp b/lib/Ray/sources/Drawables/Texture.cpp index ae01b881..7a70a459 100644 --- a/lib/Ray/sources/Drawables/Texture.cpp +++ b/lib/Ray/sources/Drawables/Texture.cpp @@ -38,6 +38,7 @@ namespace RAY { return *this; this->_texture = this->_texturesCache.fetch(filename); this->_resourcePath = filename; + this->_dimensions = Vector2(this->_texture->width, this->_texture->height); return *this; } diff --git a/sources/Component/Lobby/LobbyComponent.hpp b/sources/Component/Lobby/LobbyComponent.hpp index 76146d6c..28135c11 100644 --- a/sources/Component/Lobby/LobbyComponent.hpp +++ b/sources/Component/Lobby/LobbyComponent.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace BBM { @@ -24,8 +25,10 @@ namespace BBM bool ready = false; //! @brief The entity containing the ready display. WAL::Entity &readyButton; + //! @brief The time of last input that this lobby player has made. + std::chrono::time_point lastInput; - Component * clone(WAL::Entity &entity) const override; + Component *clone(WAL::Entity &entity) const override; //! @brief Create a new lobby component. explicit LobbyComponent(WAL::Entity &entity, int playerID, WAL::Entity &readyButton); diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index bef333a8..ccc368d9 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -18,6 +18,11 @@ namespace BBM void LobbySystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) { auto &lobby = entity.get(); + + auto lastTick = std::chrono::steady_clock::now(); + if (lastTick - lobby.lastInput < std::chrono::milliseconds(150)) + return; + if (lobby.layout == ControllableComponent::NONE) { for (auto &[_, controller] : this->_wal.getScene()->view()) { if (controller.jump) { @@ -25,27 +30,22 @@ namespace BBM return view.get().layout == controller.layout; })) return; + lobby.lastInput = lastTick; lobby.layout = controller.layout; entity.get().drawable = std::make_shared("assets/player/icons/blue.png"); return; } } } + for (auto &[_, controller] : this->_wal.getScene()->view()) { if (controller.layout == lobby.layout && controller.jump) { lobby.ready = true; - if (lobby.ready) { - auto *texture = dynamic_cast(lobby.readyButton.getComponent().drawable.get()); - if (texture) - texture->use("assets/player/icons/ready.png"); - } + lobby.lastInput = lastTick; + auto *texture = dynamic_cast(lobby.readyButton.getComponent().drawable.get()); + if (texture) + texture->use("assets/player/icons/ready.png"); } } } - - //void LobbySystem::updateEntityConnectedUser(WAL::Entity &entity) - //{ - // RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - // texture->use("assets/player/icons/blue.png"); - //} } \ No newline at end of file From 7fb62d10f4a763fa4b7d39057e627c66ee66e47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Mon, 14 Jun 2021 10:47:12 +0200 Subject: [PATCH 49/82] indent issues --- .../System/BombHolder/BombHolderSystem.cpp | 27 ++++++++------ .../System/BombHolder/BombHolderSystem.hpp | 35 ++++++++++++------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 4a575b8b..db3c5c55 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -22,20 +22,23 @@ namespace BBM std::chrono::nanoseconds BombHolderSystem::explosionTimer = 2s; void BombHolderSystem::_bombCollide(WAL::Entity &entity, - const WAL::Entity &bomb, - CollisionComponent::CollidedAxis collidedAxis) + const WAL::Entity &bomb, + CollisionComponent::CollidedAxis collidedAxis) { auto &bombInfo = bomb.getComponent(); if (bombInfo.ignoreOwner && bombInfo.ownerID == entity.getUid()) return; - return MapGenerator::wallCollided( entity, bomb, collidedAxis); + return MapGenerator::wallCollided(entity, bomb, collidedAxis); } BombHolderSystem::BombHolderSystem(WAL::Wal &wal) : System(wal) {} - void BombHolderSystem::_dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, ExpansionDirection expansionDirections) + void BombHolderSystem::_dispatchExplosion(const Vector3f &position, + WAL::Wal &wal, + int radiusToDo, + ExpansionDirection expansionDirections) { if (radiusToDo <= 0) return; @@ -45,7 +48,8 @@ namespace BBM explosion.scheduleDeletion(); }) .addComponent("assets/bombs/explosion/explosion.glb", false, - std::make_pair(MAP_DIFFUSE, "assets/bombs/explosion/blast.png")); + std::make_pair(MAP_DIFFUSE, + "assets/bombs/explosion/blast.png")); wal.getSystem().dispatchEvent([position, radiusToDo, expansionDirections](WAL::Wal &wal) { for (auto &[entity, pos, _] : wal.getScene()->view>()) { if (pos.position.round() == position) { @@ -83,16 +87,19 @@ namespace BBM .addComponent(position.round()) .addComponent(holder.damage, holder.explosionRadius, id) .addComponent(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion) - .addComponent(WAL::Callback(), - &BombHolderSystem::_bombCollide, 0.25, .75) + .addComponent( + WAL::Callback(), + &BombHolderSystem::_bombCollide, 0.25, .75) .addComponent("assets/bombs/bomb.obj", false, - std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png")); + std::make_pair(MAP_DIFFUSE, + "assets/bombs/bomb_normal.png")); holder.damage = 1; holder.explosionRadius = 3; } - void BombHolderSystem::onUpdate(WAL::ViewEntity &entity, - std::chrono::nanoseconds dtime) + void + BombHolderSystem::onUpdate(WAL::ViewEntity &entity, + std::chrono::nanoseconds dtime) { auto &holder = entity.get(); auto &position = entity.get(); diff --git a/sources/System/BombHolder/BombHolderSystem.hpp b/sources/System/BombHolder/BombHolderSystem.hpp index e7245eae..3eca4151 100644 --- a/sources/System/BombHolder/BombHolderSystem.hpp +++ b/sources/System/BombHolder/BombHolderSystem.hpp @@ -14,7 +14,8 @@ namespace BBM { - enum ExpansionDirection { + enum ExpansionDirection + { UP = 1, DOWN = 2, LEFT = 4, @@ -31,26 +32,33 @@ namespace BBM void _spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id); //! @brief Spawn a bomb at the specified position. - static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, ExpansionDirection expansionDirections); + static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, + ExpansionDirection expansionDirections); //! @brief Wrapped call to specify default arg value - inline static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo) { + inline static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo) + { return _dispatchExplosion(position, - wal, - radiusToDo, - static_cast(ExpansionDirection::DOWN - | ExpansionDirection::UP - | ExpansionDirection::FRONT - | ExpansionDirection::BACK - | ExpansionDirection::LEFT - | ExpansionDirection::RIGHT)); + wal, + radiusToDo, + static_cast( + ExpansionDirection::DOWN + | ExpansionDirection::UP + | ExpansionDirection::FRONT + | ExpansionDirection::BACK + | ExpansionDirection::LEFT + | ExpansionDirection::RIGHT + ) + ); }; //! @brief The method triggered when the bomb explode. static void _bombExplosion(WAL::Entity &bomb, WAL::Wal &); //! @brief The method called when a player collide with a bomb. - static void _bombCollide(WAL::Entity &entity, const WAL::Entity &wall, BBM::CollisionComponent::CollidedAxis collidedAxis); + static void + _bombCollide(WAL::Entity &entity, const WAL::Entity &wall, BBM::CollisionComponent::CollidedAxis collidedAxis); + public: //! @brief The explosion time of new bombs. static std::chrono::nanoseconds explosionTimer; @@ -61,10 +69,13 @@ namespace BBM //! @brief A default constructor explicit BombHolderSystem(WAL::Wal &wal); + //! @brief A bomb holder system is copy constructable BombHolderSystem(const BombHolderSystem &) = default; + //! @brief A default destructor ~BombHolderSystem() override = default; + //! @brief A bomb holder system is not assignable. BombHolderSystem &operator=(const BombHolderSystem &) = delete; }; From 3244110d27b7bdf44b9a1c7751cd9916005d4517 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Mon, 14 Jun 2021 10:47:44 +0200 Subject: [PATCH 50/82] split runner file: game scene --- CMakeLists.txt | 1 + sources/Runner/GameScene.cpp | 69 ++++++++++++++++++++++++++++++++++++ sources/Runner/Runner.cpp | 40 --------------------- 3 files changed, 70 insertions(+), 40 deletions(-) create mode 100644 sources/Runner/GameScene.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 072f19b2..96e41a30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ set(SOURCES sources/System/IntroAnimation/IntroAnimationSystem.cpp sources/Runner/SplashScreenScene.cpp sources/Runner/TitleScreenScene.cpp + sources/Runner/GameScene.cpp sources/Runner/CreditScene.cpp ) add_executable(bomberman diff --git a/sources/Runner/GameScene.cpp b/sources/Runner/GameScene.cpp new file mode 100644 index 00000000..f3a90aa6 --- /dev/null +++ b/sources/Runner/GameScene.cpp @@ -0,0 +1,69 @@ +#include +#include +#include "Runner.hpp" +#include +#include "Component/Music/MusicComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Animator/AnimatorComponent.hpp" +#include "Component/Animation/AnimationsComponent.hpp" +#include "Component/Health/HealthComponent.hpp" +#include "Component/Renderer/CameraComponent.hpp" +#include "Component/Collision/CollisionComponent.hpp" +#include "Component/Movable/MovableComponent.hpp" +#include "Component/BombHolder/BombHolderComponent.hpp" +#include "Component/Bonus/PlayerBonusComponent.hpp" +#include "Component/Shaders/ShaderComponent.hpp" +#include "Component/Tag/TagComponent.hpp" +#include "Component/Renderer/Drawable3DComponent.hpp" +#include "Component/Button/ButtonComponent.hpp" +#include "Drawables/2D/Text.hpp" +#include "Model/Model.hpp" +#include "Map/Map.hpp" + +namespace RAY3D = RAY::Drawables::Drawables3D; + +namespace BBM +{ + std::shared_ptr Runner::loadGameScene() + { + auto scene = std::make_shared(); + scene->addEntity("control") + .addComponent() + .addComponent(); + std::map soundPath ={ + {SoundComponent::JUMP, "assets/sounds/jump.wav"}, + {SoundComponent::MOVE, "assets/sounds/move.ogg"}, + {SoundComponent::BOMB, "assets/sounds/bomb_drop.ogg"}, + //{SoundComponent::DEATH, "assets/sounds/death.ogg"} + }; + scene->addEntity("player") + .addComponent() + .addComponent("assets/player/player.iqm", true, std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) + .addComponent() + .addComponent() + .addComponent() + .addComponent("assets/shaders/glsl330/predator.fs") + .addComponent>() + //.addComponent(0) + .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 3) + .addComponent(BBM::Vector3f{0.25, 0, 0.25}, BBM::Vector3f{.75, 2, .75}) + .addComponent() + .addComponent(soundPath) + .addComponent("assets/musics/music_battle.ogg") + .addComponent() + .addComponent() + .addComponent(1, [](WAL::Entity &entity, WAL::Wal &wal) { + auto &animation = entity.getComponent(); + animation.setAnimIndex(5); + }); + scene->addEntity("camera") + .addComponent(8, 20, 7) + .addComponent(Vector3f(8, 0, 8)); + MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16), scene); + + return scene; + } +} \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 364f90e4..4c18e18f 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -485,46 +485,6 @@ namespace BBM return scene; } - std::shared_ptr Runner::loadGameScene() - { - auto scene = std::make_shared(); - scene->addEntity("control") - .addComponent() - .addComponent(); - std::map soundPath ={ - {SoundComponent::JUMP, "assets/sounds/jump.wav"}, - {SoundComponent::MOVE, "assets/sounds/move.ogg"}, - {SoundComponent::BOMB, "assets/sounds/bomb_drop.ogg"}, - //{SoundComponent::DEATH, "assets/sounds/death.ogg"} - }; - scene->addEntity("player") - .addComponent() - .addComponent("assets/player/player.iqm", true, std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) - .addComponent() - .addComponent() - .addComponent() - .addComponent("assets/shaders/glsl330/predator.fs") - .addComponent>() - //.addComponent(0) - .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 3) - .addComponent(BBM::Vector3f{0.25, 0, 0.25}, BBM::Vector3f{.75, 2, .75}) - .addComponent() - .addComponent(soundPath) - .addComponent("assets/musics/music_battle.ogg") - .addComponent() - .addComponent() - .addComponent(1, [](WAL::Entity &entity, WAL::Wal &wal) { - auto &animation = entity.getComponent(); - animation.setAnimIndex(5); - }); - scene->addEntity("camera") - .addComponent(8, 20, 7) - .addComponent(Vector3f(8, 0, 8)); - MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16), scene); - - return scene; - } - void Runner::loadScenes() { gameState._loadedScenes[GameState::SceneID::MainMenuScene] = loadMainMenuScene(); From 6a9a09652aa00db9cc3530c7b6a3450b6d188ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Mon, 14 Jun 2021 10:51:27 +0200 Subject: [PATCH 51/82] more indent fixes --- sources/System/BombHolder/BombHolderSystem.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index db3c5c55..7aca6a9a 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -48,8 +48,10 @@ namespace BBM explosion.scheduleDeletion(); }) .addComponent("assets/bombs/explosion/explosion.glb", false, - std::make_pair(MAP_DIFFUSE, - "assets/bombs/explosion/blast.png")); + std::make_pair( + MAP_DIFFUSE, + "assets/bombs/explosion/blast.png" + )); wal.getSystem().dispatchEvent([position, radiusToDo, expansionDirections](WAL::Wal &wal) { for (auto &[entity, pos, _] : wal.getScene()->view>()) { if (pos.position.round() == position) { @@ -91,8 +93,10 @@ namespace BBM WAL::Callback(), &BombHolderSystem::_bombCollide, 0.25, .75) .addComponent("assets/bombs/bomb.obj", false, - std::make_pair(MAP_DIFFUSE, - "assets/bombs/bomb_normal.png")); + std::make_pair( + MAP_DIFFUSE, + "assets/bombs/bomb_normal.png" + )); holder.damage = 1; holder.explosionRadius = 3; } From d3f77835d34e9b611ad77faaccef7d3403f18e7b Mon Sep 17 00:00:00 2001 From: Askou Date: Mon, 14 Jun 2021 10:51:49 +0200 Subject: [PATCH 52/82] fix cmake not compiling because of git merge --- .../System/BombHolder/BombHolderSystem.cpp | 28 ++++++------------- .../System/BombHolder/BombHolderSystem.hpp | 9 ++---- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 1cae7500..d91c2a27 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -31,13 +31,14 @@ namespace BBM return MapGenerator::wallCollided( entity, bomb, collidedAxis); } + BombHolderSystem::BombHolderSystem(WAL::Wal &wal) : System(wal) {} - void BombHolderSystem::_dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, const Vector3f &posFrom) + void BombHolderSystem::_dispatchExplosion(Vector3f position, WAL::Wal &wal, int count) { - if (radiusToDo <= 0) + if (count <= 0) return; wal.getScene()->scheduleNewEntity("explosion") .addComponent(position) @@ -54,23 +55,10 @@ namespace BBM return; } } - const Vector3f expandVectors[] = { - {1, 0, 0}, - {-1, 0, 0}, - {0, 0, 1}, - {0, 0, -1}, - }; - - // should be true only at the first iteration - bool alwaysDispatch = position == posFrom; - - for (const auto &expandVector : expandVectors) { - Vector3f newPos = position + expandVector; - if (!alwaysDispatch && newPos == posFrom) { - continue; - } - _dispatchExplosion(newPos, wal, radiusToDo - 1, position); - } + _dispatchExplosion(position + Vector3f(1, 0, 0), wal, count - 1); + _dispatchExplosion(position + Vector3f(-1, 0, 0), wal, count - 1); + _dispatchExplosion(position + Vector3f(0, 0, 1), wal, count - 1); + _dispatchExplosion(position + Vector3f(0, 0, -1), wal, count - 1); }); } @@ -79,7 +67,7 @@ namespace BBM bomb.scheduleDeletion(); auto position = bomb.getComponent().position.round(); auto explosionRadius = bomb.getComponent().explosionRadius; - _dispatchExplosion(position, wal, explosionRadius); + _dispatchExplosion(position, wal, 3 + (explosionRadius - 3)); } void BombHolderSystem::_spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id) diff --git a/sources/System/BombHolder/BombHolderSystem.hpp b/sources/System/BombHolder/BombHolderSystem.hpp index 6c872ca8..6d26435e 100644 --- a/sources/System/BombHolder/BombHolderSystem.hpp +++ b/sources/System/BombHolder/BombHolderSystem.hpp @@ -22,12 +22,7 @@ namespace BBM void _spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id); //! @brief Spawn a bomb at the specified position. - static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo, const Vector3f &posFrom); - - //! @brief Wrapped call to specify default arg value - inline static void _dispatchExplosion(const Vector3f &position, WAL::Wal &wal, int radiusToDo) { - return _dispatchExplosion(position, wal, radiusToDo, position); - }; + static void _dispatchExplosion(Vector3f position, WAL::Wal &, int count); //! @brief The method triggered when the bomb explode. static void _bombExplosion(WAL::Entity &bomb, WAL::Wal &); @@ -51,4 +46,4 @@ namespace BBM //! @brief A bomb holder system is not assignable. BombHolderSystem &operator=(const BombHolderSystem &) = delete; }; -} +} \ No newline at end of file From 73ee44d7088f76dd0c97deedf64e2aa1e90dc970 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Mon, 14 Jun 2021 11:04:52 +0200 Subject: [PATCH 53/82] split runner file: remove unnecessary includes --- CMakeLists.txt | 3 + sources/Runner/MainMenuScene.cpp | 119 ++++++++ sources/Runner/PauseMenuScene.cpp | 101 +++++++ sources/Runner/Runner.cpp | 393 --------------------------- sources/Runner/SettingsMenuScene.cpp | 212 +++++++++++++++ 5 files changed, 435 insertions(+), 393 deletions(-) create mode 100644 sources/Runner/MainMenuScene.cpp create mode 100644 sources/Runner/PauseMenuScene.cpp create mode 100644 sources/Runner/SettingsMenuScene.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 96e41a30..6fda39a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,7 +117,10 @@ set(SOURCES sources/System/IntroAnimation/IntroAnimationSystem.cpp sources/Runner/SplashScreenScene.cpp sources/Runner/TitleScreenScene.cpp + sources/Runner/MainMenuScene.cpp sources/Runner/GameScene.cpp + sources/Runner/PauseMenuScene.cpp + sources/Runner/SettingsMenuScene.cpp sources/Runner/CreditScene.cpp ) add_executable(bomberman diff --git a/sources/Runner/MainMenuScene.cpp b/sources/Runner/MainMenuScene.cpp new file mode 100644 index 00000000..3a515c1e --- /dev/null +++ b/sources/Runner/MainMenuScene.cpp @@ -0,0 +1,119 @@ + +#include +#include +#include "Runner.hpp" +#include +#include "Component/Music/MusicComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Button/ButtonComponent.hpp" +#include "Drawables/2D/Text.hpp" + +namespace RAY2D = RAY::Drawables::Drawables2D; + +namespace BBM +{ + std::shared_ptr Runner::loadMainMenuScene() + { + static const std::map sounds = { + {SoundComponent::JUMP, "assets/sounds/click.ogg"} + }; + auto scene = std::make_shared(); + + scene->addEntity("Control entity") + .addComponent() + .addComponent() + .addComponent("assets/musics/music_title.ogg") + .addComponent(sounds); + scene->addEntity("background") + .addComponent() + .addComponent("assets/plain_menu_background.png"); + scene->addEntity("logo") + .addComponent(1920 / 3, 180, 0) + .addComponent("assets/logo_small.png"); + auto &play = scene->addEntity("play button") + .addComponent(1920 / 2.5, 1080 - 540, 0) + .addComponent("assets/buttons/button_new_game.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_new_game.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_new_game_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::GameScene; + }); + auto &settings = scene->addEntity("settings button") + .addComponent(1920 / 2.5, 1080 - 360, 0) + .addComponent("assets/buttons/button_settings.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_settings.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_settings_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::SettingsScene; + }); + auto &exit = scene->addEntity("exit button") + .addComponent(1920 / 2.5, 1080 - 180, 0) + .addComponent("assets/buttons/button_exit.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_exit.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_exit_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + wal.shouldClose = true; + }); + auto &credits = scene->addEntity("credit button") + .addComponent(1920 - 100, 1080 - 30, 0) + .addComponent("Credits", 20, RAY::Vector2(), BLACK) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + text->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + text->setColor(ORANGE); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + gameState.nextScene = BBM::GameState::SceneID::CreditScene; + }); + play.getComponent().setButtonLinks(nullptr, &settings); + settings.getComponent().setButtonLinks(&play, &exit); + exit.getComponent().setButtonLinks(&settings, &credits, nullptr, &credits); + credits.getComponent().setButtonLinks(&exit, nullptr, &exit); + return scene; + } +} \ No newline at end of file diff --git a/sources/Runner/PauseMenuScene.cpp b/sources/Runner/PauseMenuScene.cpp new file mode 100644 index 00000000..ed674e3a --- /dev/null +++ b/sources/Runner/PauseMenuScene.cpp @@ -0,0 +1,101 @@ + +#include +#include +#include "Runner.hpp" +#include +#include "Component/Music/MusicComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Button/ButtonComponent.hpp" +#include "Drawables/2D/Text.hpp" + +namespace RAY2D = RAY::Drawables::Drawables2D; + +namespace BBM +{ + std::shared_ptr Runner::loadPauseMenuScene() + { + static const std::map sounds = { + {SoundComponent::JUMP, "assets/sounds/click.ogg"} + }; + auto scene = std::make_shared(); + + scene->addEntity("Control entity") + .addComponent() + .addComponent() + .addComponent("assets/musics/music_player_select.ogg") + .addComponent(sounds); + scene->addEntity("background") + .addComponent() + .addComponent("assets/plain_menu_background.png"); + scene->addEntity("pause text") + .addComponent(1920 / 2.5, 180, 0) + .addComponent("PAUSE", 120, RAY::Vector2(), ORANGE); + auto &play = scene->addEntity("play button") + .addComponent(1920 / 6.5, 1080 - 360, 0) + .addComponent("assets/buttons/button_back.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::GameScene; + }); + auto &settings = scene->addEntity("settings button") + .addComponent(1920 / 2.5, 1080 - 360, 0) + .addComponent("assets/buttons/button_settings.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_settings.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_settings_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::SettingsScene; + }); + auto &exit = scene->addEntity("exit button") + .addComponent(1920 / 1.5, 1080 - 360, 0) + .addComponent("assets/buttons/button_exit.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_exit.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_exit_hovered.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; + }); + //needed material + //music + play.getComponent().setButtonLinks(nullptr, nullptr, nullptr, &settings); + settings.getComponent().setButtonLinks(nullptr, nullptr, &play, &exit); + exit.getComponent().setButtonLinks(nullptr, nullptr, &settings, nullptr); + return scene; + } +} \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 4c18e18f..97a92ea9 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -11,16 +11,8 @@ #include #include "System/Keyboard/KeyboardSystem.hpp" #include "System/Controllable/ControllableSystem.hpp" -#include "Component/Movable/MovableComponent.hpp" -#include "Component/Controllable/ControllableComponent.hpp" -#include "Component/Keyboard/KeyboardComponent.hpp" #include "System/Gamepad/GamepadSystem.hpp" #include -#include "Component/Button/ButtonComponent.hpp" -#include -#include "Component/Renderer/CameraComponent.hpp" -#include "Component/Renderer/Drawable3DComponent.hpp" -#include "Component/Renderer/Drawable2DComponent.hpp" #include "Runner.hpp" #include "Models/GameState.hpp" #include @@ -29,22 +21,14 @@ #include #include #include -#include -#include #include #include #include -#include -#include -#include "Component/Animation/AnimationsComponent.hpp" #include "System/Animation/AnimationsSystem.hpp" -#include "Component/Shaders/ShaderComponent.hpp" #include "Map/Map.hpp" #include "System/MenuControllable/MenuControllableSystem.hpp" #include #include -#include "Component/Music/MusicComponent.hpp" -#include "Component/Sound/SoundComponent.hpp" #include "System/Sound/PlayerSoundManagerSystem.hpp" #include "System/Sound/MenuSoundManagerSystem.hpp" #include "System/Music/MusicSystem.hpp" @@ -108,383 +92,6 @@ namespace BBM .addSystem(window); } - std::shared_ptr Runner::loadMainMenuScene() - { - static const std::map sounds = { - {SoundComponent::JUMP, "assets/sounds/click.ogg"} - }; - auto scene = std::make_shared(); - - scene->addEntity("Control entity") - .addComponent() - .addComponent() - .addComponent("assets/musics/music_title.ogg") - .addComponent(sounds); - scene->addEntity("background") - .addComponent() - .addComponent("assets/plain_menu_background.png"); - scene->addEntity("logo") - .addComponent(1920 / 3, 180, 0) - .addComponent("assets/logo_small.png"); - auto &play = scene->addEntity("play button") - .addComponent(1920 / 2.5, 1080 - 540, 0) - .addComponent("assets/buttons/button_new_game.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_new_game.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_new_game_hovered.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - gameState.nextScene = BBM::GameState::SceneID::GameScene; - }); - auto &settings = scene->addEntity("settings button") - .addComponent(1920 / 2.5, 1080 - 360, 0) - .addComponent("assets/buttons/button_settings.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_settings.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_settings_hovered.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - gameState.nextScene = BBM::GameState::SceneID::SettingsScene; - }); - auto &exit = scene->addEntity("exit button") - .addComponent(1920 / 2.5, 1080 - 180, 0) - .addComponent("assets/buttons/button_exit.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_exit.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_exit_hovered.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &wal) - { - wal.shouldClose = true; - }); - auto &credits = scene->addEntity("credit button") - .addComponent(1920 - 100, 1080 - 30, 0) - .addComponent("Credits", 20, RAY::Vector2(), BLACK) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); - - text->setColor(BLACK); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); - - text->setColor(ORANGE); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &wal) - { - gameState.nextScene = BBM::GameState::SceneID::CreditScene; - }); - play.getComponent().setButtonLinks(nullptr, &settings); - settings.getComponent().setButtonLinks(&play, &exit); - exit.getComponent().setButtonLinks(&settings, &credits, nullptr, &credits); - credits.getComponent().setButtonLinks(&exit, nullptr, &exit); - return scene; - } - - std::shared_ptr Runner::loadPauseMenuScene() - { - static const std::map sounds = { - {SoundComponent::JUMP, "assets/sounds/click.ogg"} - }; - auto scene = std::make_shared(); - - scene->addEntity("Control entity") - .addComponent() - .addComponent() - .addComponent("assets/musics/music_player_select.ogg") - .addComponent(sounds); - scene->addEntity("background") - .addComponent() - .addComponent("assets/plain_menu_background.png"); - scene->addEntity("pause text") - .addComponent(1920 / 2.5, 180, 0) - .addComponent("PAUSE", 120, RAY::Vector2(), ORANGE); - auto &play = scene->addEntity("play button") - .addComponent(1920 / 6.5, 1080 - 360, 0) - .addComponent("assets/buttons/button_back.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_back.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_back_hovered.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - gameState.nextScene = BBM::GameState::SceneID::GameScene; - }); - auto &settings = scene->addEntity("settings button") - .addComponent(1920 / 2.5, 1080 - 360, 0) - .addComponent("assets/buttons/button_settings.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_settings.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_settings_hovered.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - gameState.nextScene = BBM::GameState::SceneID::SettingsScene; - }); - auto &exit = scene->addEntity("exit button") - .addComponent(1920 / 1.5, 1080 - 360, 0) - .addComponent("assets/buttons/button_exit.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_exit.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_exit_hovered.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &wal) - { - gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; - }); - //needed material - //music - play.getComponent().setButtonLinks(nullptr, nullptr, nullptr, &settings); - settings.getComponent().setButtonLinks(nullptr, nullptr, &play, &exit); - exit.getComponent().setButtonLinks(nullptr, nullptr, &settings, nullptr); - return scene; - } - - std::shared_ptr Runner::loadSettingsMenuScene() - { - auto scene = std::make_shared(); - static const std::map sounds = { - {SoundComponent::JUMP, "assets/sounds/click.ogg"} - }; - - scene->addEntity("Control entity") - .addComponent() - .addComponent() - .addComponent("assets/musics/music_title.ogg") - .addComponent(sounds); - scene->addEntity("background") - .addComponent() - .addComponent("assets/plain_menu_background.png"); - scene->addEntity("logo") - .addComponent(1920 / 3, 180, 0) - .addComponent("assets/logo_small.png"); - auto &music = scene->addEntity("music text") - .addComponent(1920 / 2.5, 1080 - 540, 0) - .addComponent("Music Volume", 70, RAY::Vector2(), BLACK) - .addComponent() - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(BLACK); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(ORANGE); - }); - - auto &musicUp = scene->addEntity("music up button") - .addComponent(1920 / 1.5, 1080 - 540, 0) - .addComponent("assets/buttons/button_plus.png") - .addComponent("assets/musics/music_title.ogg") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_plus.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - auto &component = entity.getComponent(); - - component.turnUpVolume(); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_plus_hovered.png"); - }); - - auto &musicDown = scene->addEntity("music down button") - .addComponent(1920 / 3, 1080 - 540, 0) - .addComponent("assets/buttons/button_minus.png") - .addComponent("assets/musics/music_title.ogg") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_minus.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - auto &component = entity.getComponent(); - - component.turnDownVolume(); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_minus_hovered.png"); - }); - - auto &sound = scene->addEntity("sound text") - .addComponent(1920 / 2.5, 1080 - 360, 0) - .addComponent("Sound Volume", 70, RAY::Vector2(), BLACK) - .addComponent() - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(BLACK); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(ORANGE); - }); - - auto &soundUp = scene->addEntity("sound up button") - .addComponent(1920 / 1.5, 1080 - 360, 0) - .addComponent("assets/buttons/button_plus.png") - .addComponent(sounds) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - auto &component = entity.getComponent(); - - component.turnUpVolume(); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_plus.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_plus_hovered.png"); - }); - - auto &soundDown = scene->addEntity("sound down button") - .addComponent(1920 / 3, 1080 - 360, 0) - .addComponent("assets/buttons/button_minus.png") - .addComponent(sounds) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_minus.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - auto &component = entity.getComponent(); - - component.turnDownVolume(); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_minus_hovered.png"); - }); - - auto &debug = scene->addEntity("debug text") - .addComponent(1920 / 2.5, 1080 - 180, 0) - .addComponent("Debug Mode: Off", 70, RAY::Vector2(), BLACK) - .addComponent([](WAL::Entity &entity, WAL::Wal &wal) - { - RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); - - if (text->getString().find("Off") != std::string::npos) { - text->setText("Debug Mode: On"); - wal.getSystem().setDebug(true); - } else { - text->setText("Debug Mode: Off"); - wal.getSystem().setDebug(false); - } - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(BLACK); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - entity.getComponent().drawable->setColor(ORANGE); - }); - auto &back = scene->addEntity("back to menu") - .addComponent(10, 1080 - 85, 0) - .addComponent("assets/buttons/button_back.png") - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_back.png"); - }) - .addComponent([](WAL::Entity &entity, WAL::Wal &) - { - RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); - - texture->use("assets/buttons/button_back_hovered.png"); - }); - //needed material - //music - //sound - - music.getComponent().setButtonLinks(nullptr, &sound, &musicDown, &musicUp); - musicDown.getComponent().setButtonLinks(&debug, &sound, nullptr, &music); - musicUp.getComponent().setButtonLinks(&debug, &sound, &music); - sound.getComponent().setButtonLinks(&music, &debug, &soundDown, &soundUp); - soundDown.getComponent().setButtonLinks(&music, &debug, nullptr, &sound); - soundUp.getComponent().setButtonLinks(&music, &debug, &sound); - debug.getComponent().setButtonLinks(&sound, &back, &back); - back.getComponent().setButtonLinks(&debug, nullptr, nullptr, &debug); - return scene; - } - void Runner::loadScenes() { gameState._loadedScenes[GameState::SceneID::MainMenuScene] = loadMainMenuScene(); diff --git a/sources/Runner/SettingsMenuScene.cpp b/sources/Runner/SettingsMenuScene.cpp new file mode 100644 index 00000000..4d409aab --- /dev/null +++ b/sources/Runner/SettingsMenuScene.cpp @@ -0,0 +1,212 @@ + +#include +#include +#include "Runner.hpp" +#include +#include "Component/Music/MusicComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Button/ButtonComponent.hpp" +#include "Drawables/2D/Text.hpp" +#include "System/Renderer/RenderSystem.hpp" + +namespace RAY2D = RAY::Drawables::Drawables2D; + +namespace BBM +{ + std::shared_ptr Runner::loadSettingsMenuScene() + { + auto scene = std::make_shared(); + static const std::map sounds = { + {SoundComponent::JUMP, "assets/sounds/click.ogg"} + }; + + scene->addEntity("Control entity") + .addComponent() + .addComponent() + .addComponent("assets/musics/music_title.ogg") + .addComponent(sounds); + scene->addEntity("background") + .addComponent() + .addComponent("assets/plain_menu_background.png"); + scene->addEntity("logo") + .addComponent(1920 / 3, 180, 0) + .addComponent("assets/logo_small.png"); + auto &music = scene->addEntity("music text") + .addComponent(1920 / 2.5, 1080 - 540, 0) + .addComponent("Music Volume", 70, RAY::Vector2(), BLACK) + .addComponent() + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(ORANGE); + }); + + auto &musicUp = scene->addEntity("music up button") + .addComponent(1920 / 1.5, 1080 - 540, 0) + .addComponent("assets/buttons/button_plus.png") + .addComponent("assets/musics/music_title.ogg") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_plus.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + auto &component = entity.getComponent(); + + component.turnUpVolume(); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_plus_hovered.png"); + }); + + auto &musicDown = scene->addEntity("music down button") + .addComponent(1920 / 3, 1080 - 540, 0) + .addComponent("assets/buttons/button_minus.png") + .addComponent("assets/musics/music_title.ogg") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_minus.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + auto &component = entity.getComponent(); + + component.turnDownVolume(); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_minus_hovered.png"); + }); + + auto &sound = scene->addEntity("sound text") + .addComponent(1920 / 2.5, 1080 - 360, 0) + .addComponent("Sound Volume", 70, RAY::Vector2(), BLACK) + .addComponent() + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(ORANGE); + }); + + auto &soundUp = scene->addEntity("sound up button") + .addComponent(1920 / 1.5, 1080 - 360, 0) + .addComponent("assets/buttons/button_plus.png") + .addComponent(sounds) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + auto &component = entity.getComponent(); + + component.turnUpVolume(); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_plus.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_plus_hovered.png"); + }); + + auto &soundDown = scene->addEntity("sound down button") + .addComponent(1920 / 3, 1080 - 360, 0) + .addComponent("assets/buttons/button_minus.png") + .addComponent(sounds) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_minus.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + auto &component = entity.getComponent(); + + component.turnDownVolume(); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_minus_hovered.png"); + }); + + auto &debug = scene->addEntity("debug text") + .addComponent(1920 / 2.5, 1080 - 180, 0) + .addComponent("Debug Mode: Off", 70, RAY::Vector2(), BLACK) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + if (text->getString().find("Off") != std::string::npos) { + text->setText("Debug Mode: On"); + wal.getSystem().setDebug(true); + } else { + text->setText("Debug Mode: Off"); + wal.getSystem().setDebug(false); + } + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(ORANGE); + }); + auto &back = scene->addEntity("back to menu") + .addComponent(10, 1080 - 85, 0) + .addComponent("assets/buttons/button_back.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back_hovered.png"); + }); + //needed material + //music + //sound + + music.getComponent().setButtonLinks(nullptr, &sound, &musicDown, &musicUp); + musicDown.getComponent().setButtonLinks(&debug, &sound, nullptr, &music); + musicUp.getComponent().setButtonLinks(&debug, &sound, &music); + sound.getComponent().setButtonLinks(&music, &debug, &soundDown, &soundUp); + soundDown.getComponent().setButtonLinks(&music, &debug, nullptr, &sound); + soundUp.getComponent().setButtonLinks(&music, &debug, &sound); + debug.getComponent().setButtonLinks(&sound, &back, &back); + back.getComponent().setButtonLinks(&debug, nullptr, nullptr, &debug); + return scene; + } +} \ No newline at end of file From 993aadcf6c82b9399348eb3c9d0c4bdb0c0e10c7 Mon Sep 17 00:00:00 2001 From: Askou Date: Mon, 14 Jun 2021 11:27:49 +0200 Subject: [PATCH 54/82] put classic mode --- sources/Runner/Runner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 687fcc1d..f8a44bb4 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -551,7 +551,7 @@ namespace BBM scene->addEntity("camera") .addComponent(8, 25, 7) .addComponent(Vector3f(8, 0, 8)); - MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16, false, true), scene); + MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16, false, false), scene); return scene; } From 669c17ae24cfa998b2e72db1087fe6fbef352172 Mon Sep 17 00:00:00 2001 From: Askou Date: Mon, 14 Jun 2021 11:38:06 +0200 Subject: [PATCH 55/82] fix comment --- sources/Component/BumperTimer/BumperTimerComponent.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/Component/BumperTimer/BumperTimerComponent.hpp b/sources/Component/BumperTimer/BumperTimerComponent.hpp index dbeba275..a0b8c958 100644 --- a/sources/Component/BumperTimer/BumperTimerComponent.hpp +++ b/sources/Component/BumperTimer/BumperTimerComponent.hpp @@ -18,9 +18,9 @@ namespace BBM bool _isReseting = false; - //! @brief The number of seconds of each refill. This variable is used to reset the nextBombRefill value. + //! @brief The number of seconds of each rest. This variable is used to reset the nextReset value. std::chrono::nanoseconds resetRate = 1500ms; - //! @brief The number of nanosecond before the next bomb refill. + //! @brief The number of nanosecond before the next bumper reset for the player. std::chrono::nanoseconds nextReset = resetRate; //! @inherit From a42ca685953dc596b1571fd0ecfdbdfd40af088d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 14 Jun 2021 11:39:00 +0200 Subject: [PATCH 56/82] Fixing play button and menu handling --- lib/wal/sources/Scene/Scene.hpp | 5 +-- sources/Runner/Runner.cpp | 38 ++++--------------- sources/System/Lobby/LobbySystem.cpp | 38 +++++++++++++++++-- sources/System/Lobby/LobbySystem.hpp | 7 ++++ .../MenuControllableSystem.cpp | 5 +-- .../MenuControllableSystem.hpp | 4 +- 6 files changed, 55 insertions(+), 42 deletions(-) diff --git a/lib/wal/sources/Scene/Scene.hpp b/lib/wal/sources/Scene/Scene.hpp index e0aad880..dd786d73 100644 --- a/lib/wal/sources/Scene/Scene.hpp +++ b/lib/wal/sources/Scene/Scene.hpp @@ -74,13 +74,12 @@ namespace WAL //! @brief A default constructor Scene() = default; - //! @brief A scene is copy constructable - Scene(const Scene &) = default; + //! @brief A scene is not copy constructable + Scene(const Scene &) = delete; //! @brief A default destructor ~Scene() = default; //! @brief A scene is assignable Scene &operator=(const Scene &); - Scene(Scene &&) = default; friend Entity; }; diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 8933ec03..d32f0994 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -7,12 +7,8 @@ #include "System/Movable/MovableSystem.hpp" #include "System/Renderer/RenderSystem.hpp" #include -#include #include #include -#include