mirror of
https://github.com/zoriya/Bomberman.git
synced 2026-05-28 00:31:50 +00:00
Merge pull request #51 from AnonymusRaccoon/ecs
Updating dependencies management, adding a callback
This commit is contained in:
@@ -23,6 +23,9 @@ jobs:
|
||||
if: matrix.name == 'Linux'
|
||||
run: |
|
||||
sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev
|
||||
- name: Update G++
|
||||
if: matrix.name == 'Linux'
|
||||
run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
|
||||
@@ -13,6 +13,8 @@ jobs:
|
||||
- name: Install Xorg lib
|
||||
run: |
|
||||
sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev
|
||||
- name: Update G++
|
||||
run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
|
||||
@@ -9,12 +9,8 @@ add_library(wal
|
||||
sources/System/System.hpp
|
||||
sources/Wal.cpp
|
||||
sources/Wal.hpp
|
||||
sources/Scene/SceneManager.cpp
|
||||
sources/Scene/SceneManager.hpp
|
||||
sources/Scene/Scene.cpp
|
||||
sources/Scene/Scene.hpp
|
||||
sources/Events/EventManager.cpp
|
||||
sources/Events/EventManager.hpp
|
||||
sources/Exception/WalError.cpp
|
||||
sources/Exception/WalError.hpp
|
||||
sources/Entity/Entity.cpp
|
||||
@@ -27,6 +23,7 @@ add_library(wal
|
||||
sources/System/Movable/MovableSystem.cpp
|
||||
sources/System/Movable/MovableSystem.hpp
|
||||
sources/System/System.cpp
|
||||
sources/Models/Callback.hpp
|
||||
)
|
||||
|
||||
target_include_directories(wal PUBLIC sources)
|
||||
@@ -35,6 +32,7 @@ add_executable(wal_tests EXCLUDE_FROM_ALL
|
||||
tests/EntityTests.cpp
|
||||
tests/MainTest.cpp
|
||||
tests/EngineTests.cpp
|
||||
tests/CallbackTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(wal_tests PRIVATE wal)
|
||||
|
||||
@@ -20,11 +20,6 @@ namespace WAL
|
||||
this->_disabled = disabled;
|
||||
}
|
||||
|
||||
const std::vector<std::type_index> &Component::getDependencies() const
|
||||
{
|
||||
return this->_dependencies;
|
||||
}
|
||||
|
||||
void Component::onStart()
|
||||
{
|
||||
//TODO handle events here
|
||||
|
||||
@@ -22,8 +22,6 @@ namespace WAL
|
||||
protected:
|
||||
//! @brief The entity that own this component
|
||||
Entity &_entity;
|
||||
//! @brief The list of dependencies of this component.
|
||||
std::vector<std::type_index> _dependencies;
|
||||
|
||||
//! @brief A component can't be instantiated, it should be derived.
|
||||
explicit Component(Entity &entity);
|
||||
@@ -44,9 +42,6 @@ namespace WAL
|
||||
//! @brief Disable this component.
|
||||
void setDisable(bool disabled);
|
||||
|
||||
//! @brief Get the dependencies of this component.
|
||||
const std::vector<std::type_index> &getDependencies() const;
|
||||
|
||||
//! @brief The entity or this component has just been enabled.
|
||||
virtual void onStart();
|
||||
|
||||
|
||||
@@ -59,4 +59,12 @@ namespace WAL
|
||||
});
|
||||
return existing != this->_components.end();
|
||||
}
|
||||
|
||||
bool Entity::hasComponent(const std::type_index &type) const
|
||||
{
|
||||
auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) {
|
||||
return std::type_index(typeid(*cmp)) == type;
|
||||
});
|
||||
return existing != this->_components.end();
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,10 @@ namespace WAL
|
||||
//! @param type The type of the component
|
||||
bool hasComponent(const std::type_info &type) const;
|
||||
|
||||
//! @brief Check if this entity has a component.
|
||||
//! @param type The type of the component
|
||||
bool hasComponent(const std::type_index &type) const;
|
||||
|
||||
//! @brief Add a component to this entity. The component is constructed in place.
|
||||
//! @throw DuplicateError is thrown if a component with the same type already exist.
|
||||
//! @return This entity is returned
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-05-14.
|
||||
//
|
||||
|
||||
#include "EventManager.hpp"
|
||||
@@ -1,15 +0,0 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-05-14.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
//! @brief A class to handle events.
|
||||
class EventManager
|
||||
{
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Created by Zoe Roux on 5/21/21.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
//! @brief A callback where you can subscribe to and emit it.
|
||||
template<typename ...Types>
|
||||
class Callback
|
||||
{
|
||||
private:
|
||||
int _nextID = 0;
|
||||
//! @brief The list of functions to call.
|
||||
std::unordered_map<int, std::function<void (Types...)>> _functions = {};
|
||||
|
||||
public:
|
||||
//! @brief Add a method to be called when this callback is invoked.
|
||||
//! @param callback The list of arguments of the callback method
|
||||
//! @return A unique ID for this callback. That can be used to remove the callback later.
|
||||
int addCallback(std::function<void (Types...)> callback)
|
||||
{
|
||||
int id = this->_nextID++;
|
||||
this->_functions[id] = std::move(callback);
|
||||
return id;
|
||||
}
|
||||
|
||||
//! @brief Remove a function from this callback.
|
||||
//! @param id The ID of the function.
|
||||
void removeCallback(int id)
|
||||
{
|
||||
this->_functions.erase(id);
|
||||
}
|
||||
|
||||
void operator()(Types ...args) const
|
||||
{
|
||||
for (const auto &[_, callback] : this->_functions)
|
||||
callback(args...);
|
||||
}
|
||||
|
||||
//! @brief A default constructor
|
||||
Callback() = default;
|
||||
//! @brief A default copy constructor
|
||||
Callback(const Callback &) = default;
|
||||
//! @brief A default destructor
|
||||
~Callback() = default;
|
||||
//! @brief A default assignment operator
|
||||
Callback &operator=(const Callback &) = default;
|
||||
};
|
||||
}
|
||||
@@ -23,12 +23,12 @@ namespace WAL
|
||||
T z;
|
||||
|
||||
//! @brief Create a new nil vector3.
|
||||
Vector3<T>()
|
||||
Vector3()
|
||||
: x(0), y(0), z(0)
|
||||
{}
|
||||
|
||||
//! @brief Create a new vector3 representing a specific coordinate.
|
||||
Vector3<T>(T x, T y, T z)
|
||||
Vector3(T x, T y, T z)
|
||||
: x(x), y(y), z(z)
|
||||
{}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "Entity/Entity.hpp"
|
||||
|
||||
namespace WAL
|
||||
@@ -15,9 +16,27 @@ namespace WAL
|
||||
{
|
||||
private:
|
||||
//! @brief The list of registered entities
|
||||
std::vector<Entity> _entities;
|
||||
std::vector<Entity> _entities = {};
|
||||
public:
|
||||
//! @brief Get the list of entities.
|
||||
std::vector<Entity> &getEntities();
|
||||
|
||||
//! @brief Add a new entity to the scene, you can use this method with the same arguments as the entity's constructor.
|
||||
//! @return The current scene is returned to allow you to chain call.
|
||||
template <class ...Params>
|
||||
Scene &addEntity(Params ...params)
|
||||
{
|
||||
this->_entities.emplace_back(params...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief A default constructor
|
||||
Scene() = default;
|
||||
//! @brief A scene is copy constructable
|
||||
Scene(const Scene &) = default;
|
||||
//! @brief A default destructor
|
||||
~Scene() = default;
|
||||
//! @brief A scene is assignable
|
||||
Scene &operator=(const Scene &) = default;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-05-14.
|
||||
//
|
||||
|
||||
#include "SceneManager.hpp"
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
SceneManager &WAL::SceneManager::addScene(WAL::Scene &&scene)
|
||||
{
|
||||
this->_scenes.push_front(scene);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SceneManager &SceneManager::addBackScene(Scene &&scene)
|
||||
{
|
||||
this->_scenes.insert(++this->_scenes.begin(), scene);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Scene &SceneManager::getCurrent()
|
||||
{
|
||||
if (this->_scenes.empty())
|
||||
throw NotFoundError("No scene exists.");
|
||||
return this->_scenes.front();
|
||||
}
|
||||
|
||||
SceneManager &SceneManager::closeCurrent()
|
||||
{
|
||||
this->_scenes.pop_front();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-05-14.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include "Scene/Scene.hpp"
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
//! @brief A class to manage scenes
|
||||
class SceneManager
|
||||
{
|
||||
private:
|
||||
std::deque<Scene> _scenes = {};
|
||||
public:
|
||||
//! @brief Add a scene to the container and move to it.
|
||||
//! @return The manager instance used to call this function is returned. This allow method chaining.
|
||||
SceneManager &addScene(Scene &&scene);
|
||||
|
||||
//! @brief Add a scene before the current scene. This could be useful for lobbies or scene where the next scene can be constructed.
|
||||
//! @return The manager instance used to call this function is returned. This allow method chaining.
|
||||
SceneManager &addBackScene(Scene &&scene);
|
||||
|
||||
//! @breif Get the current scene
|
||||
Scene &getCurrent();
|
||||
|
||||
//! @brief Remove the current scene and switch to the previous scene on the stack.
|
||||
//! @return The manager instance used to call this function is returned. This allow method chaining.
|
||||
SceneManager &closeCurrent();
|
||||
|
||||
//! @brief A default constructor
|
||||
SceneManager() = default;
|
||||
//! @brief A scene manager is copy constructable
|
||||
SceneManager(const SceneManager &) = default;
|
||||
//! @brief A default destructor.
|
||||
~SceneManager() = default;
|
||||
//! @brief A scene manager is assignable
|
||||
SceneManager &operator=(const SceneManager &) = default;
|
||||
};
|
||||
}
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
const std::type_info &MovableSystem::getComponent() const
|
||||
{
|
||||
return typeid(MovableComponent);
|
||||
}
|
||||
MovableSystem::MovableSystem()
|
||||
: System({
|
||||
typeid(MovableComponent),
|
||||
typeid(PositionComponent)
|
||||
})
|
||||
{}
|
||||
|
||||
void MovableSystem::onFixedUpdate(Entity &entity)
|
||||
{
|
||||
|
||||
@@ -13,13 +13,11 @@ namespace WAL
|
||||
class MovableSystem : public System
|
||||
{
|
||||
public:
|
||||
//! @inherit
|
||||
const std::type_info &getComponent() const override;
|
||||
//! @inherit
|
||||
void onFixedUpdate(Entity &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
MovableSystem() = default;
|
||||
MovableSystem();
|
||||
//! @brief A movable system is copy constructable
|
||||
MovableSystem(const MovableSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
|
||||
#include "System.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
System::System(std::vector<std::type_index> dependencies)
|
||||
: _dependencies(std::move(dependencies))
|
||||
{}
|
||||
|
||||
void System::onUpdate(Entity &entity, std::chrono::nanoseconds dtime)
|
||||
{}
|
||||
@@ -15,4 +20,9 @@ namespace WAL
|
||||
|
||||
void System::onSelfUpdate()
|
||||
{}
|
||||
|
||||
const std::vector<std::type_index> &System::getDependencies() const
|
||||
{
|
||||
return this->_dependencies;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,9 @@ namespace WAL
|
||||
//! @brief A base system of WAL
|
||||
class System
|
||||
{
|
||||
private:
|
||||
//! @brief The list of dependencies of this system
|
||||
std::vector<std::type_index> _dependencies = {};
|
||||
public:
|
||||
//! @brief A virtual, default, destructor
|
||||
virtual ~System() = default;
|
||||
@@ -19,8 +22,8 @@ namespace WAL
|
||||
System(System &&) = default;
|
||||
|
||||
//! @brief Get the name of the component corresponding to this system.
|
||||
virtual const std::type_info &getComponent() const = 0;
|
||||
|
||||
const std::vector<std::type_index> &getDependencies() const;
|
||||
|
||||
//! @brief Update the corresponding component of the given entity
|
||||
//! @param entity The entity to update.
|
||||
//! @param dtime The delta time.
|
||||
@@ -35,7 +38,7 @@ namespace WAL
|
||||
virtual void onSelfUpdate();
|
||||
protected:
|
||||
//! @brief A system can't be instantiated, it should be derived.
|
||||
System() = default;
|
||||
explicit System(std::vector<std::type_index> dependencies);
|
||||
//! @brief A system can't be instantiated, it should be derived.
|
||||
System(const System &) = default;
|
||||
//! @brief A system can't be instantiated, it should be derived.
|
||||
|
||||
+14
-13
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include "Wal.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
@@ -11,11 +12,6 @@ namespace WAL
|
||||
{
|
||||
std::chrono::nanoseconds Wal::timestep = 8ms;
|
||||
|
||||
SceneManager &Wal::getSceneManager()
|
||||
{
|
||||
return this->_sceneManager;
|
||||
}
|
||||
|
||||
void Wal::run()
|
||||
{
|
||||
auto lastTick = std::chrono::steady_clock::now();
|
||||
@@ -37,14 +33,12 @@ namespace WAL
|
||||
|
||||
void Wal::_update(std::chrono::nanoseconds dtime)
|
||||
{
|
||||
auto &entities = this->_sceneManager.getCurrent().getEntities();
|
||||
auto &entities = this->_scene.getEntities();
|
||||
|
||||
for (auto &system : this->_systems) {
|
||||
for (auto &entity : entities) {
|
||||
const auto &cmp = system->getComponent();
|
||||
if (!entity.hasComponent(cmp))
|
||||
if (!Wal::_hasDependencies(entity, *system))
|
||||
continue;
|
||||
// TODO handle dependencies.
|
||||
system->onUpdate(entity, dtime);
|
||||
}
|
||||
system->onSelfUpdate();
|
||||
@@ -53,16 +47,23 @@ namespace WAL
|
||||
|
||||
void Wal::_fixedUpdate()
|
||||
{
|
||||
auto &entities = this->_sceneManager.getCurrent().getEntities();
|
||||
auto &entities = this->_scene.getEntities();
|
||||
|
||||
for (auto &system : this->_systems) {
|
||||
for (auto &entity : entities) {
|
||||
auto &cmp = system->getComponent();
|
||||
if (!entity.hasComponent(cmp))
|
||||
if (!Wal::_hasDependencies(entity, *system))
|
||||
continue;
|
||||
// TODO handle dependencies.
|
||||
system->onFixedUpdate(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Wal::_hasDependencies(const Entity &entity, const System &system)
|
||||
{
|
||||
// TODO use an hashmap to cache results.
|
||||
const auto &dependency = system.getDependencies();
|
||||
return std::ranges::all_of(dependency.begin(), dependency.end(), [&entity](const auto &dependency) {
|
||||
return entity.hasComponent(dependency);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,7 @@
|
||||
#include <memory>
|
||||
#include <typeinfo>
|
||||
#include <Exception/WalError.hpp>
|
||||
#include "Events/EventManager.hpp"
|
||||
#include "Scene/SceneManager.hpp"
|
||||
#include "Scene/Scene.hpp"
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "System/System.hpp"
|
||||
|
||||
@@ -21,9 +20,7 @@ namespace WAL
|
||||
{
|
||||
private:
|
||||
//! @brief The scene manager that allow multiple scene to work together.
|
||||
SceneManager _sceneManager;
|
||||
//! @brief The event manager
|
||||
EventManager _eventManager;
|
||||
Scene _scene;
|
||||
//! @brief The list of registered systems
|
||||
std::vector<std::unique_ptr<System>> _systems = {};
|
||||
//! @brief True if the engine should close after the end of the current tick.
|
||||
@@ -34,6 +31,12 @@ namespace WAL
|
||||
|
||||
//! @brief Call the onFixedUpdate of every system with every component
|
||||
void _fixedUpdate();
|
||||
|
||||
//! @brief Check if an entity met a system's dependencies.
|
||||
//! @param entity The entity to check
|
||||
//! @param system The system that will list dependencies
|
||||
//! @return True if all dependencies are met, false otherwise.
|
||||
static bool _hasDependencies(const Entity &entity, const System &system);
|
||||
public:
|
||||
//! @brief The time between each fixed update.
|
||||
static std::chrono::nanoseconds timestep;
|
||||
@@ -97,9 +100,6 @@ namespace WAL
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief Get the scene manager.
|
||||
SceneManager &getSceneManager();
|
||||
|
||||
//! @brief Start the game loop
|
||||
void run();
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by Zoe Roux on 5/21/21.
|
||||
//
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Entity/Entity.hpp>
|
||||
#include "Models/Callback.hpp"
|
||||
|
||||
using namespace WAL;
|
||||
|
||||
TEST_CASE("Callback basic test", "[Callback]")
|
||||
{
|
||||
Callback<std::string> callback;
|
||||
|
||||
REQUIRE_NOTHROW(callback("1"));
|
||||
SECTION("Check add") {
|
||||
int id = callback.addCallback([](const std::string& i) {
|
||||
if (i == "Super")
|
||||
throw std::runtime_error(i);
|
||||
});
|
||||
REQUIRE_THROWS_AS(callback("Super"), std::runtime_error);
|
||||
|
||||
SECTION("Check remove") {
|
||||
REQUIRE(id == 0);
|
||||
callback.removeCallback(id);
|
||||
REQUIRE_NOTHROW(callback("Super"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Callback multiple arguments", "[Callback]")
|
||||
{
|
||||
Callback<std::string, int, unsigned *, Entity &> callback;
|
||||
|
||||
callback.addCallback([](const std::string& str, int a, unsigned *value, Entity &entity) {
|
||||
throw std::runtime_error("");
|
||||
});
|
||||
Entity entity("name");
|
||||
REQUIRE_THROWS_AS(callback("1", 0, nullptr, entity), std::runtime_error);
|
||||
}
|
||||
Reference in New Issue
Block a user