merge develop
5
.gitignore
vendored
@@ -7,4 +7,7 @@ build/*
|
||||
docs/*
|
||||
emsdk/
|
||||
build_web/*
|
||||
wasm-python.py
|
||||
wasm-python.py
|
||||
lua54*
|
||||
include/*
|
||||
save/*
|
||||
@@ -122,10 +122,18 @@ set(SOURCES
|
||||
sources/System/Sound/PlayerSoundManagerSystem.hpp
|
||||
sources/System/Music/MusicSystem.hpp
|
||||
sources/System/Music/MusicSystem.cpp
|
||||
sources/Parser/ParserYaml.hpp
|
||||
sources/Parser/ParserYaml.cpp
|
||||
sources/Exception/Error.hpp
|
||||
sources/Exception/Error.cpp
|
||||
sources/System/Lobby/LobbySystem.cpp
|
||||
sources/System/Lobby/LobbySystem.hpp
|
||||
sources/Component/Lobby/LobbyComponent.cpp
|
||||
sources/Component/Lobby/LobbyComponent.hpp
|
||||
sources/System/Lobby/ResumeLobbySystem.cpp
|
||||
sources/System/Lobby/ResumeLobbySystem.hpp
|
||||
sources/Component/Lobby/ResumeLobbyComponent.cpp
|
||||
sources/Component/Lobby/ResumeLobbyComponent.hpp
|
||||
sources/Component/Gravity/GravityComponent.hpp
|
||||
sources/Component/Gravity/GravityComponent.cpp
|
||||
sources/System/Gravity/GravitySystem.hpp
|
||||
@@ -156,6 +164,12 @@ set(SOURCES
|
||||
sources/System/EndCondition/EndConditionSystem.hpp
|
||||
sources/System/EndCondition/EndConditionSystem.cpp
|
||||
sources/Runner/LobbyScene.cpp
|
||||
sources/Runner/ResumeLobbyScene.cpp
|
||||
sources/Runner/ScoreScene.cpp
|
||||
sources/Parser/Node.cpp
|
||||
sources/Parser/Node.hpp
|
||||
sources/Utils/Utils.cpp
|
||||
sources/Utils/Utils.hpp
|
||||
sources/Runner/HowToPlayScene.cpp
|
||||
sources/Runner/ScoreScene.cpp
|
||||
sources/System/Shaders/ShaderSystem.cpp
|
||||
@@ -180,6 +194,8 @@ set(SOURCES
|
||||
sources/Map/LuaMap.hpp
|
||||
sources/Component/Shaders/Items/AlphaCtxShaderComponent.cpp
|
||||
sources/Component/Shaders/Items/AlphaCtxShaderComponent.hpp
|
||||
sources/Component/Speed/SpeedComponent.cpp
|
||||
sources/Component/Speed/SpeedComponent.hpp
|
||||
)
|
||||
|
||||
add_executable(bomberman
|
||||
|
||||
20
README.md
@@ -8,14 +8,17 @@ A recreation of the classic Bomberman arcade game
|
||||
|
||||
Repository link: https://github.com/AnonymusRaccoon/Bomberman/
|
||||
|
||||
## Demo
|
||||
|
||||
Very soon :)
|
||||
## Demo (Click to See on YouTube)
|
||||
|
||||
[](http://www.youtube.com/watch?v=5tkaYtMpdKY "Indie Studio - Bomberman")
|
||||
|
||||
## Screenshots
|
||||
|
||||
Very soon :)
|
||||
<div>
|
||||
<img align="left" src="./assets/images/titlescreen.png" width="45%">
|
||||
<img align="right" src="./assets/images/lobby.png" width="45%">
|
||||
<img src="./assets/images/game.png">
|
||||
</div>
|
||||
|
||||
|
||||
## Run (compile from the sources)
|
||||
@@ -56,14 +59,7 @@ Enjoy !
|
||||
|
||||
## Tech Stack
|
||||
|
||||
**Bomberman:** C++20, raylib, Catch2, CMake, Doxygen
|
||||
## Contributing
|
||||
|
||||
Contributions are always welcome!
|
||||
|
||||
See `contributing.md` for ways to get started.
|
||||
|
||||
Please adhere to this project's `code of conduct`.
|
||||
**Bomberman:** C++20, raylib, Catch2, CMake, Doxygen, Lua
|
||||
|
||||
|
||||
## Authors
|
||||
|
||||
@@ -9,7 +9,7 @@ mapinfo.dist { }
|
||||
------------
|
||||
|
||||
------ Debug variables
|
||||
local debug = true
|
||||
local debug = false
|
||||
|
||||
if not debug then
|
||||
log = function() end
|
||||
|
||||
BIN
assets/buttons/button_resume_game.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/buttons/button_resume_game_hovered.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
assets/buttons/button_save.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
assets/buttons/button_save_hovered.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/images/game.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/images/lobby.png
Normal file
|
After Width: | Height: | Size: 941 KiB |
BIN
assets/images/titlescreen.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
images/game.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
images/lobby.png
Normal file
|
After Width: | Height: | Size: 941 KiB |
BIN
images/titlescreen.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
@@ -31,4 +31,4 @@ RAY::Vector3::operator ::Vector3() const
|
||||
v.y = this->y;
|
||||
v.z = this->z;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace WAL
|
||||
return this->_name;
|
||||
}
|
||||
|
||||
void Entity::setName(std::string &name)
|
||||
{
|
||||
this->_name = name;
|
||||
}
|
||||
|
||||
bool Entity::isDisable() const
|
||||
{
|
||||
return this->_disabled;
|
||||
|
||||
@@ -51,8 +51,10 @@ namespace WAL
|
||||
Scene &_scene;
|
||||
//! @brief Get the ID of the entity.
|
||||
unsigned getUid() const;
|
||||
//! @brief Get the name fo the entity
|
||||
//! @brief Get the name of the entity
|
||||
std::string getName() const;
|
||||
//!@brief Set the name of the entity
|
||||
void setName(std::string &name);
|
||||
|
||||
//! @brief Used if the entity is disabled
|
||||
bool isDisable() const;
|
||||
|
||||
@@ -12,9 +12,10 @@ namespace BBM
|
||||
: WAL::Component(entity)
|
||||
{}
|
||||
|
||||
BombHolderComponent::BombHolderComponent(WAL::Entity &entity, unsigned int maxCount)
|
||||
BombHolderComponent::BombHolderComponent(WAL::Entity &entity, unsigned int maxCount, unsigned int bombExplosionRadius)
|
||||
: WAL::Component(entity),
|
||||
maxBombCount(maxCount)
|
||||
maxBombCount(maxCount),
|
||||
explosionRadius(bombExplosionRadius)
|
||||
{}
|
||||
|
||||
WAL::Component *BombHolderComponent::clone(WAL::Entity &entity) const
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace BBM
|
||||
//! @brief The number of nanosecond before the next bomb refill.
|
||||
std::chrono::nanoseconds nextBombRefill = refillRate;
|
||||
//! @brief The radius of the explosion.
|
||||
float explosionRadius = 3;
|
||||
unsigned int explosionRadius = 3;
|
||||
//! @brief The damage made by the explosion on an entity
|
||||
int damage = 1;
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace BBM
|
||||
explicit BombHolderComponent(WAL::Entity &entity);
|
||||
|
||||
//! @brief Constructor
|
||||
BombHolderComponent(WAL::Entity &entity, unsigned int maxBombCount);
|
||||
BombHolderComponent(WAL::Entity &entity, unsigned int maxBombCount, unsigned int bombExplosionRadius = 3);
|
||||
|
||||
//! @brief A component can't be instantiated, it should be derived.
|
||||
BombHolderComponent(const BombHolderComponent &) = default;
|
||||
|
||||
@@ -40,8 +40,6 @@ namespace BBM
|
||||
bool bomb = false;
|
||||
//! @brief input value for pause
|
||||
bool pause = false;
|
||||
//! @brief The speed applied to every controllable entities.
|
||||
float speed = .15f;
|
||||
//! @brief The layout used for this controllable.
|
||||
Layout layout = NONE;
|
||||
//! @brief True if buttons should be triggered every frame where the key is down, false if the button should only be triggered once the key is released.
|
||||
|
||||
21
sources/Component/Lobby/ResumeLobbyComponent.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by hbenjamin on 6/18/21.
|
||||
//
|
||||
|
||||
#include "ResumeLobbyComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
ResumeLobbyComponent::ResumeLobbyComponent(WAL::Entity &entity, int playerNumber, WAL::Entity &button, WAL::Entity &tile, int pColor)
|
||||
: WAL::Component(entity),
|
||||
playerID(playerNumber),
|
||||
playerColor(pColor),
|
||||
readyButton(button),
|
||||
coloredTile(tile)
|
||||
{}
|
||||
|
||||
WAL::Component *ResumeLobbyComponent::clone(WAL::Entity &entity) const
|
||||
{
|
||||
return new ResumeLobbyComponent(entity, this->playerID, this->readyButton, this->coloredTile, this->playerColor);
|
||||
}
|
||||
}
|
||||
44
sources/Component/Lobby/ResumeLobbyComponent.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Created by hbenjamin on 6/18/21.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Component/Component.hpp>
|
||||
#include <Entity/Entity.hpp>
|
||||
#include <Color.hpp>
|
||||
#include <Component/Controllable/ControllableComponent.hpp>
|
||||
#include <chrono>
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
class ResumeLobbyComponent : 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 (as an index)
|
||||
int playerColor;
|
||||
//! @brief Is this player ready
|
||||
bool ready = false;
|
||||
//! @brief The entity containing the ready display.
|
||||
WAL::Entity &readyButton;
|
||||
//! @brief The colored rectangle behind the player.
|
||||
WAL::Entity &coloredTile;
|
||||
//! @brief The time of last input that this lobby player has made.
|
||||
std::chrono::time_point<std::chrono::steady_clock> lastInput;
|
||||
|
||||
Component *clone(WAL::Entity &entity) const override;
|
||||
|
||||
//! @brief Create a new lobby component.
|
||||
explicit ResumeLobbyComponent(WAL::Entity &entity, int playerNumber, WAL::Entity &button, WAL::Entity &tile, int pColor);
|
||||
//! @brief A lobby component is copyable.
|
||||
ResumeLobbyComponent(const ResumeLobbyComponent &) = default;
|
||||
//! @brief A default destructor
|
||||
~ResumeLobbyComponent() override = default;
|
||||
//! @brief A lobby component is not assignable.
|
||||
ResumeLobbyComponent &operator=(const ResumeLobbyComponent &) = delete;
|
||||
};
|
||||
}
|
||||
24
sources/Component/Speed/SpeedComponent.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by cbihan on 18/06/2021.
|
||||
//
|
||||
|
||||
#include "SpeedComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
SpeedComponent::SpeedComponent(WAL::Entity &entity) :
|
||||
WAL::Component(entity)
|
||||
{
|
||||
}
|
||||
|
||||
WAL::Component *SpeedComponent::clone(WAL::Entity &entity) const
|
||||
{
|
||||
return new SpeedComponent(this->_entity, this->speed);
|
||||
}
|
||||
|
||||
SpeedComponent::SpeedComponent(WAL::Entity &entity, float entitySpeed) :
|
||||
WAL::Component(entity),
|
||||
speed(entitySpeed)
|
||||
{
|
||||
}
|
||||
}
|
||||
34
sources/Component/Speed/SpeedComponent.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by cbihan on 18/06/2021.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Component/Component.hpp>
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
class SpeedComponent : public WAL::Component
|
||||
{
|
||||
public:
|
||||
//! @brief entity speed
|
||||
float speed = .15f;
|
||||
|
||||
//! @inherit
|
||||
WAL::Component *clone(WAL::Entity &entity) const override;
|
||||
|
||||
//! @brief Initialize a new controllable component.
|
||||
explicit SpeedComponent(WAL::Entity &entity);
|
||||
|
||||
//! @brief Initialize a new controllable component.
|
||||
explicit SpeedComponent(WAL::Entity &entity, float entitySpeed);
|
||||
//! @brief A Controllable component is copy constructable.
|
||||
SpeedComponent(const SpeedComponent &) = default;
|
||||
//! @brief default destructor
|
||||
~SpeedComponent() override = default;
|
||||
//! @brief A Controllable component can't be assigned
|
||||
SpeedComponent &operator=(const SpeedComponent &) = delete;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -61,4 +61,5 @@ namespace BBM
|
||||
constexpr const char Bumper[] = "Bumper";
|
||||
// interact with bombs (getting damage etc) but doesn't stop explosion
|
||||
constexpr const char BlowablePass[] = "BlowablePass";
|
||||
constexpr const char Timer[] = "Timer";
|
||||
}
|
||||
|
||||
16
sources/Exception/Error.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by hbenjamin on 11/06/2021.
|
||||
//
|
||||
|
||||
#include "Error.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
Error::Error(const std::string &what)
|
||||
: std::runtime_error(what)
|
||||
{}
|
||||
|
||||
ParserError::ParserError(const std::string &what)
|
||||
: Error(what)
|
||||
{}
|
||||
} // namespace BBM
|
||||
37
sources/Exception/Error.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by hbenjamin on 11/06/2021.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace BBM {
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
//! @brief Create a new exception
|
||||
explicit Error(const std::string &what);
|
||||
//! @brief An exception is copy constructable
|
||||
Error(const Error &) = default;
|
||||
//! @brief A default destructor
|
||||
~Error() override = default;
|
||||
//! @brief A default assignment operator
|
||||
Error &operator=(const Error &) = default;
|
||||
};
|
||||
|
||||
class ParserError : public Error
|
||||
{
|
||||
public:
|
||||
//! @brief Create a new parser exception
|
||||
explicit ParserError(const std::string &what);
|
||||
//! @brief A parser exception is copy constructable
|
||||
ParserError(const ParserError &) = default;
|
||||
//! @brief A default destructor
|
||||
~ParserError() override = default;
|
||||
//! @brief A default assignment operator
|
||||
ParserError &operator=(const ParserError &) = default;
|
||||
};
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <Component/Collision/CollisionComponent.hpp>
|
||||
#include <Component/Collision/CollisionComponent.hpp>
|
||||
#include <Component/Controllable/ControllableComponent.hpp>
|
||||
#include "Component/Speed/SpeedComponent.hpp"
|
||||
#include <Component/Bonus/PlayerBonusComponent.hpp>
|
||||
#include "Component/Movable/MovableComponent.hpp"
|
||||
#include "Bonus.hpp"
|
||||
@@ -40,13 +41,13 @@ namespace BBM {
|
||||
{
|
||||
if (bonus.shouldDelete() || axis != CollisionComponent::CollidedAxis::ALL)
|
||||
return;
|
||||
auto *controllable = player.tryGetComponent<ControllableComponent>();
|
||||
auto *speed = player.tryGetComponent<SpeedComponent>();
|
||||
auto *playerBonus = player.tryGetComponent<PlayerBonusComponent>();
|
||||
if (!controllable || !playerBonus)
|
||||
if (!speed || !playerBonus)
|
||||
return;
|
||||
if (controllable->speed >= 0.4)
|
||||
if (speed->speed >= 0.4)
|
||||
return;
|
||||
controllable->speed += 0.025f;
|
||||
speed->speed += 0.025f;
|
||||
const_cast<WAL::Entity &>(bonus).scheduleDeletion();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Component/Collision/CollisionComponent.hpp"
|
||||
|
||||
namespace BBM {
|
||||
class Bonus {
|
||||
@@ -15,11 +16,6 @@ namespace BBM {
|
||||
//! @brief Apply bonus effect that allows players to carry one more bomb than before
|
||||
static void BombUpBonus(WAL::Entity &player, const WAL::Entity &bonus, CollisionComponent::CollidedAxis axis);
|
||||
|
||||
//! @param bonus bonus
|
||||
//! @param player the entity on which the effect will be applied
|
||||
//! @brief Apply bonus effect who increased the bomb damage
|
||||
static void DamageIncreasedBonus(WAL::Entity &player, const WAL::Entity &bonus, CollisionComponent::CollidedAxis axis);
|
||||
|
||||
//! @param bonus bonus
|
||||
//! @param player the entity on which the effect will be applied
|
||||
//! @brief Apply bonus effect that expend the explosion range of the bomb
|
||||
|
||||
@@ -19,6 +19,34 @@ using namespace std::chrono_literals;
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
void MapGenerator::createBonus(WAL::Entity &entity, Vector3f position, Bonus::BonusType bonusType) {
|
||||
static std::map<Bonus::BonusType, std::vector<std::string>> map = {
|
||||
{Bonus::BonusType::BOMBSTOCK, {"Bonus Bomb Up", "assets/items/bombup"}},
|
||||
{Bonus::BonusType::SPEEDUP, {"Bonus Speed Up", "assets/items/speedup"}},
|
||||
{Bonus::BonusType::EXPLOSIONINC, {"Bonus Fire Up", "assets/items/fireup"}},
|
||||
{Bonus::BonusType::NOCLIP, {"Bonus Wallpass", "assets/items/wallpass"}}
|
||||
};
|
||||
static std::vector<std::function<void (WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis)>> func = {
|
||||
&Bonus::BombUpBonus, &Bonus::SpeedUpBonus, &Bonus::ExplosionRangeBonus, &Bonus::NoClipBonus
|
||||
};
|
||||
|
||||
entity.addComponent<PositionComponent>(position)
|
||||
.addComponent<TagComponent<Blowable>>()
|
||||
.addComponent<MovableComponent>()
|
||||
.addComponent<HealthComponent>(1, [](WAL::Entity &myEntity, WAL::Wal &wal) {
|
||||
myEntity.scheduleDeletion();
|
||||
})
|
||||
.addComponent<LevitateComponent>(position.y)
|
||||
.addComponent<CollisionComponent>([](WAL::Entity &bonus, const WAL::Entity &player, CollisionComponent::CollidedAxis axis) {
|
||||
bonus.scheduleDeletion();
|
||||
}, func[bonusType - 1], 0.5, .5)
|
||||
.addComponent<TimerComponent>(5s, [](WAL::Entity &bonus, WAL::Wal &wal){
|
||||
bonus.scheduleDeletion();
|
||||
})
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(map.at(bonusType)[1] + ".obj", false,
|
||||
std::make_pair(MAP_DIFFUSE, "assets/items/items.png"));
|
||||
}
|
||||
|
||||
void MapGenerator::bumperCollide(WAL::Entity &entity,
|
||||
const WAL::Entity &wall,
|
||||
CollisionComponent::CollidedAxis collidedAxis)
|
||||
@@ -84,14 +112,11 @@ namespace BBM
|
||||
{
|
||||
entity.scheduleDeletion();
|
||||
auto &position = entity.getComponent<PositionComponent>().position;
|
||||
static std::map<Bonus::BonusType, std::string> map = {
|
||||
{Bonus::BonusType::BOMBSTOCK, "assets/items/bombup"},
|
||||
{Bonus::BonusType::SPEEDUP, "assets/items/speedup"},
|
||||
{Bonus::BonusType::EXPLOSIONINC, "assets/items/fireup"},
|
||||
{Bonus::BonusType::NOCLIP, "assets/items/wallpass"}
|
||||
};
|
||||
static std::vector<std::function<void (WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis)>> func = {
|
||||
&Bonus::BombUpBonus, &Bonus::SpeedUpBonus, &Bonus::ExplosionRangeBonus, &Bonus::NoClipBonus
|
||||
static std::map<Bonus::BonusType, std::vector<std::string>> map = {
|
||||
{Bonus::BonusType::BOMBSTOCK, {"Bonus Bomb Up", "assets/items/bombup"}},
|
||||
{Bonus::BonusType::SPEEDUP, {"Bonus Speed Up", "assets/items/speedup"}},
|
||||
{Bonus::BonusType::EXPLOSIONINC, {"Bonus Fire Up", "assets/items/fireup"}},
|
||||
{Bonus::BonusType::NOCLIP, {"Bonus Wallpass", "assets/items/wallpass"}}
|
||||
};
|
||||
auto bonusType = Bonus::getRandomBonusType();
|
||||
|
||||
@@ -99,21 +124,7 @@ namespace BBM
|
||||
return;
|
||||
if (!map.contains(bonusType))
|
||||
return;
|
||||
wal.getScene()->scheduleNewEntity("Bonus")
|
||||
.addComponent<PositionComponent>(position)
|
||||
.addComponent<TagComponent<BlowablePass>>()
|
||||
.addComponent<MovableComponent>()
|
||||
.addComponent<HealthComponent>(1, [](WAL::Entity &myEntity, WAL::Wal &) {
|
||||
myEntity.scheduleDeletion();
|
||||
})
|
||||
.addComponent<LevitateComponent>(position.y)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
|
||||
func[bonusType - 1], 0.5, .5)
|
||||
.addComponent<TimerComponent>(5s, [](WAL::Entity &bonus, WAL::Wal &){
|
||||
bonus.scheduleDeletion();
|
||||
})
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(map.at(bonusType) + ".obj", false,
|
||||
std::make_pair(MAP_DIFFUSE, "assets/items/items.png"));
|
||||
createBonus(wal.getScene()->scheduleNewEntity(map.at(bonusType)[0]), position, bonusType);
|
||||
}
|
||||
|
||||
const std::string MapGenerator::assetsPath = "./assets/";
|
||||
@@ -227,7 +238,6 @@ namespace BBM
|
||||
{BREAKABLE, &createBreakable},
|
||||
{UNBREAKABLE, &createUnbreakable},
|
||||
{HOLE, &createHole},
|
||||
{FLOOR, &createFloor},
|
||||
{BUMPER, &createBumper},
|
||||
{UPPERFLOOR, &createUpperFloor},
|
||||
};
|
||||
@@ -254,16 +264,6 @@ namespace BBM
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(breakableObj, false, std::make_pair(MAP_DIFFUSE, breakablePng));
|
||||
}
|
||||
|
||||
void MapGenerator::createFloor(Vector3f coords, std::shared_ptr<WAL::Scene> scene)
|
||||
{
|
||||
static const std::string floorObj = floorPath + objExtension;
|
||||
static const std::string floorPng = floorPath + imageExtension;
|
||||
|
||||
scene->addEntity("Floor")
|
||||
.addComponent<PositionComponent>(Vector3f(coords))
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(floorObj, false, std::make_pair(MAP_DIFFUSE, floorPng));
|
||||
}
|
||||
|
||||
void MapGenerator::createUpperFloor(Vector3f coords, std::shared_ptr<WAL::Scene> scene)
|
||||
{
|
||||
static const std::string floorObj = secondFloorPath + objExtension;
|
||||
@@ -508,7 +508,7 @@ namespace BBM
|
||||
.addComponent<PositionComponent>(Vector3f(width / 2 - width / 4, 0, height / 2 - height / 4))
|
||||
.addComponent<CollisionComponent>(
|
||||
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
|
||||
&MapGenerator::wallCollided, Vector3f(0.25, 0.25, 0.25),Vector3f(width / 2 + width / 4, 0.75, height / 2 + height / 4));
|
||||
&MapGenerator::wallCollided, Vector3f(0.25, 0.25, 0.25),Vector3f(width / 2 + 0.75, 0.75, height / 2 + 0.75));
|
||||
}
|
||||
|
||||
void MapGenerator::loadMap(int width, int height, MapBlock map, const std::shared_ptr<WAL::Scene> &scene)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "Component/Collision/CollisionComponent.hpp"
|
||||
#include "Component/Movable/MovableComponent.hpp"
|
||||
#include <chrono>
|
||||
|
||||
#include <Items/Bonus.hpp>
|
||||
|
||||
|
||||
namespace BBM
|
||||
@@ -38,16 +38,54 @@ namespace BBM
|
||||
BREAKABLE,
|
||||
HOLE,
|
||||
UPPERFLOOR,
|
||||
FLOOR,
|
||||
BUMPER,
|
||||
SPAWNER,
|
||||
UNBREAKABLE
|
||||
UNBREAKABLE,
|
||||
INVISIBLE
|
||||
};
|
||||
|
||||
private:
|
||||
using MapElem = std::function<void(Vector3f coords, std::shared_ptr<WAL::Scene> scene)>;
|
||||
using MapBlock = std::map<std::tuple<int, int, int>, BlockType>;
|
||||
|
||||
static void createBonus(WAL::Entity &entity, Vector3f position, Bonus::BonusType bonusType);
|
||||
|
||||
static void wallCollision(WAL::Entity &entity,
|
||||
const WAL::Entity &wall,
|
||||
CollisionComponent::CollidedAxis collidedAxis);
|
||||
static void wallCollided(WAL::Entity &entity,
|
||||
const WAL::Entity &wall,
|
||||
CollisionComponent::CollidedAxis collidedAxis);
|
||||
static void wallDestroyed(WAL::Entity &entity, WAL::Wal &wal);
|
||||
|
||||
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
|
||||
//! @brief Generate map of block to be loaded
|
||||
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
|
||||
//! @param map Map to load with block declared inside
|
||||
//! @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<WAL::Scene> &scene);
|
||||
|
||||
//! @param coords coords of the element
|
||||
//! @param scene Scene where the map is instanced
|
||||
//! @brief Create element of the map
|
||||
static void createElement(Vector3f coords, std::shared_ptr<WAL::Scene> scene, BlockType blockType);
|
||||
private:
|
||||
|
||||
using MapElem = std::function<void(Vector3f coords, std::shared_ptr<WAL::Scene> scene)>;
|
||||
|
||||
//! @brief Generate random block type
|
||||
static BlockType getRandomBlockType(bool = false);
|
||||
|
||||
@@ -77,11 +115,6 @@ namespace BBM
|
||||
//! @brief Generate the floor of the map
|
||||
static void generateFloor(MapBlock map, int width, int height, std::shared_ptr<WAL::Scene> scene);
|
||||
|
||||
//! @param coords coords of the element
|
||||
//! @param scene Scene where the map is instanced
|
||||
//! @brief Create element of the map
|
||||
static void createElement(Vector3f coords, std::shared_ptr<WAL::Scene> scene, BlockType blockType);
|
||||
|
||||
//! @param coords coords of the element
|
||||
//! @param scene Scene where the map is instanced
|
||||
//! @brief Create breakable of the map
|
||||
@@ -102,11 +135,6 @@ namespace BBM
|
||||
//! @brief Create bumper of the map
|
||||
static void createBumper(Vector3f coords, std::shared_ptr<WAL::Scene> scene);
|
||||
|
||||
//! @param coords coords of the element
|
||||
//! @param scene Scene where the map is instanced
|
||||
//! @brief Create floor of the map
|
||||
static void createFloor(Vector3f coords, std::shared_ptr<WAL::Scene> scene);
|
||||
|
||||
//! @param coords coords of the element
|
||||
//! @param scene Scene where the map is instanced
|
||||
//! @brief Create upper floor of the map
|
||||
@@ -175,37 +203,5 @@ namespace BBM
|
||||
static const std::string holePath;
|
||||
|
||||
static const std::string secondFloorHolePath;
|
||||
|
||||
public:
|
||||
|
||||
static void wallCollision(WAL::Entity &entity,
|
||||
const WAL::Entity &wall,
|
||||
CollisionComponent::CollidedAxis collidedAxis);
|
||||
static void wallCollided(WAL::Entity &entity,
|
||||
const WAL::Entity &wall,
|
||||
CollisionComponent::CollidedAxis collidedAxis);
|
||||
static void wallDestroyed(WAL::Entity &entity, WAL::Wal &wal);
|
||||
|
||||
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
|
||||
//! @brief Generate map of block to be loaded
|
||||
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
|
||||
//! @param map Map to load with block declared inside
|
||||
//! @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<WAL::Scene> &scene);
|
||||
};
|
||||
} // namespace BBM
|
||||
@@ -24,6 +24,7 @@ namespace BBM
|
||||
SettingsScene,
|
||||
PauseMenuScene,
|
||||
LobbyScene,
|
||||
ResumeLobbyScene,
|
||||
TitleScreenScene,
|
||||
CreditScene,
|
||||
HowToPlayScene,
|
||||
|
||||
61
sources/Parser/Node.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Created by cbihan on 16/06/2021.
|
||||
//
|
||||
|
||||
#include "Node.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
|
||||
Node::Node(std::string name) :
|
||||
_name(std::move(name))
|
||||
{
|
||||
}
|
||||
|
||||
void Node::setProperty(const std::string &propertyName, const std::string &propertyValue)
|
||||
{
|
||||
this->_properties[propertyName] = propertyValue;
|
||||
}
|
||||
|
||||
std::string Node::getProperty(const std::string &propertyName) const
|
||||
{
|
||||
return this->_properties.at(propertyName);
|
||||
}
|
||||
|
||||
std::string Node::getName() const
|
||||
{
|
||||
return this->_name;
|
||||
}
|
||||
|
||||
void Node::addChildNode(const Node &childNode)
|
||||
{
|
||||
this->_childNodes.emplace_back(childNode);
|
||||
}
|
||||
|
||||
std::vector<Node> Node::getChildNodes(const std::string &childNodeName)
|
||||
{
|
||||
std::vector<Node> childs;
|
||||
|
||||
for (const auto &child : this->_childNodes) {
|
||||
if (child.getName() == childNodeName) {
|
||||
childs.emplace_back(child);
|
||||
}
|
||||
}
|
||||
return childs;
|
||||
}
|
||||
|
||||
std::vector<Node> Node::getChildNodes(void)
|
||||
{
|
||||
return this->_childNodes;
|
||||
}
|
||||
|
||||
void Node::setName(const std::string &name)
|
||||
{
|
||||
this->_name = name;
|
||||
}
|
||||
|
||||
void Node::setProperty(const std::pair<std::string, std::string> &propertyNameValue)
|
||||
{
|
||||
this->setProperty(propertyNameValue.first, propertyNameValue.second);
|
||||
}
|
||||
}
|
||||
51
sources/Parser/Node.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// Created by cbihan on 16/06/2021.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
class Node
|
||||
{
|
||||
private:
|
||||
//! @brief Node name
|
||||
std::string _name;
|
||||
|
||||
//! @brief child nodes
|
||||
std::vector<Node> _childNodes;
|
||||
|
||||
//! @brief node's properties
|
||||
std::map<std::string, std::string> _properties;
|
||||
|
||||
public:
|
||||
|
||||
std::string getName() const;
|
||||
|
||||
void setName(const std::string &name);
|
||||
|
||||
void addChildNode(const Node &childNode);
|
||||
|
||||
std::vector<Node> getChildNodes(const std::string &childNodeName);
|
||||
std::vector<Node> getChildNodes(void);
|
||||
|
||||
void setProperty(const std::string &propertyName, const std::string &propertyValue);
|
||||
void setProperty(const std::pair<std::string, std::string> &propertyNameValue);
|
||||
|
||||
std::string getProperty(const std::string &propertyName) const;
|
||||
|
||||
//! @brief ctor
|
||||
explicit Node(std::string name);
|
||||
//! @brief copy ctor
|
||||
Node(const Node &) = default;
|
||||
//! @brief dtor
|
||||
~Node() = default;
|
||||
//! @brief assignment operator
|
||||
Node &operator=(const Node &) = default;
|
||||
};
|
||||
}
|
||||
|
||||
453
sources/Parser/ParserYaml.cpp
Normal file
@@ -0,0 +1,453 @@
|
||||
//
|
||||
// Created by hbenjamin on 10/06/2021.
|
||||
//
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <Component/Position/PositionComponent.hpp>
|
||||
#include <Component/Timer/TimerComponent.hpp>
|
||||
#include <Map/Map.hpp>
|
||||
#include <Component/BombHolder/BombHolderComponent.hpp>
|
||||
#include <sstream>
|
||||
#include <Component/Keyboard/KeyboardComponent.hpp>
|
||||
#include <Component/Shaders/ShaderComponent.hpp>
|
||||
#include <Component/Animator/AnimatorComponent.hpp>
|
||||
#include <Component/Tag/TagComponent.hpp>
|
||||
#include <Component/Animation/AnimationsComponent.hpp>
|
||||
#include <Component/Sound/SoundComponent.hpp>
|
||||
#include <Component/Bonus/PlayerBonusComponent.hpp>
|
||||
#include <Component/Music/MusicComponent.hpp>
|
||||
#include <Items/Bonus.hpp>
|
||||
#include <Exception/Error.hpp>
|
||||
#include "ParserYaml.hpp"
|
||||
#include "Component/Speed/SpeedComponent.hpp"
|
||||
#include <algorithm>
|
||||
#include <Component/Levitate/LevitateComponent.hpp>
|
||||
#include <Runner/Runner.hpp>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <Component/Gamepad/GamepadComponent.hpp>
|
||||
#include <Component/Renderer/Drawable2DComponent.hpp>
|
||||
#include <System/Lobby/LobbySystem.hpp>
|
||||
#include <filesystem>
|
||||
#include <Component/Lobby/ResumeLobbyComponent.hpp>
|
||||
#include "Utils/Utils.hpp"
|
||||
|
||||
namespace RAY3D = RAY::Drawables::Drawables3D;
|
||||
namespace RAY2D = RAY::Drawables::Drawables2D;
|
||||
|
||||
namespace BBM {
|
||||
|
||||
const std::string ParserYAML::fileName = "save";
|
||||
std::stringstream ParserYAML::_block("");
|
||||
std::stringstream ParserYAML::_bonus("");
|
||||
std::stringstream ParserYAML::_player("");
|
||||
std::vector<ParserYAML::PlayerInfos> ParserYAML::playersInfos = {};
|
||||
|
||||
std::string ParserYAML::_getBlockType(const std::string& blockName)
|
||||
{
|
||||
static std::map<std::string, MapGenerator::BlockType> map {
|
||||
{"Upper Floor", MapGenerator::BlockType::UPPERFLOOR},
|
||||
{"Bumper Block", MapGenerator::BlockType::BUMPER},
|
||||
{"Breakable Block", MapGenerator::BlockType::BREAKABLE},
|
||||
{"Unbreakable Block", MapGenerator::BlockType::UNBREAKABLE},
|
||||
{"Hole Block", MapGenerator::BlockType::HOLE}
|
||||
};
|
||||
|
||||
return (std::to_string(map.at(blockName)));
|
||||
}
|
||||
|
||||
std::string ParserYAML::_getBonusType(const std::string& bonusName)
|
||||
{
|
||||
static std::map<std::string, Bonus::BonusType> map {
|
||||
{"Bonus Bomb Up", Bonus::BonusType::BOMBSTOCK},
|
||||
{"Bonus Speed Up", Bonus::BonusType::SPEEDUP},
|
||||
{"Bonus Fire Up", Bonus::BonusType::EXPLOSIONINC}
|
||||
};
|
||||
|
||||
return (std::to_string(map.at(bonusName)));
|
||||
}
|
||||
|
||||
void ParserYAML::_saveBonus(const WAL::Entity &entity)
|
||||
{
|
||||
auto *position = entity.tryGetComponent<PositionComponent>();
|
||||
auto name = entity.getName();
|
||||
|
||||
if (!position)
|
||||
return;
|
||||
std::replace(name.begin(), name.end(), ' ', '_');
|
||||
_bonus << std::endl << " " << name << ":" << std::endl << " ";
|
||||
_bonus << std::string("bonus_type: ") << _getBonusType(entity.getName()) << std::endl << " ";
|
||||
_bonus << "position: [" << std::to_string(position->getX()) << "," << std::to_string(position->getY()) << "," << std::to_string(position->getZ()) << "]";
|
||||
}
|
||||
|
||||
void ParserYAML::_savePlayer(const WAL::Entity &entity)
|
||||
{
|
||||
auto *position = entity.tryGetComponent<PositionComponent>();
|
||||
auto *bombHolder = entity.tryGetComponent<BombHolderComponent>();
|
||||
auto *model = entity.tryGetComponent<Drawable3DComponent>();
|
||||
auto *speed = entity.tryGetComponent<SpeedComponent>();
|
||||
auto name = entity.getName();
|
||||
|
||||
if (!position || !bombHolder || !model || !speed)
|
||||
return;
|
||||
std::replace(name.begin(), name.end(), ' ', '_');
|
||||
_player << std::endl << " " << name << ":" << std::endl << " ";
|
||||
_player << "texture_path: " << dynamic_cast<RAY3D::Model *>(model->drawable.get())->getTextureByMaterial(MAP_DIFFUSE).getResourcePath() << std::endl << " ";
|
||||
_player << "max_bomb: " << std::to_string(bombHolder->maxBombCount) << std::endl << " ";
|
||||
_player << "explosion_radius: " << std::to_string(bombHolder->explosionRadius) << std::endl << " ";
|
||||
_player << "speed: " << std::to_string(speed->speed) << std::endl << " ";
|
||||
_player << "position: [" << std::to_string(position->getX()) << "," << std::to_string(position->getY()) << "," << std::to_string(position->getZ()) << "]";
|
||||
}
|
||||
|
||||
void ParserYAML::_saveBlock(const WAL::Entity &entity)
|
||||
{
|
||||
auto *position = entity.tryGetComponent<PositionComponent>();
|
||||
auto name = entity.getName();
|
||||
|
||||
if (!position)
|
||||
return;
|
||||
std::replace(name.begin(), name.end(), ' ', '_');
|
||||
_block << std::endl << " " << name << ":" << std::endl << " ";
|
||||
_block << std::string("block_type: ") << _getBlockType(entity.getName()) << std::endl << " ";
|
||||
_block << "position: [" << std::to_string(position->getX()) << "," << std::to_string(position->getY()) << "," << std::to_string(position->getZ()) << "]";
|
||||
}
|
||||
|
||||
void ParserYAML::save(std::shared_ptr<WAL::Scene> scene)
|
||||
{
|
||||
std::string block = std::string("save/" + fileName + "_block.yml");
|
||||
std::string player = std::string("save/" + fileName + "_player.yml");
|
||||
std::string bonus = std::string("save/" + fileName + "_bonus.yml");
|
||||
std::map<std::string, std::function<void (const WAL::Entity &)>> savingGame = {
|
||||
{"Bonus", &_saveBonus},
|
||||
{"Block", &_saveBlock},
|
||||
{"Upper Floor", &_saveBlock},
|
||||
{"Player", &_savePlayer}
|
||||
};
|
||||
std::ofstream blockFile(block);
|
||||
std::ofstream playerFile(player);
|
||||
std::ofstream bonusFile(bonus);
|
||||
auto &ret = scene->view<TagComponent<Timer>, TimerComponent>();
|
||||
_block << "timer: " << ret.front().get<TimerComponent>().ringIn.count();
|
||||
|
||||
_player << "players:";
|
||||
_bonus << "bonuses:";
|
||||
_block << std::endl << "width: " << std::to_string(Runner::mapWidth);
|
||||
_block << std::endl << "height: " + std::to_string(Runner::mapHeight);
|
||||
_block << std::endl << "blocks:";
|
||||
for (const auto &entity : scene->getEntities()) {
|
||||
for (const auto& type : savingGame) {
|
||||
if (entity.getName().find(type.first) != std::string::npos) {
|
||||
type.second(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
blockFile << _block.str() << std::endl;
|
||||
playerFile << _player.str() << std::endl;
|
||||
bonusFile << _bonus.str() << std::endl;
|
||||
_block = std::stringstream();
|
||||
_player = std::stringstream();
|
||||
_bonus = std::stringstream();
|
||||
}
|
||||
|
||||
void ParserYAML::_loadPlayer(std::shared_ptr<WAL::Scene> scene, Node &node, int countPlayer)
|
||||
{
|
||||
std::string tmpAssets = node.getProperty("texture_path");
|
||||
std::map<std::string, RAY::Color> map = {
|
||||
{"red", RED},
|
||||
{"blue", BLUE},
|
||||
{"yellow", YELLOW},
|
||||
{"green", GREEN}
|
||||
};
|
||||
std::map<std::string, int> colors = {
|
||||
{"red", 1},
|
||||
{"blue", 0},
|
||||
{"yellow", 3},
|
||||
{"green", 2}
|
||||
};
|
||||
|
||||
|
||||
playersInfos.emplace_back(PlayerInfos{
|
||||
node.getName(),
|
||||
_parsePosition(node.getProperty("position")),
|
||||
_parseMaxBomb(node.getProperty("max_bomb")),
|
||||
_parseExplosionRadius(node.getProperty("explosion_radius")),
|
||||
_parseSpeed(node.getProperty("speed")),
|
||||
node.getProperty("texture_path")
|
||||
});
|
||||
|
||||
if ((tmpAssets.find("red.png") == std::string::npos && tmpAssets.find("blue.png") == std::string::npos &&
|
||||
tmpAssets.find("green.png") == std::string::npos && tmpAssets.find("yellow.png") == std::string::npos &&
|
||||
tmpAssets.find("ai.png") == std::string::npos) || !std::filesystem::exists(tmpAssets)) {
|
||||
throw (ParserError("One asset is invalid."));
|
||||
}
|
||||
auto start = tmpAssets.find_last_of('/') + 1;
|
||||
auto colorStr = tmpAssets.substr(start, tmpAssets.length() - start - 4);
|
||||
auto color = map.at(colorStr);
|
||||
auto resumeScene = Runner::gameState.loadedScenes[GameState::SceneID::ResumeLobbyScene];
|
||||
auto &playerTile = resumeScene->addEntity("player tile")
|
||||
.addComponent<PositionComponent>(224 * (countPlayer + 1) + 200 * countPlayer, 1080 / 3, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Rectangle>(RAY::Vector2(224 * (countPlayer + 1) + 200 * countPlayer, 1080 / 3), RAY::Vector2(200, 200), color);
|
||||
auto &playerLogo = resumeScene->addEntity("player")
|
||||
.addComponent<PositionComponent>(224 * (countPlayer + 1) + 200 * countPlayer, 1080 / 3, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>(tmpAssets.replace(tmpAssets.find("textures"), 8, "icons"));
|
||||
auto &ready = resumeScene->addEntity("ready")
|
||||
.addComponent<PositionComponent>(224 * (countPlayer + 1) + 200 * countPlayer, 1080 / 3, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>();
|
||||
playerLogo.addComponent<ResumeLobbyComponent>(countPlayer, ready, playerTile, colors.at(colorStr));
|
||||
}
|
||||
|
||||
void ParserYAML::_loadPlayers(std::shared_ptr<WAL::Scene> scene, Node &node)
|
||||
{
|
||||
int countPlayer = 0;
|
||||
auto childNode = node.getChildNodes("players").at(0).getChildNodes();
|
||||
|
||||
if (childNode.size() < 2)
|
||||
throw (ParserError("There isn't enough players to load this saved map."));
|
||||
for (auto &child : childNode) {
|
||||
_loadPlayer(scene, child, countPlayer);
|
||||
countPlayer++;
|
||||
}
|
||||
}
|
||||
|
||||
void ParserYAML::_loadBlock(std::shared_ptr<WAL::Scene> scene, Node child, MapGenerator::MapBlock &map)
|
||||
{
|
||||
Vector3f pos = _parsePosition(child.getProperty("position"));
|
||||
MapGenerator::BlockType blockType = _parseBlockType(child.getProperty("block_type"));
|
||||
|
||||
if (blockType == MapGenerator::NOTHING)
|
||||
throw (ParserError("Invalid block_type field."));
|
||||
if (blockType == MapGenerator::HOLE)
|
||||
pos.y += 1.0f;
|
||||
map[std::make_tuple(pos.x, pos.y, pos.z)] = blockType;
|
||||
}
|
||||
|
||||
void ParserYAML::_loadBlocks(std::shared_ptr<WAL::Scene> scene, Node &node)
|
||||
{
|
||||
MapGenerator::MapBlock map;
|
||||
int size = -1;
|
||||
|
||||
if (!Utils::tryParseInteger(node.getProperty("width"), size)) {
|
||||
throw ParserError("width property must be an int");
|
||||
}
|
||||
Runner::mapWidth = size;
|
||||
if (!Utils::tryParseInteger(node.getProperty("height"), size)) {
|
||||
throw ParserError("width property must be an int");
|
||||
}
|
||||
Runner::mapHeight = size;
|
||||
long timer = 0;
|
||||
if (!Utils::tryParseLong(node.getProperty("timer"), timer)) {
|
||||
throw ParserError("timer property must be a long");
|
||||
}
|
||||
Runner::timerDelay = std::chrono::nanoseconds(timer);
|
||||
|
||||
for (int i = 0; i < Runner::mapWidth; i++)
|
||||
for (int j = 0; j < Runner::mapHeight; j++)
|
||||
map[std::make_tuple(i, 0, j)] = MapGenerator::NOTHING;
|
||||
auto childNode = node.getChildNodes("blocks").at(0).getChildNodes();
|
||||
for (const auto& child : childNode)
|
||||
_loadBlock(scene, child, map);
|
||||
MapGenerator::loadMap(Runner::mapWidth, Runner::mapHeight, map, scene);
|
||||
}
|
||||
|
||||
void ParserYAML::_loadBonus(std::shared_ptr<WAL::Scene> scene, Node &node)
|
||||
{
|
||||
auto &entity = scene->addEntity(node.getName());
|
||||
Vector3f pos = _parsePosition(node.getProperty("position"));
|
||||
Bonus::BonusType bonusType = _parseBonusType(node.getProperty("bonus_type"));
|
||||
|
||||
if (bonusType == Bonus::NOTHING) {
|
||||
entity.scheduleDeletion();
|
||||
return;
|
||||
}
|
||||
MapGenerator::createBonus(entity, pos, bonusType);
|
||||
}
|
||||
|
||||
void ParserYAML::_loadBonuses(std::shared_ptr<WAL::Scene> scene, Node &node)
|
||||
{
|
||||
auto childNode = node.getChildNodes("bonuses").at(0).getChildNodes();
|
||||
for (auto child : childNode)
|
||||
_loadBonus(scene, child);
|
||||
}
|
||||
|
||||
void ParserYAML::load(std::shared_ptr<WAL::Scene> gameScene)
|
||||
{
|
||||
Node blocksInfos = parseFile("save/save_block.yml");
|
||||
Node bonusesInfos = parseFile("save/save_bonus.yml");
|
||||
Node playerInfos = parseFile("save/save_player.yml");
|
||||
_loadBlocks(gameScene, blocksInfos);
|
||||
_loadBonuses(gameScene, bonusesInfos);
|
||||
_loadPlayers(gameScene, playerInfos);
|
||||
}
|
||||
|
||||
Vector3f ParserYAML::_parsePosition(const std::string& line)
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
std::string subStr;
|
||||
|
||||
try {
|
||||
auto start = line.find('[') + 1;
|
||||
auto end = line.find(']');
|
||||
if (line.front() != '[' || end == std::string::npos || line.back() != ']') {
|
||||
throw ParserError("Error parsing position.");
|
||||
}
|
||||
subStr = line.substr(start, end - start);
|
||||
auto pos = Utils::splitStr(subStr, ',');
|
||||
if (pos.size() != 3)
|
||||
throw (ParserError("Error parsing position."));
|
||||
if (!Utils::tryParseFloat(pos[0], x) || !Utils::tryParseFloat(pos[1], y) || !Utils::tryParseFloat(pos[2], z))
|
||||
throw (ParserError("Error parsing position."));
|
||||
} catch (const std::out_of_range &err) {
|
||||
throw (ParserError("Error parsing position."));
|
||||
}
|
||||
return Vector3f(x, y, z);
|
||||
}
|
||||
|
||||
int ParserYAML::_parseMaxBomb(const std::string &str)
|
||||
{
|
||||
int maxBomb = 0;
|
||||
|
||||
if (str.find('-') != std::string::npos)
|
||||
throw (ParserError("Couldn't parse max bomb."));
|
||||
if (!Utils::tryParseInteger(str, maxBomb))
|
||||
throw (ParserError("Couldn't parse max bomb."));
|
||||
return (maxBomb);
|
||||
}
|
||||
|
||||
int ParserYAML::_parseExplosionRadius(const std::string& line)
|
||||
{
|
||||
int explosionRadius = 0;
|
||||
|
||||
if (line.find('-') != std::string::npos)
|
||||
throw (ParserError("Couldn't parse explosion radius."));
|
||||
if (!Utils::tryParseInteger(line, explosionRadius))
|
||||
throw (ParserError("Couldn't parse explosion radius."));
|
||||
return (explosionRadius);
|
||||
}
|
||||
|
||||
float ParserYAML::_parseSpeed(const std::string& line)
|
||||
{
|
||||
float speed = 0;
|
||||
|
||||
if (line.find('-') != std::string::npos)
|
||||
throw (ParserError("Couldn't parse speed."));
|
||||
if (!Utils::tryParseFloat(line, speed))
|
||||
throw (ParserError("Couldn't parse speed."));
|
||||
return (speed);
|
||||
}
|
||||
|
||||
MapGenerator::BlockType ParserYAML::_parseBlockType(const std::string& blockType)
|
||||
{
|
||||
if (blockType.find('-') != std::string::npos)
|
||||
throw (ParserError("Couldn't parse block type."));
|
||||
int block = 0;
|
||||
if (!Utils::tryParseInteger(blockType, block))
|
||||
throw (ParserError("Couldn't parse block type."));
|
||||
return (static_cast<MapGenerator::BlockType>(block));
|
||||
}
|
||||
|
||||
Bonus::BonusType ParserYAML::_parseBonusType(const std::string& bonusType)
|
||||
{
|
||||
if (bonusType.find('-') != std::string::npos)
|
||||
throw (ParserError("Couldn't parse bonus type."));
|
||||
int bonus = 0;
|
||||
if (!Utils::tryParseInteger(bonusType, bonus))
|
||||
throw (ParserError("Couldn't parse bonus type."));
|
||||
return (static_cast<Bonus::BonusType>(bonus));
|
||||
}
|
||||
|
||||
std::string ParserYAML::parseHeader(const std::string &line)
|
||||
{
|
||||
std::stringstream ss(line);
|
||||
std::string headerName;
|
||||
std::string garbage;
|
||||
|
||||
ss >> headerName >> garbage;
|
||||
|
||||
|
||||
if (!garbage.empty()) {
|
||||
throw ParserError("Ill formed header,\nline: " + Utils::trimCopy(line));
|
||||
}
|
||||
if (headerName.back() != ':') {
|
||||
throw ParserError("Header not ended with ':',\nline: " + Utils::trimCopy(line));
|
||||
}
|
||||
headerName.pop_back();
|
||||
return headerName;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> ParserYAML::parseProperty(const std::string &line)
|
||||
{
|
||||
std::stringstream ss(line);
|
||||
std::string propertyName;
|
||||
std::string propertyValue;
|
||||
std::string garbage;
|
||||
|
||||
ss >> propertyName >> propertyValue >> garbage;
|
||||
|
||||
if (!garbage.empty()) {
|
||||
throw ParserError("ill formed property, \nline: " + Utils::trimCopy(line));
|
||||
}
|
||||
if (propertyName.back() != ':') {
|
||||
throw ParserError("property name not ended with ':', \nline: " + Utils::trimCopy(line));
|
||||
}
|
||||
propertyName.pop_back();
|
||||
return std::make_pair(propertyName, propertyValue);
|
||||
}
|
||||
|
||||
bool ParserYAML::isHeader(const std::string &line)
|
||||
{
|
||||
return line.back() == ':';
|
||||
}
|
||||
|
||||
Node ParserYAML::parseFile(const std::string &path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
|
||||
if (!file.good())
|
||||
throw ParserError("Can't read file");
|
||||
return parseNode(file, "root");
|
||||
}
|
||||
|
||||
Node ParserYAML::parseNode(std::ifstream &file, const std::string &nodeName, int indentLevel)
|
||||
{
|
||||
std::string line;
|
||||
Node node(nodeName);
|
||||
|
||||
while(std::getline(file, line)) {
|
||||
if (line.empty())
|
||||
continue;
|
||||
float lineIndentLevel = getIndent(line);
|
||||
if (lineIndentLevel != static_cast<int>(lineIndentLevel)) {
|
||||
throw ParserError("Yaml only support 2 spaces as indent");
|
||||
}
|
||||
if (lineIndentLevel > static_cast<float>(indentLevel)) {
|
||||
throw ParserError("Indent issue");
|
||||
}
|
||||
if (lineIndentLevel < static_cast<float>(indentLevel)) {
|
||||
file.seekg(static_cast<size_t>(file.tellg()) - (line.length() + endlNbChars));
|
||||
return node;
|
||||
}
|
||||
if (isHeader(line)) {
|
||||
node.addChildNode(parseNode(file, parseHeader(line), indentLevel + 1));
|
||||
} else {
|
||||
node.setProperty(parseProperty(line));
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
float ParserYAML::getIndent(const std::string &line)
|
||||
{
|
||||
int nb = 0;
|
||||
for (const auto &c : line) {
|
||||
if (!std::isspace(c))
|
||||
break;
|
||||
if (c != ' ')
|
||||
throw ParserError("Yaml only support 2 spaces as indent");
|
||||
nb++;
|
||||
}
|
||||
return static_cast<float>(nb / 2.);
|
||||
}
|
||||
}
|
||||
135
sources/Parser/ParserYaml.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// Created by hbenjamin on 10/06/2021.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wal.hpp>
|
||||
#include "Items/Bonus.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "Map/Map.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
|
||||
namespace BBM {
|
||||
class ParserYAML {
|
||||
private:
|
||||
|
||||
//! @brief The number of chars for endl
|
||||
#ifdef __linux__
|
||||
static constexpr int endlNbChars = 1;
|
||||
#elif _WIN32
|
||||
static constexpr int endlNbChars = 2;
|
||||
#endif
|
||||
|
||||
//!@brief file block of the parser
|
||||
static std::stringstream _block;
|
||||
//!@brief file bonus of the parser
|
||||
static std::stringstream _bonus;
|
||||
//!@brief file player of the parser
|
||||
static std::stringstream _player;
|
||||
|
||||
//!@param entity entity to save
|
||||
//!@brief save block in _block
|
||||
static void _saveBlock(const WAL::Entity &entity);
|
||||
//!@param entity entity to save
|
||||
//!@brief save bonus in _bonus
|
||||
static void _saveBonus(const WAL::Entity &entity);
|
||||
//!@param entity entity to save
|
||||
//!@brief save player in _player
|
||||
static void _savePlayer(const WAL::Entity &entity);
|
||||
//!@param blockName block name
|
||||
//!@brief transform block name
|
||||
static std::string _getBlockType(const std::string& blockName);
|
||||
//!@param blockName bonus name
|
||||
//!@brief transform bonus name
|
||||
static std::string _getBonusType(const std::string& bonusName);
|
||||
|
||||
//!@param str to parse
|
||||
//!@brief return max bomb parsed
|
||||
static int _parseMaxBomb(const std::string& str);
|
||||
//!@param line to parse
|
||||
//!@brief return explosion radius parsed
|
||||
static int _parseExplosionRadius(const std::string& line);
|
||||
//!@param line to parse
|
||||
//!@brief return speed parsed
|
||||
static float _parseSpeed(const std::string& line);
|
||||
//!@param line to parse
|
||||
//!@brief return vector3f of position parsed
|
||||
static Vector3f _parsePosition(const std::string& line);
|
||||
//!@param blockType to parse
|
||||
//!@brief return BlockType of type parsed
|
||||
static MapGenerator::BlockType _parseBlockType(const std::string& blockType);
|
||||
//!@param bonusType to parse
|
||||
//!@brief return bonusType of type parsed
|
||||
static Bonus::BonusType _parseBonusType(const std::string& bonusType);
|
||||
|
||||
//!@param scene Scene to update
|
||||
//!@param lines Lines of the file
|
||||
//!@param index index of the vector
|
||||
//!@brief add player into scene
|
||||
static void _loadPlayer(std::shared_ptr<WAL::Scene> scene, Node &node, int countPlayer);
|
||||
//!@param scene Scene to update
|
||||
//!@param lines Lines of the file
|
||||
//!@param index index of the vector
|
||||
//!@param map map of all the block
|
||||
//!@brief add block into scene
|
||||
static void _loadBlock(std::shared_ptr<WAL::Scene> scene, Node child, MapGenerator::MapBlock &map);
|
||||
//!@param scene Scene to update
|
||||
//!@param lines Lines of the file
|
||||
//!@param index index of the vector
|
||||
//!@brief add bonus into scene
|
||||
static void _loadBonus(std::shared_ptr<WAL::Scene> scene, Node &node);
|
||||
|
||||
//!@param scene Scene to update
|
||||
//!@brief load all players into scene
|
||||
static void _loadPlayers(std::shared_ptr<WAL::Scene> scene, Node &node);
|
||||
//!@param scene Scene to update
|
||||
//!@brief load all blocks into scene
|
||||
static void _loadBlocks(std::shared_ptr<WAL::Scene> scene, Node &node);
|
||||
//!@param scene Scene to update
|
||||
//!@brief load all blocks into scene
|
||||
static void _loadBonuses(std::shared_ptr<WAL::Scene> scene, Node &node);
|
||||
|
||||
static std::string parseHeader(const std::string &line);
|
||||
|
||||
static std::pair<std::string ,std::string> parseProperty(const std::string &line);
|
||||
|
||||
static bool isHeader(const std::string &line);
|
||||
|
||||
static Node parseNode(std::ifstream &file, const std::string &nodeName, int indentLevel = 0);
|
||||
|
||||
static float getIndent(const std::string &line);
|
||||
|
||||
static constexpr const char* indent = " ";
|
||||
|
||||
public:
|
||||
|
||||
static Node parseFile(const std::string &path);
|
||||
|
||||
struct PlayerInfos {
|
||||
std::string name;
|
||||
//! @brief Player position
|
||||
Vector3f position;
|
||||
//! @brief The amount of bomb a player had
|
||||
int maxBombCount;
|
||||
//! @brief The explosion range of a player
|
||||
int explosionRange;
|
||||
//! @brief The speed of a player
|
||||
float speed;
|
||||
//! @brief The assets of the player
|
||||
std::string asset;
|
||||
};
|
||||
|
||||
static std::vector<PlayerInfos> playersInfos;
|
||||
|
||||
//!@param scene Scene to update
|
||||
//!@brief save yaml
|
||||
static void save(std::shared_ptr<WAL::Scene> scene);
|
||||
//!@param scene Scene to update
|
||||
//!@brief load yaml
|
||||
static void load(std::shared_ptr<WAL::Scene> scene);
|
||||
|
||||
//! @brief save file name
|
||||
static const std::string fileName;
|
||||
};
|
||||
}
|
||||
@@ -3,11 +3,14 @@
|
||||
#include "Runner.hpp"
|
||||
#include <map>
|
||||
#include "Component/Tag/TagComponent.hpp"
|
||||
#include <Parser/ParserYaml.hpp>
|
||||
#include <Component/Bonus/PlayerBonusComponent.hpp>
|
||||
#include <Component/Renderer/Drawable2DComponent.hpp>
|
||||
#include "Component/Music/MusicComponent.hpp"
|
||||
#include "Component/Sound/SoundComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include "Component/Timer/TimerComponent.hpp"
|
||||
#include "Component/Animator/AnimatorComponent.hpp"
|
||||
#include "Component/Animation/AnimationsComponent.hpp"
|
||||
#include "Component/Health/HealthComponent.hpp"
|
||||
@@ -18,6 +21,7 @@
|
||||
#include "Component/Tag/TagComponent.hpp"
|
||||
#include "Component/Renderer/Drawable3DComponent.hpp"
|
||||
#include "Component/Shaders/Items/AlphaCtxShaderComponent.hpp"
|
||||
#include "Component/Speed/SpeedComponent.hpp"
|
||||
#include <Drawables/Image.hpp>
|
||||
#include "Component/Shaders/ShaderComponent.hpp"
|
||||
#include "Component/Gravity/GravityComponent.hpp"
|
||||
@@ -44,7 +48,6 @@ namespace BBM
|
||||
scene->addEntity("background image")
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>("assets/map/breakable_wall.obj", true, std::make_pair(MAP_DIFFUSE, "assets/backgrounds/gameWall.png"), Vector3f(50, 1, 50), -90, Vector3f(), Vector3f(1, 0, 0))
|
||||
.addComponent<PositionComponent>(5, 14, 22);
|
||||
MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16, hasHeights), scene);
|
||||
return scene;
|
||||
}
|
||||
|
||||
@@ -57,7 +60,7 @@ namespace BBM
|
||||
//{SoundComponent::DEATH, "assets/sounds/death.ogg"}
|
||||
};
|
||||
|
||||
return scene.addEntity("player")
|
||||
return scene.addEntity("Player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>("assets/player/player.iqm", true, std::nullopt, Vector3f(.75, .75, .75))
|
||||
.addComponent<ScoreComponent>()
|
||||
@@ -67,6 +70,7 @@ namespace BBM
|
||||
.addComponent<ControllableComponent>(true)
|
||||
.addComponent<TagComponent<BlowablePass>>()
|
||||
.addComponent<TagComponent<Player>>()
|
||||
.addComponent<SpeedComponent>()
|
||||
.addComponent<AnimationsComponent>("assets/player/player.iqm", 3)
|
||||
.addComponent<CollisionComponent>(BBM::Vector3f{0.25, 0, 0.25}, BBM::Vector3f{.6, 2, .6})
|
||||
.addComponent<MovableComponent>()
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <Wal.hpp>
|
||||
#include "Runner.hpp"
|
||||
#include <map>
|
||||
#include <Parser/ParserYaml.hpp>
|
||||
#include <Component/Timer/TimerComponent.hpp>
|
||||
#include "Component/Music/MusicComponent.hpp"
|
||||
#include "Component/Sound/SoundComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
@@ -34,7 +36,7 @@ namespace BBM
|
||||
.addComponent<PositionComponent>(1920 / 3, 180, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/logo_small.png");
|
||||
auto &play = scene->addEntity("play button")
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 540, 0)
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 650, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_new_game.png")
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
@@ -52,8 +54,42 @@ namespace BBM
|
||||
{
|
||||
gameState.nextScene = BBM::GameState::SceneID::LobbyScene;
|
||||
});
|
||||
auto &resume = scene->addEntity("resume button")
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 540, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_resume_game.png")
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
RAY::Texture *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
|
||||
texture->use("assets/buttons/button_resume_game.png");
|
||||
})
|
||||
.addComponent<OnHoverComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
RAY::Texture *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
|
||||
texture->use("assets/buttons/button_resume_game_hovered.png");
|
||||
})
|
||||
.addComponent<OnClickComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
gameState.nextScene = BBM::GameState::SceneID::ResumeLobbyScene;
|
||||
auto gameScene = Runner::loadGameScene();
|
||||
try {
|
||||
ParserYAML::load(gameScene);
|
||||
} catch (std::exception const &err) {
|
||||
std::cout << err.what() << std::endl;
|
||||
Runner::gameState.loadedScenes[GameState::SceneID::MainMenuScene]->addEntity("Error message parser")
|
||||
.addComponent<PositionComponent>(1920 / 5, 2 * 1080 / 4.25, 0)
|
||||
.addComponent<TimerComponent>(3s, [](WAL::Entity &myEntity, WAL::Wal &) {
|
||||
myEntity.scheduleDeletion();
|
||||
})
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("Could not load file: " + std::string(err.what()), 50, RAY::Vector2(), RED);
|
||||
gameState.nextScene = BBM::GameState::SceneID::MainMenuScene;
|
||||
return;
|
||||
}
|
||||
Runner::gameState.loadedScenes[GameState::SceneID::GameScene] = gameScene;
|
||||
});
|
||||
auto &settings = scene->addEntity("settings button")
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 360, 0)
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 430, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_settings.png")
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
@@ -72,7 +108,7 @@ namespace BBM
|
||||
gameState.nextScene = BBM::GameState::SceneID::SettingsScene;
|
||||
});
|
||||
auto &exit = scene->addEntity("exit button")
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 180, 0)
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 320, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_exit.png")
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
@@ -109,8 +145,9 @@ namespace BBM
|
||||
{
|
||||
gameState.nextScene = BBM::GameState::SceneID::CreditScene;
|
||||
});
|
||||
play.getComponent<OnClickComponent>().setButtonLinks(nullptr, &settings);
|
||||
settings.getComponent<OnClickComponent>().setButtonLinks(&play, &exit);
|
||||
play.getComponent<OnClickComponent>().setButtonLinks(nullptr, &resume);
|
||||
resume.getComponent<OnClickComponent>().setButtonLinks(&play, &settings);
|
||||
settings.getComponent<OnClickComponent>().setButtonLinks(&resume, &exit);
|
||||
exit.getComponent<OnClickComponent>().setButtonLinks(&settings, &credits, nullptr, &credits);
|
||||
credits.getComponent<OnClickComponent>().setButtonLinks(&exit, nullptr, &exit);
|
||||
return scene;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Component/Health/HealthComponent.hpp"
|
||||
#include "Component/Timer/TimerComponent.hpp"
|
||||
#include "Component/Tag/TagComponent.hpp"
|
||||
#include <Parser/ParserYaml.hpp>
|
||||
#include "Component/Music/MusicComponent.hpp"
|
||||
#include "Component/Sound/SoundComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
@@ -14,6 +15,7 @@
|
||||
#include "Component/Renderer/Drawable2DComponent.hpp"
|
||||
#include "Component/Button/ButtonComponent.hpp"
|
||||
#include "Drawables/2D/Text.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
namespace RAY2D = RAY::Drawables::Drawables2D;
|
||||
|
||||
@@ -75,10 +77,33 @@ namespace BBM
|
||||
entity.scheduleDeletion();
|
||||
})
|
||||
.addComponent<PositionComponent>(1920 / 2 - 2 * 30, 1080 / 2, 0)
|
||||
.addComponent<TagComponent<"Timer">>()
|
||||
.addComponent<TagComponent<Timer>>()
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("", 60, RAY::Vector2(), ORANGE);
|
||||
gameState.nextScene = BBM::GameState::SceneID::GameScene;
|
||||
});
|
||||
auto &save = scene->addEntity("save & quit button")
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 240, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_save.png")
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
RAY::Texture *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
|
||||
texture->use("assets/buttons/button_save.png");
|
||||
})
|
||||
.addComponent<OnHoverComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
RAY::Texture *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
|
||||
texture->use("assets/buttons/button_save_hovered.png");
|
||||
})
|
||||
.addComponent<OnClickComponent>([](WAL::Entity &entity, WAL::Wal &wal)
|
||||
{
|
||||
if (!std::filesystem::exists("save"))
|
||||
std::filesystem::create_directories("save");
|
||||
ParserYAML::save(Runner::gameState.loadedScenes[GameState::SceneID::GameScene]);
|
||||
wal.getSystem<CameraSystem>().hasEnded = false;
|
||||
gameState.nextScene = BBM::GameState::SceneID::MainMenuScene;
|
||||
});
|
||||
auto &settings = scene->addEntity("settings button")
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 360, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_settings.png")
|
||||
@@ -99,7 +124,7 @@ namespace BBM
|
||||
gameState.nextScene = BBM::GameState::SceneID::SettingsScene;
|
||||
});
|
||||
auto &exit = scene->addEntity("exit button")
|
||||
.addComponent<PositionComponent>(1920 / 1.5, 1080 - 360, 0)
|
||||
.addComponent<PositionComponent>(1920 / 1.55, 1080 - 360, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_exit.png")
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
@@ -120,9 +145,10 @@ namespace BBM
|
||||
});
|
||||
//needed material
|
||||
//music
|
||||
play.getComponent<OnClickComponent>().setButtonLinks(nullptr, nullptr, nullptr, &settings);
|
||||
settings.getComponent<OnClickComponent>().setButtonLinks(nullptr, nullptr, &play, &exit);
|
||||
exit.getComponent<OnClickComponent>().setButtonLinks(nullptr, nullptr, &settings, nullptr);
|
||||
save.getComponent<OnClickComponent>().setButtonLinks(&settings);
|
||||
play.getComponent<OnClickComponent>().setButtonLinks(nullptr, &save, nullptr, &settings);
|
||||
settings.getComponent<OnClickComponent>().setButtonLinks(nullptr, &save, &play, &exit);
|
||||
exit.getComponent<OnClickComponent>().setButtonLinks(nullptr, &save, &settings, nullptr);
|
||||
return scene;
|
||||
}
|
||||
}
|
||||
97
sources/Runner/ResumeLobbyScene.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// Created by hbenjamin on 15/06/2021.
|
||||
//
|
||||
|
||||
#include <Wal.hpp>
|
||||
#include "System/Movable/MovableSystem.hpp"
|
||||
#include <Model/Model.hpp>
|
||||
#include <Drawables/2D/Rectangle.hpp>
|
||||
#include <Drawables/2D/Text.hpp>
|
||||
#include <TraceLog.hpp>
|
||||
#include "Component/Button/ButtonComponent.hpp"
|
||||
#include "Component/Renderer/CameraComponent.hpp"
|
||||
#include "Component/Renderer/Drawable2DComponent.hpp"
|
||||
#include "Runner.hpp"
|
||||
#include "Models/GameState.hpp"
|
||||
#include <Component/Animator/AnimatorComponent.hpp>
|
||||
#include <Component/Tag/TagComponent.hpp>
|
||||
#include <Drawables/Texture.hpp>
|
||||
#include <System/Lobby/ResumeLobbySystem.hpp>
|
||||
#include "System/Sound/PlayerSoundManagerSystem.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;
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
std::shared_ptr<WAL::Scene> Runner::loadResumeLobbyScene()
|
||||
{
|
||||
static const std::map<SoundComponent::SoundIndex, std::string> sounds = {
|
||||
{SoundComponent::JUMP, "assets/sounds/click.ogg"}
|
||||
};
|
||||
auto scene = std::make_shared<WAL::Scene>();
|
||||
|
||||
addMenuControl(*scene);
|
||||
scene->addEntity("Control entity")
|
||||
.addComponent<MusicComponent>("assets/musics/music_player_select.ogg")
|
||||
.addComponent<SoundComponent>(sounds);
|
||||
scene->addEntity("background")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/backgrounds/menu.png");
|
||||
scene->addEntity("white background")
|
||||
.addComponent<PositionComponent>(200, 300, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Rectangle>(Vector2f(), Vector2f(1525, 325), RAY::Color(WHITE).setA(150));
|
||||
scene->addEntity("lobby text")
|
||||
.addComponent<PositionComponent>(1920 / 2.75, 100, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("Get Ready", 120, RAY::Vector2(), ORANGE);
|
||||
auto &play = scene->addEntity("play button")
|
||||
.addComponent<PositionComponent>(1920 / 2.5, 1080 - 180, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_new_game.png")
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &wal)
|
||||
{
|
||||
auto *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
texture->use("assets/buttons/button_new_game.png");
|
||||
})
|
||||
.addComponent<OnHoverComponent>([](WAL::Entity &entity, WAL::Wal &wal)
|
||||
{
|
||||
auto *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
texture->use("assets/buttons/button_new_game_hovered.png");
|
||||
})
|
||||
.addComponent<OnClickComponent>([](WAL::Entity &entity, WAL::Wal &wal)
|
||||
{
|
||||
if (Runner::gameState.currentScene != GameState::ResumeLobbyScene
|
||||
|| !ResumeLobbySystem::playersAreReady(*wal.getScene()))
|
||||
return;
|
||||
ResumeLobbySystem::resumeToGame(wal);
|
||||
})
|
||||
.addComponent<TagComponent<"PlayButton">>();
|
||||
auto &back = scene->addEntity("back to menu")
|
||||
.addComponent<PositionComponent>(10, 1080 - 85, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>("assets/buttons/button_back.png")
|
||||
.addComponent<OnClickComponent>([](WAL::Entity &entity, WAL::Wal &wal)
|
||||
{
|
||||
wal.getSystem<ResumeLobbySystem>().unloadLobbyFromResume();
|
||||
gameState.nextScene = BBM::GameState::SceneID::MainMenuScene;
|
||||
})
|
||||
.addComponent<OnIdleComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
RAY::Texture *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
texture->use("assets/buttons/button_back.png");
|
||||
})
|
||||
.addComponent<OnHoverComponent>([](WAL::Entity &entity, WAL::Wal &)
|
||||
{
|
||||
RAY::Texture *texture = dynamic_cast<RAY::Texture *>(entity.getComponent<Drawable2DComponent>().drawable.get());
|
||||
|
||||
texture->use("assets/buttons/button_back_hovered.png");
|
||||
});
|
||||
scene->addEntity("camera")
|
||||
.addComponent<PositionComponent>(8, 20, 7)
|
||||
.addComponent<CameraComponent>(Vector3f(8, 0, 8));
|
||||
play.getComponent<OnClickComponent>().setButtonLinks(nullptr, &back, &back);
|
||||
back.getComponent<OnClickComponent>().setButtonLinks(&play, nullptr, nullptr, &play);
|
||||
return scene;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "System/IAControllable/IAControllableSystem.hpp"
|
||||
#include "System/MenuControllable/MenuControllableSystem.hpp"
|
||||
#include <System/Bomb/BombSystem.hpp>
|
||||
#include <Parser/ParserYaml.hpp>
|
||||
#include <System/Lobby/ResumeLobbySystem.hpp>
|
||||
#include "System/Sound/PlayerSoundManagerSystem.hpp"
|
||||
#include "System/Sound/MenuSoundManagerSystem.hpp"
|
||||
#include "System/Gravity/GravitySystem.hpp"
|
||||
@@ -46,7 +48,10 @@
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
std::chrono::nanoseconds Runner::timerDelay = std::chrono::minutes(3);
|
||||
GameState Runner::gameState;
|
||||
int Runner::mapWidth = 16;
|
||||
int Runner::mapHeight = 16;
|
||||
bool Runner::hasHeights = false;
|
||||
|
||||
void Runner::updateState(WAL::Wal &engine, GameState &state)
|
||||
@@ -108,6 +113,7 @@ namespace BBM
|
||||
.addSystem<ShaderDrawable2DSystem>()
|
||||
.addSystem<ScoreSystem>()
|
||||
.addSystem<CameraSystem>()
|
||||
.addSystem<ResumeLobbySystem>()
|
||||
.addSystem<EndConditionSystem>()
|
||||
.addSystem<MusicSystem>();
|
||||
}
|
||||
@@ -152,6 +158,7 @@ namespace BBM
|
||||
gameState.loadedScenes[GameState::SceneID::CreditScene] = loadCreditScene();
|
||||
gameState.loadedScenes[GameState::SceneID::SplashScreen] = loadSplashScreenScene();
|
||||
gameState.loadedScenes[GameState::SceneID::LobbyScene] = loadLobbyScene();
|
||||
gameState.loadedScenes[GameState::SceneID::ResumeLobbyScene] = loadResumeLobbyScene();
|
||||
gameState.loadedScenes[GameState::SceneID::HowToPlayScene] = loadHowToPlayScene();
|
||||
}
|
||||
|
||||
@@ -164,6 +171,7 @@ namespace BBM
|
||||
Runner::loadScenes();
|
||||
wal.changeScene(Runner::gameState.loadedScenes[GameState::SceneID::SplashScreen]);
|
||||
wal.run<GameState>(Runner::updateState, Runner::gameState);
|
||||
gameState.loadedScenes.clear();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
#include "Models/GameState.hpp"
|
||||
#include "Wal.hpp"
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include "Component/Sound/SoundComponent.hpp"
|
||||
|
||||
@@ -15,7 +16,14 @@ namespace BBM
|
||||
//! @brief Has the map heights or is it disabled?
|
||||
static bool hasHeights;
|
||||
|
||||
//! @brief store current scenes information
|
||||
//! @brief the width of the map
|
||||
static int mapWidth;
|
||||
//! @brief the height of the map
|
||||
static int mapHeight;
|
||||
//! @brief timer duration
|
||||
static std::chrono::nanoseconds timerDelay;
|
||||
|
||||
//! @brief store current scenes informations
|
||||
static GameState gameState;
|
||||
//! @brief Start the game and run a Bomberman.
|
||||
//! @return 0 on success, another value on error.
|
||||
@@ -55,6 +63,9 @@ namespace BBM
|
||||
//! @brief load all data related to lobby screen
|
||||
static std::shared_ptr<WAL::Scene> loadLobbyScene();
|
||||
|
||||
//! @brief load all data related to resume lobby screen
|
||||
static std::shared_ptr<WAL::Scene> loadResumeLobbyScene();
|
||||
|
||||
//! @brief Create a player (without any controllable) and add it to the scene.
|
||||
//! @param scene The scene where to player should reside.
|
||||
//! @return A reference to the created player.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "ControllableSystem.hpp"
|
||||
#include "Component/Movable/MovableComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
#include "Component/Speed/SpeedComponent.hpp"
|
||||
#include "Component/Health/HealthComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
@@ -17,8 +18,10 @@ namespace BBM
|
||||
void ControllableSystem::onFixedUpdate(WAL::ViewEntity<ControllableComponent, MovableComponent> &entity)
|
||||
{
|
||||
auto &controllable = entity.get<ControllableComponent>();
|
||||
// todo check why the .get doesn't work
|
||||
auto &speed = entity->getComponent<SpeedComponent>();
|
||||
auto &movable = entity.get<MovableComponent>();
|
||||
Vector2f move = controllable.move.normalized() * controllable.speed;
|
||||
Vector2f move = controllable.move.normalized() * speed.speed;
|
||||
|
||||
movable.addForce(Vector3f(move.x, 0, move.y));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Component/Renderer/Drawable2DComponent.hpp"
|
||||
#include "System/Lobby/LobbySystem.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
#include "Component/Speed/SpeedComponent.hpp"
|
||||
#include "System/MenuControllable/MenuControllableSystem.hpp"
|
||||
#include "Component/Tag/TagComponent.hpp"
|
||||
#include <algorithm>
|
||||
@@ -15,12 +16,13 @@
|
||||
#include "Component/IAControllable/IAControllableComponent.hpp"
|
||||
#include <Component/Position/PositionComponent.hpp>
|
||||
#include <Component/Renderer/Drawable3DComponent.hpp>
|
||||
#include <Drawables/2D/Text.hpp>
|
||||
#include <Map/Map.hpp>
|
||||
#include <Component/BombHolder/BombHolderComponent.hpp>
|
||||
#include <Parser/ParserYaml.hpp>
|
||||
#include <Drawables/2D/Text.hpp>
|
||||
#include "Component/Color/ColorComponent.hpp"
|
||||
#include "Component/Stat/StatComponent.hpp"
|
||||
#include "Component/Bonus/PlayerBonusComponent.hpp"
|
||||
#include "Component/BombHolder/BombHolderComponent.hpp"
|
||||
|
||||
namespace RAY3D = RAY::Drawables::Drawables3D;
|
||||
namespace RAY2D = RAY::Drawables::Drawables2D;
|
||||
@@ -179,7 +181,7 @@ namespace BBM
|
||||
});
|
||||
}
|
||||
|
||||
void LobbySystem::_addController(WAL::Entity &player, ControllableComponent::Layout layout)
|
||||
void LobbySystem::addController(WAL::Entity &player, ControllableComponent::Layout layout)
|
||||
{
|
||||
switch (layout) {
|
||||
case ControllableComponent::KEYBOARD_0:
|
||||
@@ -207,35 +209,18 @@ namespace BBM
|
||||
player.getComponent<ControllableComponent>().layout = layout;
|
||||
}
|
||||
|
||||
void LobbySystem::switchToGame(WAL::Wal &wal)
|
||||
void LobbySystem::createTile(std::shared_ptr<WAL::Scene> scene, WAL::Entity &player, int color, int playerCount)
|
||||
{
|
||||
auto scene = Runner::loadGameScene();
|
||||
int mapWidth = 16;
|
||||
int mapHeight = 16;
|
||||
int playerCount = 0;
|
||||
|
||||
for (auto &[_, lobby] : wal.getScene()->view<LobbyComponent>()) {
|
||||
if (lobby.layout == ControllableComponent::NONE)
|
||||
continue;
|
||||
auto &player = Runner::createPlayer(*scene);
|
||||
_addController(player, lobby.layout);
|
||||
player.getComponent<PositionComponent>().position = Vector3f(mapWidth * (playerCount % 2),
|
||||
(Runner::hasHeights ? 1.01 : 0),
|
||||
mapHeight * (!(playerCount % 3)));
|
||||
auto *model = dynamic_cast<RAY3D::Model *>(player.getComponent<Drawable3DComponent>().drawable.get());
|
||||
model->setTextureToMaterial(MAP_DIFFUSE, "assets/player/textures/" + colors[lobby.color] + ".png");
|
||||
|
||||
|
||||
std::string texturePath = "assets/player/ui/" + colors[lobby.color] + ".png";
|
||||
int x = (playerCount % 2 == 0) ? 1920 - 10 - 320 : 10;
|
||||
int y = (playerCount % 3 != 0) ? 1080 - 10 - 248 : 10;
|
||||
scene->addEntity("player color tile")
|
||||
std::string texturePath = "assets/player/ui/" + colors[color] + ".png";
|
||||
int x = (playerCount % 2 == 0) ? 1920 - 10 - 320 : 10;
|
||||
int y = (playerCount % 3 != 0) ? 1080 - 10 - 248 : 10;
|
||||
scene->addEntity("player color tile")
|
||||
.addComponent<PositionComponent>(x, y - 2, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Rectangle>(x, y, 320, 248, _rayColors[lobby.color]);
|
||||
scene->addEntity("player ui tile")
|
||||
.addComponent<Drawable2DComponent, RAY2D::Rectangle>(x, y, 320, 248, RAY::Color(_rayColors[color]).setA(150));
|
||||
scene->addEntity("player ui tile")
|
||||
.addComponent<PositionComponent>(x, y, 0)
|
||||
.addComponent<Drawable2DComponent, RAY::Texture>(texturePath);
|
||||
scene->addEntity("player hide fireup")
|
||||
scene->addEntity("player hide fireup")
|
||||
.addComponent<PositionComponent>(x + 220, y + 35, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("", 20, x, y, WHITE)
|
||||
.addComponent<StatComponent>([&player](Drawable2DComponent &drawble) {
|
||||
@@ -248,7 +233,7 @@ namespace BBM
|
||||
return;
|
||||
text->setText(std::to_string(static_cast<int>(bonus->explosionRadius)));
|
||||
});
|
||||
scene->addEntity("player hide bombup")
|
||||
scene->addEntity("player hide bombup")
|
||||
.addComponent<PositionComponent>(x + 220, y + 77, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("", 20, x, y, WHITE)
|
||||
.addComponent<StatComponent>([&player](Drawable2DComponent &drawble) {
|
||||
@@ -261,20 +246,20 @@ namespace BBM
|
||||
return;
|
||||
text->setText(std::to_string(bonus->bombCount) + " / " + std::to_string(bonus->maxBombCount));
|
||||
});
|
||||
scene->addEntity("player hide speedup")
|
||||
scene->addEntity("player hide speedup")
|
||||
.addComponent<PositionComponent>(x + 220, y + 122, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("", 20, x, y, WHITE)
|
||||
.addComponent<StatComponent>([&player](Drawable2DComponent &drawble) {
|
||||
const ControllableComponent *bonus = player.tryGetComponent<ControllableComponent>();
|
||||
auto *speed = player.tryGetComponent<SpeedComponent>();
|
||||
|
||||
if (!bonus)
|
||||
if (!speed)
|
||||
return;
|
||||
RAY2D::Text *text = dynamic_cast<RAY2D::Text *>(drawble.drawable.get());
|
||||
if (!text)
|
||||
return;
|
||||
text->setText(std::to_string(static_cast<int>(bonus->speed * 100)));
|
||||
text->setText(std::to_string(static_cast<int>(speed->speed * 100)));
|
||||
});
|
||||
scene->addEntity("player hide wall")
|
||||
scene->addEntity("player hide wall")
|
||||
.addComponent<PositionComponent>(x + 220, y + 161, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("", 20, x, y, WHITE)
|
||||
.addComponent<StatComponent>([&player](Drawable2DComponent &drawble) {
|
||||
@@ -287,9 +272,31 @@ namespace BBM
|
||||
return;
|
||||
text->setText(bonus->isNoClipOn ? "YES" : "NO");
|
||||
});
|
||||
}
|
||||
|
||||
void LobbySystem::switchToGame(WAL::Wal &wal)
|
||||
{
|
||||
auto scene = Runner::loadGameScene();
|
||||
int mapWidth = Runner::mapWidth;
|
||||
int mapHeight = Runner::mapHeight;
|
||||
int playerCount = 0;
|
||||
|
||||
for (auto &[_, lobby] : wal.getScene()->view<LobbyComponent>()) {
|
||||
if (lobby.layout == ControllableComponent::NONE)
|
||||
continue;
|
||||
auto &player = Runner::createPlayer(*scene);
|
||||
player.getComponent<PositionComponent>().position = Vector3f(mapWidth * (playerCount % 2),
|
||||
(Runner::hasHeights ? 1.01 : 0),
|
||||
mapHeight * (!(playerCount % 3)));
|
||||
auto *model = dynamic_cast<RAY3D::Model *>(player.getComponent<Drawable3DComponent>().drawable.get());
|
||||
model->setTextureToMaterial(MAP_DIFFUSE, "assets/player/textures/" + colors[lobby.color] + ".png");
|
||||
|
||||
addController(player, lobby.layout);
|
||||
createTile(scene, player, lobby.color, playerCount);
|
||||
playerCount++;
|
||||
}
|
||||
Runner::gameState.loadedScenes[GameState::SceneID::GameScene] = scene;
|
||||
MapGenerator::loadMap(Runner::mapWidth, Runner::mapHeight, MapGenerator::createMap(Runner::mapWidth, Runner::mapHeight, Runner::hasHeights), scene);
|
||||
Runner::gameState.nextScene = BBM::GameState::SceneID::GameScene;
|
||||
wal.getSystem<LobbySystem>().unloadLobby();
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ namespace BBM
|
||||
class LobbySystem : public WAL::System<LobbyComponent, Drawable2DComponent>
|
||||
{
|
||||
private:
|
||||
//! @brief Add a controller for the player.
|
||||
static void _addController(WAL::Entity &player, ControllableComponent::Layout layout);
|
||||
|
||||
void _nextColor(WAL::ViewEntity<LobbyComponent, Drawable2DComponent> &entity);
|
||||
|
||||
@@ -29,6 +27,12 @@ namespace BBM
|
||||
public:
|
||||
static std::array<std::string, 4> colors;
|
||||
|
||||
//! @brief Add a controller for the player.
|
||||
static void addController(WAL::Entity &player, ControllableComponent::Layout layout);
|
||||
|
||||
//! @brief Create ingame tile
|
||||
static void createTile(std::shared_ptr<WAL::Scene> scene, WAL::Entity &player, int color, int playerCount);
|
||||
|
||||
//! @inherit
|
||||
void onUpdate(WAL::ViewEntity<LobbyComponent, Drawable2DComponent> &entity, std::chrono::nanoseconds dtime) override;
|
||||
|
||||
|
||||
125
sources/System/Lobby/ResumeLobbySystem.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// Created by Zoe Roux on 6/11/21.
|
||||
//
|
||||
|
||||
#include "System/Event/EventSystem.hpp"
|
||||
#include "Component/Renderer/Drawable2DComponent.hpp"
|
||||
#include "System/Lobby/ResumeLobbySystem.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
#include "Component/Speed/SpeedComponent.hpp"
|
||||
#include "System/MenuControllable/MenuControllableSystem.hpp"
|
||||
#include "Component/Tag/TagComponent.hpp"
|
||||
#include <algorithm>
|
||||
#include <Runner/Runner.hpp>
|
||||
#include <Component/Keyboard/KeyboardComponent.hpp>
|
||||
#include <Component/Gamepad/GamepadComponent.hpp>
|
||||
#include "Component/IAControllable/IAControllableComponent.hpp"
|
||||
#include <Component/Position/PositionComponent.hpp>
|
||||
#include <Component/Renderer/Drawable3DComponent.hpp>
|
||||
#include <Map/Map.hpp>
|
||||
#include <Component/BombHolder/BombHolderComponent.hpp>
|
||||
#include <Parser/ParserYaml.hpp>
|
||||
#include <Drawables/2D/Text.hpp>
|
||||
#include "Component/Color/ColorComponent.hpp"
|
||||
#include "Component/Stat/StatComponent.hpp"
|
||||
#include "Component/Bonus/PlayerBonusComponent.hpp"
|
||||
#include "System/Lobby/LobbySystem.hpp"
|
||||
|
||||
namespace RAY3D = RAY::Drawables::Drawables3D;
|
||||
namespace RAY2D = RAY::Drawables::Drawables2D;
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
ResumeLobbySystem::ResumeLobbySystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void ResumeLobbySystem::onUpdate(WAL::ViewEntity<ResumeLobbyComponent, Drawable2DComponent> &entity, std::chrono::nanoseconds dtime)
|
||||
{
|
||||
auto &lobby = entity.get<ResumeLobbyComponent>();
|
||||
|
||||
auto lastTick = std::chrono::steady_clock::now();
|
||||
if (lastTick - lobby.lastInput < std::chrono::milliseconds(150))
|
||||
return;
|
||||
|
||||
if (lobby.layout == ControllableComponent::NONE) {
|
||||
for (auto &[_, ctrl] : this->_wal.getScene()->view<ControllableComponent>()) {
|
||||
auto &controller = ctrl;
|
||||
if (controller.bomb) {
|
||||
if (std::any_of(this->getView().begin(), this->getView().end(), [&controller](WAL::ViewEntity<ResumeLobbyComponent, Drawable2DComponent> &view) {
|
||||
return view.get<ResumeLobbyComponent>().layout == controller.layout;
|
||||
}))
|
||||
return;
|
||||
lobby.ready = true;
|
||||
lobby.lastInput = lastTick;
|
||||
lobby.layout = controller.layout;
|
||||
controller.bomb = false;
|
||||
this->_wal.getSystem<MenuControllableSystem>().now = lastTick;
|
||||
auto *texture = dynamic_cast<RAY::Texture *>(lobby.readyButton.getComponent<Drawable2DComponent>().drawable.get());
|
||||
if (texture)
|
||||
texture->use("assets/player/icons/ready.png");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResumeLobbySystem::onSelfUpdate(std::chrono::nanoseconds dtime)
|
||||
{
|
||||
auto &view = this->_wal.getScene()->view<TagComponent<"PlayButton">, Drawable2DComponent>();
|
||||
if (view.size() == 0)
|
||||
return;
|
||||
auto *texture = dynamic_cast<RAY::Texture *>(view.front().get<Drawable2DComponent>().drawable.get());
|
||||
if (!texture)
|
||||
return;
|
||||
if (playersAreReady(*this->_wal.getScene()))
|
||||
texture->setColor(WHITE);
|
||||
else
|
||||
texture->setColor(GRAY);
|
||||
}
|
||||
|
||||
bool ResumeLobbySystem::playersAreReady(WAL::Scene &scene)
|
||||
{
|
||||
auto &lobby = scene.view<ResumeLobbyComponent>();
|
||||
return std::all_of(lobby.begin(), lobby.end(), [](WAL::ViewEntity<ResumeLobbyComponent> &entity) {
|
||||
auto &lobbyPlayer = entity.get<ResumeLobbyComponent>();
|
||||
return lobbyPlayer.ready && lobbyPlayer.layout != ControllableComponent::NONE;
|
||||
}); }
|
||||
|
||||
void ResumeLobbySystem::resumeToGame(WAL::Wal &wal)
|
||||
{
|
||||
auto scene = Runner::gameState.loadedScenes[GameState::SceneID::GameScene];
|
||||
int countPlayer = 0;
|
||||
|
||||
for (auto &[_, lobby] : wal.getScene()->view<ResumeLobbyComponent>()) {
|
||||
if (lobby.layout == ControllableComponent::NONE)
|
||||
continue;
|
||||
auto &player = Runner::createPlayer(*scene);
|
||||
player.setName(ParserYAML::playersInfos[countPlayer].name);
|
||||
auto *position = player.tryGetComponent<PositionComponent>();
|
||||
auto *bombHolder = player.tryGetComponent<BombHolderComponent>();
|
||||
auto *model = player.tryGetComponent<Drawable3DComponent>();
|
||||
auto *speed = player.tryGetComponent<SpeedComponent>();
|
||||
if (position && bombHolder && model && speed) {
|
||||
dynamic_cast<RAY3D::Model *>(model->drawable.get())->setTextureToMaterial(MAP_DIFFUSE,
|
||||
ParserYAML::playersInfos[countPlayer].asset);
|
||||
position->position = ParserYAML::playersInfos[countPlayer].position;
|
||||
bombHolder->explosionRadius = ParserYAML::playersInfos[countPlayer].explosionRange;
|
||||
bombHolder->maxBombCount = ParserYAML::playersInfos[countPlayer].maxBombCount;
|
||||
speed->speed = ParserYAML::playersInfos[countPlayer].speed;
|
||||
}
|
||||
LobbySystem::addController(player, lobby.layout);
|
||||
LobbySystem::createTile(scene, player, lobby.playerColor, countPlayer);
|
||||
countPlayer++;
|
||||
}
|
||||
Runner::gameState.nextScene = BBM::GameState::SceneID::GameScene;
|
||||
wal.getSystem<ResumeLobbySystem>().unloadLobbyFromResume();
|
||||
}
|
||||
|
||||
void ResumeLobbySystem::unloadLobbyFromResume()
|
||||
{
|
||||
for (auto &entity : this->getView()) {
|
||||
entity->scheduleDeletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
46
sources/System/Lobby/ResumeLobbySystem.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Created by hbenjamin on 6/18/21.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "System/System.hpp"
|
||||
#include "Component/Lobby/ResumeLobbyComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
#include "Entity/Entity.hpp"
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief A system to handle Health entities.
|
||||
class ResumeLobbySystem : public WAL::System<ResumeLobbyComponent, Drawable2DComponent>
|
||||
{
|
||||
public:
|
||||
|
||||
//! @brief Add a controller for the player when we resume a game
|
||||
static void resumeToGame(WAL::Wal &wal);
|
||||
|
||||
//! @inherit
|
||||
void onUpdate(WAL::ViewEntity<ResumeLobbyComponent, Drawable2DComponent> &entity, std::chrono::nanoseconds dtime) override;
|
||||
|
||||
//! @inherit
|
||||
void onSelfUpdate(std::chrono::nanoseconds dtime) override;
|
||||
|
||||
//! @brief Check if every player is ready.
|
||||
//! @param scene The lobby scene containing lobby players.
|
||||
static bool playersAreReady(WAL::Scene &scene);
|
||||
|
||||
//! @brief Reset the resume lobby scene to it's default state.
|
||||
void unloadLobbyFromResume();
|
||||
|
||||
//! @brief A default constructor
|
||||
explicit ResumeLobbySystem(WAL::Wal &wal);
|
||||
//! @brief A Lobby system is copy constructable
|
||||
ResumeLobbySystem(const ResumeLobbySystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~ResumeLobbySystem() override = default;
|
||||
//! @brief A system is not assignable.
|
||||
ResumeLobbySystem &operator=(const ResumeLobbySystem &) = delete;
|
||||
};
|
||||
}
|
||||
@@ -32,12 +32,12 @@ namespace BBM
|
||||
.addComponent<PositionComponent>(1920 / 2 - 2 * 30 - 20, 28, 0)
|
||||
.addComponent<Drawable2DComponent, RAY2D::Rectangle>(Vector2f(), Vector2f(150, 60), RAY::Color(BLACK).setA(150));
|
||||
this->_wal.getScene()->scheduleNewEntity("Timer")
|
||||
.addComponent<TimerComponent>(std::chrono::minutes (3), [](WAL::Entity &, WAL::Wal &engine) {
|
||||
.addComponent<TimerComponent>(Runner::timerDelay, [](WAL::Entity &, WAL::Wal &engine) {
|
||||
engine.getSystem<CameraSystem>().hasEnded = false;
|
||||
Runner::gameState.nextScene = GameState::ScoreScene;
|
||||
})
|
||||
.addComponent<TagComponent<"Timer">>()
|
||||
.addComponent<PositionComponent>(1920 / 2 - 2 * 30, 30, 0)
|
||||
.addComponent<TagComponent<Timer>>()
|
||||
.addComponent<Drawable2DComponent, RAY2D::Text>("", 60, RAY::Vector2(), ORANGE);
|
||||
for (WAL::Entity &player : this->_wal.getScene()->view<TagComponent<Player>>())
|
||||
player.getComponent<ControllableComponent>().disabled = false;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace BBM
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void TimerUISystem::onUpdate(WAL::ViewEntity<TimerComponent, Drawable2DComponent> &entity, std::chrono::nanoseconds dtime)
|
||||
void TimerUISystem::onUpdate(WAL::ViewEntity<TimerComponent, Drawable2DComponent, TagComponent<Timer>> &entity, std::chrono::nanoseconds dtime)
|
||||
{
|
||||
auto &timer = entity.get<TimerComponent>();
|
||||
RAY2D::Text *text = dynamic_cast<RAY2D::Text *>(entity.get<Drawable2DComponent>().drawable.get());
|
||||
|
||||
@@ -8,22 +8,23 @@
|
||||
#include <Wal.hpp>
|
||||
#include <Component/Timer/TimerComponent.hpp>
|
||||
#include "Component/Renderer/Drawable2DComponent.hpp"
|
||||
#include "Component/Tag/TagComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
class TimerUISystem : public WAL::System<TimerComponent, Drawable2DComponent>
|
||||
class TimerUISystem : public WAL::System<TimerComponent, Drawable2DComponent, TagComponent<Timer>>
|
||||
{
|
||||
public:
|
||||
//! @inherit
|
||||
void onUpdate(WAL::ViewEntity<TimerComponent, Drawable2DComponent> &entity, std::chrono::nanoseconds dtime) override;
|
||||
void onUpdate(WAL::ViewEntity<TimerComponent, Drawable2DComponent, TagComponent<Timer>> &entity, std::chrono::nanoseconds dtime) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
TimerUISystem(WAL::Wal &);
|
||||
explicit TimerUISystem(WAL::Wal &);
|
||||
//! @brief A timer system is copy constructable.
|
||||
TimerUISystem(const TimerUISystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~TimerUISystem() override = default;
|
||||
//! @breief A timer system is assignable.
|
||||
TimerUISystem &operator=(const TimerUISystem &) = default;
|
||||
TimerUISystem &operator=(const TimerUISystem &) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
102
sources/Utils/Utils.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// Created by cbihan on 17/06/2021.
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
void Utils::lTrim(std::string &s)
|
||||
{
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
}));
|
||||
}
|
||||
|
||||
void Utils::rTrim(std::string &s)
|
||||
{
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
}).base(), s.end());
|
||||
}
|
||||
|
||||
void Utils::trim(std::string &s)
|
||||
{
|
||||
lTrim(s);
|
||||
rTrim(s);
|
||||
}
|
||||
|
||||
std::string Utils::lTrimCopy(std::string s)
|
||||
{
|
||||
lTrim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string Utils::rTrimCopy(std::string s)
|
||||
{
|
||||
rTrim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string Utils::trimCopy(std::string s)
|
||||
{
|
||||
trim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
int Utils::findFrequency(const std::string &s, const std::string &pattern)
|
||||
{
|
||||
std::regex c(pattern);
|
||||
std::smatch m;
|
||||
|
||||
ptrdiff_t numberOfMatches = std::distance(std::sregex_iterator(s.begin(), s.end(), c), std::sregex_iterator());
|
||||
return static_cast<int>(numberOfMatches);
|
||||
}
|
||||
|
||||
bool Utils::tryParseInteger(const std::string &s, int &i)
|
||||
{
|
||||
std::istringstream iss(s);
|
||||
|
||||
iss >> std::noskipws >> i;
|
||||
return iss.eof() && !iss.fail();
|
||||
}
|
||||
|
||||
bool Utils::tryParseFloat(const std::string &s, float &f)
|
||||
{
|
||||
std::istringstream iss(s);
|
||||
|
||||
iss >> std::noskipws >> f;
|
||||
return iss.eof() && !iss.fail();
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::splitStr(const std::string &str, char delim)
|
||||
{
|
||||
std::vector<std::string> strings;
|
||||
std::istringstream f(str);
|
||||
std::string buffer;
|
||||
|
||||
while (std::getline(f, buffer, delim)) {;
|
||||
strings.push_back(buffer);
|
||||
}
|
||||
if (str.back() == delim) {
|
||||
strings.emplace_back("");
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
bool Utils::tryParseLong(const std::string &s, long &l)
|
||||
{
|
||||
std::istringstream iss(s);
|
||||
|
||||
iss >> std::noskipws >> l;
|
||||
return iss.eof() && !iss.fail();
|
||||
}
|
||||
|
||||
}
|
||||
46
sources/Utils/Utils.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Created by cbihan on 17/06/2021.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
struct Utils
|
||||
{
|
||||
//! @brief trim left end
|
||||
static void lTrim(std::string &s);
|
||||
|
||||
//! @brief trim right end
|
||||
static void rTrim(std::string &s);
|
||||
|
||||
//! @brief trim from both ends
|
||||
static void trim(std::string &s);
|
||||
|
||||
//! @brief trim left end (copying)
|
||||
static std::string lTrimCopy(std::string s);
|
||||
|
||||
//! @brief trim right end (copying)
|
||||
static std::string rTrimCopy(std::string s);
|
||||
|
||||
//! @brief trim from both ends (copying)
|
||||
static std::string trimCopy(std::string s);
|
||||
|
||||
//! @brief find the frequency of a substring in a string
|
||||
static int findFrequency(const std::string &s, const std::string &pattern);
|
||||
|
||||
//! @brief return true if parsing has been successful result ill be in i
|
||||
static bool tryParseInteger(const std::string &s, int &i);
|
||||
|
||||
//! @brief return true if parsing has been successful result ill be in f
|
||||
static bool tryParseFloat(const std::string &s, float &f);
|
||||
|
||||
//! @brief return true if parsing has been successful result ill be in l
|
||||
static bool tryParseLong(const std::string &s, long &l);
|
||||
|
||||
//! @brief split a string with a delim char
|
||||
static std::vector<std::string> splitStr(const std::string &str, char delim);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "System/Movable/MovableSystem.hpp"
|
||||
#include <Component/Controllable/ControllableComponent.hpp>
|
||||
#include <Component/Movable/MovableComponent.hpp>
|
||||
#include <Component/Speed/SpeedComponent.hpp>
|
||||
|
||||
using namespace WAL;
|
||||
using namespace BBM;
|
||||
@@ -24,6 +25,7 @@ TEST_CASE("Move test", "[Component][System]")
|
||||
wal.getScene()->addEntity("player")
|
||||
.addComponent<ControllableComponent>()
|
||||
.addComponent<MovableComponent>()
|
||||
.addComponent<SpeedComponent>()
|
||||
.addComponent<PositionComponent>();
|
||||
Entity &entity = wal.getScene()->getEntities().front();
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ TEST_CASE("View add entity", "[View]")
|
||||
.addComponent<PositionComponent>();
|
||||
scene.applyChanges();
|
||||
REQUIRE(scene.view<PositionComponent>().size() == 2);
|
||||
(void)entity;
|
||||
}
|
||||
|
||||
TEST_CASE("View remove entity", "[View]")
|
||||
@@ -75,6 +76,7 @@ TEST_CASE("View remove entity", "[View]")
|
||||
REQUIRE(scene.view<PositionComponent>().size() == 0);
|
||||
for (auto &it : scene.view<PositionComponent>())
|
||||
REQUIRE(false);
|
||||
(void)scene;
|
||||
}
|
||||
|
||||
TEST_CASE("View cache switch", "[View]")
|
||||
|
||||