mirror of
https://github.com/zoriya/Bomberman.git
synced 2025-12-20 13:25:10 +00:00
Merge pull request #116 from AnonymusRaccoon/ecs
Views of entities and components
This commit is contained in:
@@ -85,8 +85,9 @@ add_executable(unit_tests EXCLUDE_FROM_ALL
|
||||
tests/EngineTests.cpp
|
||||
tests/CallbackTest.cpp
|
||||
tests/MoveTests.cpp
|
||||
tests/ViewTest.cpp
|
||||
tests/CollisionTest.cpp
|
||||
)
|
||||
)
|
||||
target_include_directories(unit_tests PUBLIC sources)
|
||||
target_link_libraries(unit_tests PUBLIC wal ray)
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ add_library(wal
|
||||
sources/Entity/Entity.hpp
|
||||
sources/Component/Component.hpp
|
||||
sources/System/System.hpp
|
||||
sources/Wal.cpp
|
||||
sources/Wal.hpp
|
||||
sources/Scene/Scene.cpp
|
||||
sources/Scene/Scene.hpp
|
||||
@@ -15,8 +14,10 @@ add_library(wal
|
||||
sources/Exception/WalError.hpp
|
||||
sources/Entity/Entity.cpp
|
||||
sources/Component/Component.cpp
|
||||
sources/System/System.cpp
|
||||
sources/Models/Callback.hpp
|
||||
sources/Models/TypeHolder.hpp)
|
||||
sources/View/View.hpp
|
||||
sources/System/ISystem.hpp
|
||||
sources/Models/TypeHolder.hpp
|
||||
)
|
||||
|
||||
target_include_directories(wal PUBLIC sources)
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Scene/Scene.hpp"
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -10,18 +11,20 @@ namespace WAL
|
||||
{
|
||||
unsigned Entity::nextID = 0;
|
||||
|
||||
Entity::Entity(std::string name)
|
||||
Entity::Entity(Scene &scene, std::string name)
|
||||
: _uid(Entity::nextID++),
|
||||
_scene(scene),
|
||||
_name(std::move(name))
|
||||
{ }
|
||||
|
||||
Entity::Entity(const Entity &other)
|
||||
: _uid(Entity::nextID++),
|
||||
_scene(other._scene),
|
||||
_name(other._name),
|
||||
_disabled(other._disabled)
|
||||
{
|
||||
for (const auto &cmp : other._components)
|
||||
this->addComponent(*cmp);
|
||||
this->addComponent(*cmp.second);
|
||||
}
|
||||
|
||||
unsigned Entity::getUid() const
|
||||
@@ -46,25 +49,31 @@ namespace WAL
|
||||
|
||||
Entity &Entity::addComponent(const Component &component)
|
||||
{
|
||||
if (this->hasComponent(typeid(component)))
|
||||
throw DuplicateError("A component of the type \"" + std::string(typeid(component).name()) + "\" already exists.");
|
||||
this->_components.emplace_back(component.clone(*this));
|
||||
const std::type_index &type = typeid(component);
|
||||
if (this->hasComponent(type))
|
||||
throw DuplicateError("A component of the type \"" + std::string(type.name()) + "\" already exists.");
|
||||
this->_components.emplace(type, component.clone(*this));
|
||||
this->_scene._componentAdded(*this, type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Entity::hasComponent(const std::type_info &type) const
|
||||
{
|
||||
auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) {
|
||||
return typeid(*cmp) == type;
|
||||
});
|
||||
return existing != this->_components.end();
|
||||
return this->hasComponent(static_cast<const std::type_index &>(type));
|
||||
}
|
||||
|
||||
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();
|
||||
return this->_components.contains(type);
|
||||
}
|
||||
|
||||
void Entity::_componentAdded(const std::type_index &type)
|
||||
{
|
||||
this->_scene._componentAdded(*this, type);
|
||||
}
|
||||
|
||||
void Entity::_componentRemoved(const std::type_index &type)
|
||||
{
|
||||
this->_scene._componentRemoved(*this, type);
|
||||
}
|
||||
} // namespace WAL
|
||||
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
#include "Component/Component.hpp"
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
class Scene;
|
||||
|
||||
//! @brief An entity of the WAL's ECS.
|
||||
class Entity
|
||||
{
|
||||
@@ -25,10 +27,20 @@ namespace WAL
|
||||
//! @brief Is this entity enabled?
|
||||
bool _disabled = false;
|
||||
//! @brief The list of the components of this entity
|
||||
std::vector<std::unique_ptr<Component>> _components = {};
|
||||
std::unordered_map<std::type_index, std::unique_ptr<Component>> _components = {};
|
||||
|
||||
//! @brief This ID will be the one of the next entity created.
|
||||
static unsigned nextID;
|
||||
|
||||
//! @brief Callback called when a component is added
|
||||
//! @param type The type of component
|
||||
void _componentAdded(const std::type_index &type);
|
||||
//! @brief Callback called when a component is removed
|
||||
//! @param type The type of component
|
||||
void _componentRemoved(const std::type_index &type);
|
||||
protected:
|
||||
//! @brief A reference to the ECS.
|
||||
Scene &_scene;
|
||||
public:
|
||||
//! @brief Get the ID of the entity.
|
||||
unsigned getUid() const;
|
||||
@@ -42,17 +54,55 @@ namespace WAL
|
||||
void setDisable(bool disabled);
|
||||
|
||||
//! @brief Get a component of a specific type
|
||||
//! @tparam The type of the component
|
||||
//! @throw NotFoundError if the component could not be found
|
||||
//! @return The component of the requested type.
|
||||
template<typename T>
|
||||
T &getComponent()
|
||||
{
|
||||
const std::type_info &type = typeid(T);
|
||||
auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) {
|
||||
return typeid(*cmp) == type;
|
||||
});
|
||||
T *ret = this->tryGetComponent<T>();
|
||||
if (ret == nullptr)
|
||||
throw NotFoundError("No component could be found with the type \"" + std::string(typeid(T).name()) + "\".");
|
||||
return *ret;
|
||||
}
|
||||
|
||||
//! @brief Get a component of a specific type or null if not found.
|
||||
//! @tparam The type of the component
|
||||
//! @return The component or nullptr if not found.
|
||||
template<typename T>
|
||||
T *tryGetComponent()
|
||||
{
|
||||
const std::type_index &type = typeid(T);
|
||||
auto existing = this->_components.find(type);
|
||||
if (existing == this->_components.end())
|
||||
throw NotFoundError("No component could be found with the type \"" + std::string(type.name()) + "\".");
|
||||
return *static_cast<T *>(existing->get());
|
||||
return nullptr;
|
||||
return static_cast<T *>(existing->second.get());
|
||||
}
|
||||
|
||||
//! @brief Get a component of a specific type
|
||||
//! @tparam The type of the component
|
||||
//! @throw NotFoundError if the component could not be found
|
||||
//! @return The component of the requested type.
|
||||
template<typename T>
|
||||
const T &getComponent() const
|
||||
{
|
||||
const T *ret = this->tryGetComponent<T>();
|
||||
if (ret == nullptr)
|
||||
throw NotFoundError("No component could be found with the type \"" + std::string(typeid(T).name()) + "\".");
|
||||
return *ret;
|
||||
}
|
||||
|
||||
//! @brief Get a component of a specific type or null if not found.
|
||||
//! @tparam The type of the component
|
||||
//! @return The component or nullptr if not found.
|
||||
template<typename T>
|
||||
const T *tryGetComponent() const
|
||||
{
|
||||
const std::type_index &type = typeid(T);
|
||||
auto existing = this->_components.find(type);
|
||||
if (existing == this->_components.end())
|
||||
return nullptr;
|
||||
return static_cast<T *>(existing->second.get());
|
||||
}
|
||||
|
||||
//! @brief Check if this entity has a component.
|
||||
@@ -75,24 +125,14 @@ namespace WAL
|
||||
//! @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
|
||||
template<typename T, typename ...Types>
|
||||
template<typename T, typename ...TNested, typename ...Types>
|
||||
Entity &addComponent(Types &&...params)
|
||||
{
|
||||
if (this->hasComponent<T>())
|
||||
throw DuplicateError("A component of the type \"" + std::string(typeid(T).name()) + "\" already exists.");
|
||||
this->_components.push_back(std::make_unique<T>(*this, std::forward<Types>(params)...));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @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
|
||||
template<typename T, typename TNested, typename ...Types>
|
||||
Entity &addComponent(Types &&...params)
|
||||
{
|
||||
if (this->hasComponent<T>())
|
||||
throw DuplicateError("A component of the type \"" + std::string(typeid(T).name()) + "\" already exists.");
|
||||
this->_components.push_back(std::make_unique<T>(*this, TypeHolder<TNested>(), std::forward<Types>(params)...));
|
||||
const std::type_index &type = typeid(T);
|
||||
if (this->hasComponent(type))
|
||||
throw DuplicateError("A component of the type \"" + std::string(type.name()) + "\" already exists.");
|
||||
this->_components[type] = std::make_unique<T>(*this, TypeHolder<TNested>()..., std::forward<Types>(params)...);
|
||||
this->_componentAdded(type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -107,17 +147,16 @@ namespace WAL
|
||||
Entity &removeComponent()
|
||||
{
|
||||
const std::type_info &type = typeid(T);
|
||||
auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) {
|
||||
return typeid(*cmp) == type;
|
||||
});
|
||||
auto existing = this->_components.find(type);
|
||||
if (existing == this->_components.end())
|
||||
throw NotFoundError("No component could be found with the type \"" + std::string(type.name()) + "\".");
|
||||
this->_components.erase(existing);
|
||||
this->_componentRemoved(type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief A default constructor
|
||||
explicit Entity(std::string name);
|
||||
explicit Entity(Scene &wal, std::string name);
|
||||
//! @brief An entity is copyable
|
||||
Entity(const Entity &);
|
||||
//! @brief An entity is movable.
|
||||
|
||||
@@ -24,10 +24,14 @@ namespace WAL
|
||||
//! @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)
|
||||
template<typename Func>
|
||||
int addCallback(Func callback)
|
||||
{
|
||||
int id = this->_nextID++;
|
||||
if constexpr(std::is_same_v<Func, std::function<void (Types...)>>)
|
||||
this->_functions[id] = std::move(callback);
|
||||
else
|
||||
this->_functions[id] = std::function<void (Types...)>(callback);
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -53,8 +57,9 @@ namespace WAL
|
||||
//! @brief A default assignment operator
|
||||
Callback &operator=(const Callback &) = default;
|
||||
|
||||
//! @brief Implicitly transform a function into a callback.
|
||||
Callback(std::function<void (Types...)> callback) // NOLINT(google-explicit-constructor)
|
||||
//! @brief Implicitly transform a callable into a callback.
|
||||
template<typename Func>
|
||||
Callback(Func callback) // NOLINT(google-explicit-constructor)
|
||||
{
|
||||
this->addCallback(callback);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,46 @@
|
||||
//
|
||||
|
||||
#include "Scene.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
std::vector<Entity> &Scene::getEntities()
|
||||
int Scene::_nextID = 0;
|
||||
|
||||
std::list<Entity> &Scene::getEntities()
|
||||
{
|
||||
return this->_entities;
|
||||
}
|
||||
|
||||
Scene &Scene::operator=(const Scene &)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
Entity &Scene::addEntity(const std::string &name)
|
||||
{
|
||||
return this->_entities.emplace_back(*this, name);
|
||||
}
|
||||
|
||||
void Scene::_componentAdded(Entity &entity, const std::type_index &type)
|
||||
{
|
||||
for (auto &view : this->_views) {
|
||||
if (std::find(view->getTypes().begin(), view->getTypes().end(), type) == view->getTypes().end())
|
||||
continue;
|
||||
bool valid = std::all_of(view->getTypes().begin(), view->getTypes().end(), [&entity](const auto &type){
|
||||
return entity.hasComponent(type);
|
||||
});
|
||||
if (valid)
|
||||
view->emplace_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::_componentRemoved(const Entity &entity, const std::type_index &type)
|
||||
{
|
||||
for (auto &view : this->_views) {
|
||||
if (std::find(view->getTypes().begin(), view->getTypes().end(), type) == view->getTypes().end())
|
||||
continue;
|
||||
view->erase(entity);
|
||||
}
|
||||
}
|
||||
} // namespace WAL
|
||||
@@ -6,7 +6,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <View/View.hpp>
|
||||
#include "Entity/Entity.hpp"
|
||||
|
||||
namespace WAL
|
||||
@@ -15,18 +17,43 @@ namespace WAL
|
||||
class Scene
|
||||
{
|
||||
private:
|
||||
static int _nextID;
|
||||
//! @brief An ID representing this scene.
|
||||
int _id = _nextID++;
|
||||
|
||||
//! @brief The list of registered entities
|
||||
std::vector<Entity> _entities = {};
|
||||
std::list<Entity> _entities = {};
|
||||
//! @brief The list of cached views to update.
|
||||
std::vector<std::shared_ptr<IView>> _views = {};
|
||||
|
||||
//! @brief Notify this scene that a component has been added to the given entity.
|
||||
//! @param entity The entity with the new component
|
||||
//! @param type The type of the component added.
|
||||
void _componentAdded(Entity &entity, const std::type_index &type);
|
||||
//! @brief Notify this scene that a component has been removed to the given entity.
|
||||
//! @param entity The entity with the removed component
|
||||
//! @param type The type of the component removed.
|
||||
void _componentRemoved(const Entity &entity, const std::type_index &type);
|
||||
public:
|
||||
//! @brief Get the list of entities.
|
||||
std::vector<Entity> &getEntities();
|
||||
std::list<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>
|
||||
Entity &addEntity(Params &&...params)
|
||||
//! @brief Add a new entity to the scene.
|
||||
//! @param name The name of the created entity.
|
||||
//! @return The created entity is returned.
|
||||
Entity &addEntity(const std::string &name);
|
||||
|
||||
template<typename ...Components>
|
||||
View<Components...> &view()
|
||||
{
|
||||
return this->_entities.emplace_back(std::forward<Params>(params)...);
|
||||
static std::unordered_map<int, std::weak_ptr<View<Components...>>> cache;
|
||||
auto existing = cache.find(this->_id);
|
||||
if (existing != cache.end() && !existing->second.expired())
|
||||
return *existing->second.lock();
|
||||
auto view = std::make_shared<View<Components...>>(this->_entities);
|
||||
this->_views.emplace_back(view);
|
||||
cache.emplace(this->_id, view);
|
||||
return *view;
|
||||
}
|
||||
|
||||
//! @brief A default constructor
|
||||
@@ -38,5 +65,7 @@ namespace WAL
|
||||
//! @brief A scene is assignable
|
||||
Scene &operator=(const Scene &);
|
||||
Scene(Scene &&) = default;
|
||||
|
||||
friend Entity;
|
||||
};
|
||||
} // namespace WAL
|
||||
32
lib/wal/sources/System/ISystem.hpp
Normal file
32
lib/wal/sources/System/ISystem.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-06-04.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "View/View.hpp"
|
||||
#include <chrono>
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
//! @brief A base class that represent a system.
|
||||
class ISystem
|
||||
{
|
||||
public:
|
||||
//! @brief Update the whole system (every entities that this system is responsible can be updated.
|
||||
//! @param dtime The delta time since the last call to this method.
|
||||
virtual void update(std::chrono::nanoseconds dtime) = 0;
|
||||
|
||||
//! @brief An alternative of update that is called every 8ms (120 times per seconds). If the system slow down, it will try to catch up.
|
||||
//! @remark This should be used for Physics, AI and everything that could be imprecise due to float rounding.
|
||||
virtual void fixedUpdate() = 0;
|
||||
|
||||
//! @brief Get a view containing every entity this system should update.
|
||||
virtual IView &getView() = 0;
|
||||
|
||||
//! @brief A virtual default destructor.
|
||||
virtual ~ISystem() = default;
|
||||
};
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
//
|
||||
// Created by Zoe Roux on 5/17/21.
|
||||
//
|
||||
|
||||
#include "System.hpp"
|
||||
#include <vector>
|
||||
#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)
|
||||
{}
|
||||
|
||||
void System::onFixedUpdate(Entity &entity)
|
||||
{}
|
||||
|
||||
void System::onSelfUpdate()
|
||||
{}
|
||||
|
||||
const std::vector<std::type_index> &System::getDependencies() const
|
||||
{
|
||||
return this->_dependencies;
|
||||
}
|
||||
} // namespace WAL
|
||||
@@ -6,40 +6,71 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <typeinfo>
|
||||
#include <typeindex>
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Wal.hpp"
|
||||
#include "View/View.hpp"
|
||||
#include "ISystem.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
//! @brief A base system of WAL
|
||||
class System
|
||||
//! @tparam Dependencies The list of dependencies this system has.
|
||||
template<typename ...Dependencies>
|
||||
class System : public ISystem
|
||||
{
|
||||
private:
|
||||
//! @brief The list of dependencies of this system
|
||||
std::vector<std::type_index> _dependencies = {};
|
||||
public:
|
||||
//! @brief A virtual, default, destructor
|
||||
virtual ~System() = default;
|
||||
~System() override = default;
|
||||
//! @brief A system can be moved
|
||||
System(System &&) = default;
|
||||
System(System &&) noexcept = default;
|
||||
|
||||
//! @brief Get the name of the component corresponding to this system.
|
||||
const std::vector<std::type_index> &getDependencies() const;
|
||||
//! @brief Get a view of all entities containing every dependencies of this system.
|
||||
View<Dependencies...> &getView() override
|
||||
{
|
||||
return this->_wal.scene->template view<Dependencies...>();
|
||||
}
|
||||
|
||||
//! @brief Update the corresponding component of the given entity
|
||||
//! @param entity The entity to update.
|
||||
//! @param dtime The delta time.
|
||||
virtual void onUpdate(Entity &entity, std::chrono::nanoseconds dtime);
|
||||
virtual void onUpdate(ViewEntity<Dependencies...> &entity, std::chrono::nanoseconds dtime) {}
|
||||
|
||||
//! @brief An alternative of onUpdate that is called every 8ms (120 times per seconds). If the system slow down, it will try to catch up.
|
||||
//! @remark This should be used for Physics, AI and everything that could be imprecise due to float rounding.
|
||||
//! @param entity The entity to update.
|
||||
virtual void onFixedUpdate(Entity &entity);
|
||||
virtual void onFixedUpdate(ViewEntity<Dependencies...> &entity) {}
|
||||
|
||||
//! @brief A method called after all entities that this system manage has been updated.
|
||||
virtual void onSelfUpdate();
|
||||
virtual void onSelfUpdate() {}
|
||||
|
||||
|
||||
//! @brief Update the whole system (every entities that this system is responsible can be updated.
|
||||
//! @param dtime The delta time since the last call to this method.
|
||||
void update(std::chrono::nanoseconds dtime) final
|
||||
{
|
||||
for (auto &entity : this->getView())
|
||||
this->onUpdate(entity, dtime);
|
||||
this->onSelfUpdate();
|
||||
}
|
||||
|
||||
//! @brief An alternative of update that is called every 8ms (120 times per seconds). If the system slow down, it will try to catch up.
|
||||
//! @remark This should be used for Physics, AI and everything that could be imprecise due to float rounding.
|
||||
void fixedUpdate() final
|
||||
{
|
||||
for (auto &entity : this->getView())
|
||||
this->onFixedUpdate(entity);
|
||||
}
|
||||
protected:
|
||||
//! @brief A reference to the ECS.
|
||||
Wal &_wal;
|
||||
|
||||
//! @brief A system can't be instantiated, it should be derived.
|
||||
explicit System(std::vector<std::type_index> dependencies);
|
||||
explicit System(Wal &wal)
|
||||
: _wal(wal)
|
||||
{}
|
||||
//! @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.
|
||||
|
||||
222
lib/wal/sources/View/View.hpp
Normal file
222
lib/wal/sources/View/View.hpp
Normal file
@@ -0,0 +1,222 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-06-03.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#include <typeindex>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <optional>
|
||||
#include "Entity/Entity.hpp"
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
template<typename ...Components>
|
||||
class ViewEntity
|
||||
{
|
||||
private:
|
||||
std::tuple<std::reference_wrapper<Entity>, std::reference_wrapper<Components>...> &_value;
|
||||
public:
|
||||
explicit ViewEntity(std::tuple<std::reference_wrapper<Entity>, std::reference_wrapper<Components>...> &value)
|
||||
: _value(value)
|
||||
{}
|
||||
|
||||
Entity *operator->()
|
||||
{
|
||||
return &(std::get<0>(this->_value).get());
|
||||
}
|
||||
|
||||
Entity &operator*()
|
||||
{
|
||||
return std::get<0>(this->_value);
|
||||
}
|
||||
|
||||
operator Entity &()
|
||||
{
|
||||
return std::get<0>(this->_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T &get()
|
||||
{
|
||||
return std::get<std::reference_wrapper<T>>(this->_value);
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
auto &get()
|
||||
{
|
||||
return std::get<I>(this->_value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename It, typename ...Components>
|
||||
class ViewIterator
|
||||
{
|
||||
private:
|
||||
It _it;
|
||||
std::optional<ViewEntity<Components...>> _entity;
|
||||
|
||||
public:
|
||||
ViewEntity<Components...> &operator*()
|
||||
{
|
||||
if (!this->_entity)
|
||||
this->_entity.emplace(*this->_it);
|
||||
return *this->_entity;
|
||||
}
|
||||
|
||||
ViewEntity<Components...> *operator->()
|
||||
{
|
||||
if (!this->_entity)
|
||||
this->_entity =(*this->_it);
|
||||
return &this->_entity;
|
||||
}
|
||||
|
||||
ViewIterator &operator++()
|
||||
{
|
||||
this->_it++;
|
||||
this->_entity = std::nullopt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ViewIterator operator++(int)
|
||||
{
|
||||
ViewIterator copy = *this;
|
||||
this->_it++;
|
||||
this->_entity = std::nullopt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const ViewIterator &other) const
|
||||
{
|
||||
return this->_it == other._it;
|
||||
}
|
||||
|
||||
bool operator!=(const ViewIterator &other) const
|
||||
{
|
||||
return !this->operator==(other);
|
||||
}
|
||||
|
||||
explicit ViewIterator(It current)
|
||||
: _it(current),
|
||||
_entity(std::nullopt)
|
||||
{}
|
||||
};
|
||||
|
||||
//! @brief A basic view used to manipulate view without knowing their type at compile time.
|
||||
class IView
|
||||
{
|
||||
public:
|
||||
//! @brief The list of types that every entity of the view has.
|
||||
virtual const std::vector<std::type_index> &getTypes() const = 0;
|
||||
|
||||
virtual void emplace_back(Entity &) = 0;
|
||||
|
||||
virtual void erase(const Entity &) = 0;
|
||||
|
||||
//! @brief A default destructor
|
||||
virtual ~IView() = default;
|
||||
};
|
||||
|
||||
//! @brief A view allowing one to easily access entities containing a set list of component.
|
||||
//! A view is always updated and only references to entities are kept.
|
||||
template<typename ...Components>
|
||||
class View : public IView
|
||||
{
|
||||
private:
|
||||
using entity_type = std::tuple<std::reference_wrapper<Entity>, std::reference_wrapper<Components>...>;
|
||||
|
||||
//! @brief The list of entities in the view.
|
||||
std::vector<entity_type> _entities = {};
|
||||
//! @brief The list of types that every entity of the view has.
|
||||
std::vector<std::type_index> _types = {};
|
||||
public:
|
||||
using iterator = ViewIterator<typename std::vector<entity_type>::iterator, Components...>;
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return iterator(this->_entities.begin());
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(this->_entities.end());
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return this->_entities.size();
|
||||
}
|
||||
|
||||
ViewEntity<Components...> front()
|
||||
{
|
||||
return *iterator(this->_entities.begin());
|
||||
}
|
||||
|
||||
ViewEntity<Components...> back()
|
||||
{
|
||||
return *iterator(--this->_entities.end());
|
||||
}
|
||||
|
||||
const std::vector<std::type_index> &getTypes() const override
|
||||
{
|
||||
return this->_types;
|
||||
}
|
||||
|
||||
void emplace_back(Entity &entity) override
|
||||
{
|
||||
auto tuple = std::make_tuple<Components *...>(entity.tryGetComponent<Components>()...);
|
||||
if (std::apply([](const auto *...component) {return ((component == nullptr) || ...);}, tuple))
|
||||
return;
|
||||
std::apply([&](auto *...component) {
|
||||
this->_entities.emplace_back(entity, *component...);
|
||||
}, tuple);
|
||||
}
|
||||
|
||||
void erase(const Entity &entity) override
|
||||
{
|
||||
this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [&entity](const auto &ref){
|
||||
return &std::get<0>(ref).get() == &entity;
|
||||
}));
|
||||
}
|
||||
|
||||
//! @brief Construct a view from a list of entities.
|
||||
//! Those entities are never copied but references to them are kept internally.
|
||||
explicit View(std::list<Entity> &scene)
|
||||
{
|
||||
this->_types = {typeid(Components)...};
|
||||
for (auto &entity : scene)
|
||||
this->emplace_back(entity);
|
||||
}
|
||||
|
||||
//! @brief Copying a view is not possible since a view must be managed by a scene.
|
||||
View(const View &) = delete;
|
||||
//! @brief A default destructor
|
||||
~View() override = default;
|
||||
//! @brief A view is not assignable.
|
||||
View &operator=(const View &) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<typename ...Components>
|
||||
struct tuple_size<::WAL::ViewEntity<Components...>>
|
||||
: public std::integral_constant<std::size_t, 1 + sizeof...(Components)>
|
||||
{};
|
||||
|
||||
template<typename ...Components>
|
||||
struct tuple_element<0, ::WAL::ViewEntity<Components...>>
|
||||
{
|
||||
using type = WAL::Entity &;
|
||||
};
|
||||
|
||||
template<std::size_t N, typename ...Components>
|
||||
struct tuple_element<N, ::WAL::ViewEntity<Components...>>
|
||||
{
|
||||
using type = typename std::tuple_element<N - 1, std::tuple<Components...>>::type;
|
||||
};
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
//
|
||||
// Created by Zoe Roux on 2021-05-14.
|
||||
//
|
||||
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include "Wal.hpp"
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
std::chrono::nanoseconds Wal::timestep = std::chrono::milliseconds(8);
|
||||
|
||||
void Wal::_update(std::chrono::nanoseconds dtime)
|
||||
{
|
||||
auto &entities = this->scene->getEntities();
|
||||
|
||||
for (auto &system : this->_systems) {
|
||||
for (auto &entity : entities) {
|
||||
if (!Wal::_hasDependencies(entity, *system))
|
||||
continue;
|
||||
system->onUpdate(entity, dtime);
|
||||
}
|
||||
system->onSelfUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void Wal::_fixedUpdate()
|
||||
{
|
||||
auto &entities = this->scene->getEntities();
|
||||
|
||||
for (auto &system : this->_systems) {
|
||||
for (auto &entity : entities) {
|
||||
if (!Wal::_hasDependencies(entity, *system))
|
||||
continue;
|
||||
system->onFixedUpdate(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Wal::_hasDependencies(const Entity &entity, const System &system)
|
||||
{
|
||||
// TODO use an hashmap to cache results.
|
||||
const auto &dependency = system.getDependencies();
|
||||
for (const auto &dependency : system.getDependencies()) {
|
||||
if (!entity.hasComponent(dependency))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace WAL
|
||||
@@ -10,10 +10,9 @@
|
||||
#include <memory>
|
||||
#include <typeinfo>
|
||||
#include "Exception/WalError.hpp"
|
||||
#include "Scene/Scene.hpp"
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "System/System.hpp"
|
||||
#include "System/ISystem.hpp"
|
||||
#include "Models/Callback.hpp"
|
||||
#include "Scene/Scene.hpp"
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
#include <emscripten/emscripten.h>
|
||||
@@ -21,31 +20,71 @@
|
||||
|
||||
namespace WAL
|
||||
{
|
||||
class Entity;
|
||||
|
||||
//! @brief The main WAL class, it is used to setup and run the ECS.
|
||||
class Wal
|
||||
{
|
||||
private:
|
||||
//! @brief The list of registered systems
|
||||
std::vector<std::unique_ptr<System>> _systems = {};
|
||||
std::vector<std::unique_ptr<ISystem>> _systems = {};
|
||||
|
||||
//! @brief Call the onUpdate of every system with every component
|
||||
void _update(std::chrono::nanoseconds dtime);
|
||||
//! @brief Start the game loop
|
||||
//! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here)
|
||||
//! @param state An initial game state. If not specified, it will be defaulted.
|
||||
//! @tparam T A type used to track your game state. It must be default constructable.
|
||||
template<typename T>
|
||||
void _run(const Callback<Wal &, T &> &callback, T state = T())
|
||||
{
|
||||
auto lastTick = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds fBehind(0);
|
||||
|
||||
//! @brief Call the onFixedUpdate of every system with every component
|
||||
void _fixedUpdate();
|
||||
while (!this->shouldClose) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds dtime = now - lastTick;
|
||||
fBehind += dtime;
|
||||
lastTick = now;
|
||||
|
||||
//! @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);
|
||||
while (fBehind > Wal::timestep) {
|
||||
fBehind -= Wal::timestep;
|
||||
for (auto &system : this->_systems)
|
||||
system->fixedUpdate();
|
||||
}
|
||||
for (auto &system : this->_systems)
|
||||
system->update(dtime);
|
||||
callback(*this, state);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
template<typename T>
|
||||
static void _runIteration(void *param)
|
||||
{
|
||||
static auto [wal, callback, state] = *reinterpret_cast<std::tuple<Wal &, const Callback<Wal &, T &> &, T &> *>(param);
|
||||
static auto lastTick = std::chrono::steady_clock::now();
|
||||
static std::chrono::nanoseconds fBehind(0);
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds dtime = now - lastTick;
|
||||
fBehind += dtime;
|
||||
lastTick = now;
|
||||
while (fBehind > Wal::timestep) {
|
||||
fBehind -= Wal::timestep;
|
||||
for (auto &system : wal._systems)
|
||||
system->fixedUpdate();
|
||||
}
|
||||
for (auto &system : wal._systems)
|
||||
system->update(dtime);
|
||||
callback(wal, state);
|
||||
}
|
||||
#endif
|
||||
public:
|
||||
//! @brief The scene that contains entities.
|
||||
std::shared_ptr<Scene> scene;
|
||||
//! @brief True if the engine should close after the end of the current tick.
|
||||
bool shouldClose = false;
|
||||
//! @brief The time between each fixed update.
|
||||
static std::chrono::nanoseconds timestep;
|
||||
static constexpr std::chrono::nanoseconds timestep = std::chrono::milliseconds(32);
|
||||
|
||||
//! @brief Create a new system in place.
|
||||
//! @return The wal instance used to call this function is returned. This allow method chaining.
|
||||
@@ -58,7 +97,7 @@ namespace WAL
|
||||
});
|
||||
if (existing != this->_systems.end())
|
||||
throw DuplicateError("A system of the type \"" + std::string(type.name()) + "\" already exists.");
|
||||
this->_systems.push_back(std::make_unique<T>(std::forward<Types>(params)...));
|
||||
this->_systems.push_back(std::make_unique<T>(*this, std::forward<Types>(params)...));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -105,23 +144,6 @@ namespace WAL
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief Start the game loop
|
||||
//! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here)
|
||||
//! @param state An initial game state. If not specified, it will be defaulted.
|
||||
//! @tparam T A type used to track your game state. It must be default constructable.
|
||||
template<typename T>
|
||||
void run(const std::function<void (Wal &, T &)> &callback, T state = T())
|
||||
{
|
||||
Callback<Wal &, T &> update(callback);
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
std::tuple iterationParams(this, &update, &state);
|
||||
return emscripten_set_main_loop_arg((em_arg_callback_func)runIteration<T>, (void *)&iterationParams, 0, 1);
|
||||
#else
|
||||
return this->run(update, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! @brief Start the game loop
|
||||
//! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here)
|
||||
//! @param state An initial game state. If not specified, it will be defaulted.
|
||||
@@ -129,47 +151,13 @@ namespace WAL
|
||||
template<typename T>
|
||||
void run(const Callback<Wal &, T &> &callback, T state = T())
|
||||
{
|
||||
auto lastTick = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds fBehind(0);
|
||||
|
||||
while (!this->shouldClose) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds dtime = now - lastTick;
|
||||
fBehind += dtime;
|
||||
lastTick = now;
|
||||
|
||||
while (fBehind > Wal::timestep) {
|
||||
fBehind -= Wal::timestep;
|
||||
this->_fixedUpdate();
|
||||
}
|
||||
this->_update(dtime);
|
||||
callback(*this, state);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
template<typename T>
|
||||
static void runIteration(void *param)
|
||||
{
|
||||
static auto iterationParams = reinterpret_cast<std::tuple<Wal *, Callback<Wal &, T &> *, T *> *>(param);
|
||||
static const Callback<Wal &, T &> callback = *((Callback<Wal &, T &> *)std::get<1>(*iterationParams));
|
||||
static T *state = (T *)std::get<2>(*iterationParams);
|
||||
static Wal *wal = (Wal *)std::get<0>(*iterationParams);
|
||||
static auto lastTick = std::chrono::steady_clock::now();
|
||||
static std::chrono::nanoseconds fBehind(0);
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds dtime = now - lastTick;
|
||||
fBehind += dtime;
|
||||
lastTick = now;
|
||||
while (fBehind > Wal::timestep) {
|
||||
fBehind -= Wal::timestep;
|
||||
wal->_fixedUpdate();
|
||||
}
|
||||
wal->_update(dtime);
|
||||
callback(*wal, *state);
|
||||
}
|
||||
std::tuple<Wal &, const Callback<Wal &, T &> &, T &> iterationParams(*this, callback, state);
|
||||
return emscripten_set_main_loop_arg((em_arg_callback_func)_runIteration<T>, (void *)&iterationParams, 0, 1);
|
||||
#else
|
||||
return this->_run(callback, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! @brief A default constructor
|
||||
Wal() = default;
|
||||
|
||||
@@ -16,14 +16,6 @@ namespace BBM
|
||||
return new CollisionComponent(entity);
|
||||
}
|
||||
|
||||
CollisionComponent::CollisionComponent(WAL::Entity &entity, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollide, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollided, Vector3f bound)
|
||||
: WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound(bound)
|
||||
{ }
|
||||
|
||||
CollisionComponent::CollisionComponent(WAL::Entity &entity, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollide, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollided, float boundSize)
|
||||
: WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound({boundSize, boundSize, boundSize})
|
||||
{ }
|
||||
|
||||
CollisionComponent::CollisionComponent(WAL::Entity &entity, WAL::Callback<WAL::Entity &, const WAL::Entity &> onCollide, WAL::Callback<WAL::Entity &, const WAL::Entity &> onCollided, Vector3f bound)
|
||||
: WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound(bound)
|
||||
{ }
|
||||
|
||||
@@ -27,12 +27,6 @@ namespace BBM
|
||||
//! @brief A component can't be instantiated, it should be derived.
|
||||
explicit CollisionComponent(WAL::Entity &entity);
|
||||
|
||||
//! @brief Constructor with a callback function
|
||||
CollisionComponent(WAL::Entity &entity, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollide, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollided, Vector3f bound);
|
||||
|
||||
//! @brief Constructor with a callback function, same boundSize for all axis
|
||||
CollisionComponent(WAL::Entity &entity, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollide, std::function<void (WAL::Entity &, const WAL::Entity &)> onCollided, float boundSize = 0);
|
||||
|
||||
//! @brief Constructor with a WAL::Callback
|
||||
CollisionComponent(WAL::Entity &entity, WAL::Callback<WAL::Entity &, const WAL::Entity &> onCollide, WAL::Callback<WAL::Entity &, const WAL::Entity &> onCollided,Vector3f bound);
|
||||
|
||||
|
||||
@@ -20,11 +20,6 @@ namespace BBM
|
||||
this->_acceleration += force;
|
||||
}
|
||||
|
||||
void MovableComponent::resetVelocity(void)
|
||||
{
|
||||
this->_velocity = {0, 0, 0};
|
||||
}
|
||||
|
||||
const Vector3f &MovableComponent::getVelocity(void) const
|
||||
{
|
||||
return _velocity;
|
||||
|
||||
@@ -23,9 +23,6 @@ namespace BBM
|
||||
//! @param force The force to add to this entity's acceleration. The force is added instantly and in one go.
|
||||
void addForce(Vector3f force);
|
||||
|
||||
//! @brief Set velocity to 0
|
||||
void resetVelocity(void);
|
||||
|
||||
//! @brief Get velocity
|
||||
const Vector3f &getVelocity(void) const;
|
||||
|
||||
@@ -42,5 +39,6 @@ namespace BBM
|
||||
MovableComponent &operator=(const MovableComponent &) = delete;
|
||||
|
||||
friend class MovableSystem;
|
||||
friend class MapGenerator;
|
||||
};
|
||||
} // namespace WAL
|
||||
@@ -3,12 +3,33 @@
|
||||
// Edited by Benjamin Henry on 5/26/21.
|
||||
//
|
||||
|
||||
#include <Component/Collision/CollisionComponent.hpp>
|
||||
#include "Map.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace RAY3D = RAY::Drawables::Drawables3D;
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
void MapGenerator::wallCollide(WAL::Entity &entity, const WAL::Entity &wall)
|
||||
{
|
||||
auto *mov = entity.tryGetComponent<MovableComponent>();
|
||||
if (!mov)
|
||||
return;
|
||||
auto &pos = entity.getComponent<PositionComponent>();
|
||||
const auto &wallPos = wall.getComponent<PositionComponent>();
|
||||
auto diff = pos.position + mov->getVelocity() - wallPos.position;
|
||||
// mov->_velocity = Vector3f();
|
||||
if (diff.x <= 0 && mov->_velocity.x < 0)
|
||||
mov->_velocity.x = 0;
|
||||
if (diff.x >= 0 && mov->_velocity.x > 0)
|
||||
mov->_velocity.x = 0;
|
||||
if (diff.z <= 0 && mov->_velocity.z < 0)
|
||||
mov->_velocity.z = 0;
|
||||
if (diff.z >= 0 && mov->_velocity.z > 0)
|
||||
mov->_velocity.z = 0;
|
||||
}
|
||||
|
||||
const std::string MapGenerator::assetsPath = "./assets/";
|
||||
const std::string MapGenerator::wallAssetsPath = MapGenerator::assetsPath + "map/";
|
||||
const std::string MapGenerator::imageExtension = ".png";
|
||||
@@ -24,17 +45,16 @@ namespace BBM
|
||||
|
||||
void MapGenerator::generateUnbreakableBlock(int width, int height, std::shared_ptr<WAL::Scene> scene)
|
||||
{
|
||||
static const std::string UnbreakableObj = unbreakableWallPath + objExtension;
|
||||
static const std::string UnbreakablePng = unbreakableWallPath + imageExtension;
|
||||
static const std::string unbreakableObj = unbreakableWallPath + objExtension;
|
||||
static const std::string unbreakablePng = unbreakableWallPath + imageExtension;
|
||||
|
||||
for (int i = 0; i < width + 1; i++) {
|
||||
for (int j = 0; j < height + 1; j++) {
|
||||
if (!(i % 2) && !(j % 2)) {
|
||||
scene->addEntity("Unbreakable Wall")
|
||||
.addComponent<PositionComponent>(Vector3f(i, 0, j))
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(UnbreakableObj,
|
||||
std::make_pair(MAP_DIFFUSE, UnbreakablePng));
|
||||
.addComponent<PositionComponent>(i, 0, j)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, .75)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePng));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,25 +67,25 @@ namespace BBM
|
||||
|
||||
scene->addEntity("Bottom Wall")
|
||||
.addComponent<PositionComponent>(Vector3f((width + 1) / 2, 0, -1))
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, .75)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
|
||||
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
|
||||
RAY::Vector3(width + 3, 1, 1));
|
||||
scene->addEntity("Upper Wall")
|
||||
.addComponent<PositionComponent>(Vector3f((width + 1) / 2, 0, height + 1))
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, .75)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
|
||||
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
|
||||
RAY::Vector3(width + 3, 1, 1));
|
||||
scene->addEntity("Left Wall")
|
||||
.addComponent<PositionComponent>(Vector3f(width + 1, 0, height / 2))
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, .75)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
|
||||
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
|
||||
RAY::Vector3(1, 1, height + 1));
|
||||
scene->addEntity("Right Wall")
|
||||
.addComponent<PositionComponent>(Vector3f(-1, 0, height / 2))
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, .75)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
|
||||
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
|
||||
RAY::Vector3(1, 1, height + 1));
|
||||
@@ -81,7 +101,6 @@ namespace BBM
|
||||
if (map[std::make_tuple(i, 0, j)] != HOLE && map[std::make_tuple(i, -1, j)] != BUMPER)
|
||||
scene->addEntity("Unbreakable Wall")
|
||||
.addComponent<PositionComponent>(Vector3f(i, -1, j))
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(floorObj,
|
||||
std::make_pair(MAP_DIFFUSE, floorPng));
|
||||
}
|
||||
@@ -116,7 +135,7 @@ namespace BBM
|
||||
scene->addEntity("Breakable Block")
|
||||
.addComponent<PositionComponent>(coords)
|
||||
.addComponent<HealthComponent>(1)
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, .75)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng));
|
||||
}
|
||||
|
||||
@@ -138,7 +157,6 @@ namespace BBM
|
||||
|
||||
scene->addEntity("Upper Floor")
|
||||
.addComponent<PositionComponent>(Vector3f(coords))
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(floorObj, std::make_pair(MAP_DIFFUSE, floorPng));
|
||||
}
|
||||
|
||||
@@ -150,7 +168,7 @@ namespace BBM
|
||||
|
||||
scene->addEntity("Unbreakable Block")
|
||||
.addComponent<PositionComponent>(coords)
|
||||
//.addComponent<CollisionComponent>(1)
|
||||
.addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, .75)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Model>(UnbreakableObj,
|
||||
std::make_pair(MAP_DIFFUSE, UnbreakablePng));
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <tuple>
|
||||
#include <algorithm>
|
||||
#include "Component/Renderer/Drawable3DComponent.hpp"
|
||||
#include "System/Renderer/RenderSystem.hpp"
|
||||
#include "Scene/Scene.hpp"
|
||||
#include "Model/Model.hpp"
|
||||
#include "Component/Component.hpp"
|
||||
@@ -157,6 +156,8 @@ namespace BBM
|
||||
static const std::string secondFloorHolePath;
|
||||
|
||||
public:
|
||||
static void wallCollide(WAL::Entity &entity, const WAL::Entity &wall);
|
||||
|
||||
|
||||
//! @param width Width of the map
|
||||
//! @param height Height of the map
|
||||
|
||||
@@ -71,7 +71,13 @@ namespace BBM
|
||||
}
|
||||
|
||||
template<typename T2>
|
||||
Vector3<T> &operator*=(T2 d)
|
||||
Vector3<T> operator-(const Vector3<T2> &vec) const
|
||||
{
|
||||
return Vector3<T>(this->x - vec.x, this->y - vec.y, this->z - vec.z);
|
||||
}
|
||||
|
||||
template<typename T2>
|
||||
Vector3<T> &operator*=(const T2 d)
|
||||
{
|
||||
this->x *= d;
|
||||
this->y *= d;
|
||||
@@ -80,7 +86,7 @@ namespace BBM
|
||||
}
|
||||
|
||||
template<typename T2>
|
||||
Vector3<T> operator*(T2 d) const
|
||||
Vector3<T> operator*(const T2 d) const
|
||||
{
|
||||
return Vector3<T>(this->x * d, this->y * d, this->z * d);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include "System/Renderer/RenderSystem.hpp"
|
||||
#include <Model/Model.hpp>
|
||||
#include <Drawables/3D/Cube.hpp>
|
||||
#include <Drawables/2D/Rectangle.hpp>
|
||||
#include <Drawables/3D/Cube.hpp>
|
||||
#include <TraceLog.hpp>
|
||||
#include <System/Keyboard/KeyboardSystem.hpp>
|
||||
#include <System/Controllable/ControllableSystem.hpp>
|
||||
@@ -19,9 +17,7 @@
|
||||
#include <Component/Controllable/ControllableComponent.hpp>
|
||||
#include <Component/Keyboard/KeyboardComponent.hpp>
|
||||
#include <System/Gamepad/GamepadSystem.hpp>
|
||||
#include "Models/Vector2.hpp"
|
||||
#include "Component/Renderer/CameraComponent.hpp"
|
||||
#include "Component/Renderer/Drawable2DComponent.hpp"
|
||||
#include "Component/Renderer/Drawable3DComponent.hpp"
|
||||
#include "Runner.hpp"
|
||||
#include "Models/GameState.hpp"
|
||||
@@ -30,7 +26,6 @@
|
||||
#include "System/Animation/AnimationsSystem.hpp"
|
||||
#include "Map/Map.hpp"
|
||||
|
||||
namespace RAY2D = RAY::Drawables::Drawables2D;
|
||||
namespace RAY3D = RAY::Drawables::Drawables3D;
|
||||
|
||||
namespace BBM
|
||||
@@ -49,9 +44,8 @@ namespace BBM
|
||||
{
|
||||
wal.addSystem<KeyboardSystem>()
|
||||
.addSystem<GamepadSystem>()
|
||||
.addSystem<AnimationsSystem>()
|
||||
.addSystem<ControllableSystem>()
|
||||
.addSystem<CollisionSystem>(wal)
|
||||
.addSystem<CollisionSystem>()
|
||||
.addSystem<MovableSystem>();
|
||||
}
|
||||
|
||||
@@ -59,7 +53,8 @@ namespace BBM
|
||||
{
|
||||
RAY::TraceLog::setLevel(LOG_WARNING);
|
||||
RAY::Window &window = RAY::Window::getInstance(600, 400, "Bomberman", FLAG_WINDOW_RESIZABLE);
|
||||
wal.addSystem<RenderSystem>(wal, window);
|
||||
wal.addSystem<AnimationsSystem>()
|
||||
.addSystem<RenderSystem>(window);
|
||||
}
|
||||
|
||||
std::shared_ptr<WAL::Scene> loadGameScene()
|
||||
@@ -71,24 +66,18 @@ namespace BBM
|
||||
.addComponent<ControllableComponent>()
|
||||
.addComponent<KeyboardComponent>()
|
||||
.addComponent<AnimationsComponent>(RAY::ModelAnimations("assets/player/player.iqm"), 3)
|
||||
.addComponent<CollisionComponent>(2)
|
||||
.addComponent<CollisionComponent>(1)
|
||||
.addComponent<MovableComponent>();
|
||||
scene->addEntity("cube")
|
||||
.addComponent<PositionComponent>(-5, 0, -5)
|
||||
.addComponent<Drawable3DComponent, RAY3D::Cube>(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED)
|
||||
.addComponent<ControllableComponent>()
|
||||
.addComponent<KeyboardComponent>()
|
||||
.addComponent<CollisionComponent>([](WAL::Entity &, const WAL::Entity &){},
|
||||
[](WAL::Entity &actual, const WAL::Entity &) {
|
||||
try {
|
||||
auto &mov = actual.getComponent<MovableComponent>();
|
||||
mov.resetVelocity();
|
||||
} catch (std::exception &e) { };
|
||||
}, 3);
|
||||
|
||||
scene->addEntity("camera")
|
||||
.addComponent<PositionComponent>(8, 20, 7)
|
||||
.addComponent<CameraComponent>(Vector3f(8, 0, 8));
|
||||
// scene->addEntity("cube")
|
||||
// .addComponent<PositionComponent>(5, 0, 5)
|
||||
// .addComponent<Drawable3DComponent, RAY3D::Cube>(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED)
|
||||
// .addComponent<ControllableComponent>()
|
||||
// .addComponent<KeyboardComponent>()
|
||||
// .addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &>(), &MapGenerator::wallCollide, 3);
|
||||
std::srand(std::time(nullptr));
|
||||
MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16), scene);
|
||||
return scene;
|
||||
|
||||
@@ -11,18 +11,14 @@
|
||||
namespace BBM
|
||||
{
|
||||
|
||||
AnimationsSystem::AnimationsSystem()
|
||||
: WAL::System({
|
||||
typeid(Drawable3DComponent),
|
||||
typeid(AnimationsComponent)
|
||||
})
|
||||
{
|
||||
}
|
||||
AnimationsSystem::AnimationsSystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void AnimationsSystem::onUpdate(WAL::Entity &entity, std::chrono::nanoseconds)
|
||||
void AnimationsSystem::onUpdate(WAL::ViewEntity<Drawable3DComponent, AnimationsComponent> &entity, std::chrono::nanoseconds)
|
||||
{
|
||||
auto &model = entity.getComponent<Drawable3DComponent>();
|
||||
auto &anim = entity.getComponent<AnimationsComponent>();
|
||||
auto &model = entity.get<Drawable3DComponent>();
|
||||
auto &anim = entity.get<AnimationsComponent>();
|
||||
|
||||
if (anim.isDisabled())
|
||||
return;
|
||||
|
||||
@@ -5,22 +5,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <System/System.hpp>
|
||||
#include "Component/Renderer/Drawable3DComponent.hpp"
|
||||
#include "Component/Animation/AnimationsComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
class AnimationsSystem : public WAL::System
|
||||
class AnimationsSystem : public WAL::System<Drawable3DComponent, AnimationsComponent>
|
||||
{
|
||||
public:
|
||||
//! @inherit
|
||||
void onUpdate(WAL::Entity &entity, std::chrono::nanoseconds) override;
|
||||
void onUpdate(WAL::ViewEntity<Drawable3DComponent, AnimationsComponent> &entity, std::chrono::nanoseconds) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
AnimationsSystem();
|
||||
explicit AnimationsSystem(WAL::Wal &wal);
|
||||
//! @brief A Controllable system is copy constructable
|
||||
AnimationsSystem(const AnimationsSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~AnimationsSystem() override = default;
|
||||
//! @brief A Controllable system is assignable.
|
||||
AnimationsSystem &operator=(const AnimationsSystem &) = default;
|
||||
//! @brief A system is not assignable.
|
||||
AnimationsSystem &operator=(const AnimationsSystem &) = delete;
|
||||
};
|
||||
}
|
||||
@@ -6,14 +6,13 @@
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include "Component/Collision/CollisionComponent.hpp"
|
||||
#include "System/Collision/CollisionSystem.hpp"
|
||||
#include "Scene/Scene.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
CollisionSystem::CollisionSystem(WAL::Wal &wal)
|
||||
: WAL::System({typeid(PositionComponent), typeid(CollisionComponent)}), _wal(wal)
|
||||
{
|
||||
|
||||
}
|
||||
: System(wal)
|
||||
{ }
|
||||
|
||||
bool CollisionSystem::collide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB)
|
||||
{
|
||||
@@ -24,25 +23,20 @@ namespace BBM
|
||||
return (overlapX && overlapY && overlapZ);
|
||||
}
|
||||
|
||||
void CollisionSystem::onFixedUpdate(WAL::Entity &entity)
|
||||
void CollisionSystem::onFixedUpdate(WAL::ViewEntity<PositionComponent, CollisionComponent> &entity)
|
||||
{
|
||||
auto &posA = entity.getComponent<PositionComponent>();
|
||||
auto &col = entity.getComponent<CollisionComponent>();
|
||||
auto &posA = entity.get<PositionComponent>();
|
||||
auto &col = entity.get<CollisionComponent>();
|
||||
Vector3f position = posA.position;
|
||||
if (entity.hasComponent(typeid(MovableComponent)))
|
||||
position += entity.getComponent<MovableComponent>().getVelocity();
|
||||
if (auto *movable = entity->tryGetComponent<MovableComponent>())
|
||||
position += movable->getVelocity();
|
||||
Vector3f minA = Vector3f::min(position, position + col.bound);
|
||||
Vector3f maxA = Vector3f::max(position, position + col.bound);
|
||||
for (auto &other : _wal.scene->getEntities()) {
|
||||
if (&other == &entity)
|
||||
for (auto &[other, posB, colB] : this->getView()) {
|
||||
if (other.getUid() == entity->getUid())
|
||||
continue;
|
||||
if (!other.hasComponent<CollisionComponent>() ||
|
||||
!other.hasComponent<PositionComponent>())
|
||||
continue;
|
||||
auto colB = other.getComponent<CollisionComponent>();
|
||||
auto posB = other.getComponent<PositionComponent>().position;
|
||||
Vector3f minB = Vector3f::min(posB, posB + colB.bound);
|
||||
Vector3f maxB = Vector3f::max(posB, posB + colB.bound);
|
||||
Vector3f minB = Vector3f::min(posB.position, posB.position + colB.bound);
|
||||
Vector3f maxB = Vector3f::max(posB.position, posB.position + colB.bound);
|
||||
if (collide(minA, maxA, minB, maxB)) {
|
||||
col.onCollide(entity, other);
|
||||
colB.onCollided(entity, other);
|
||||
|
||||
@@ -9,27 +9,26 @@
|
||||
#include "Wal.hpp"
|
||||
#include "System/System.hpp"
|
||||
#include "Models/Vector3.hpp"
|
||||
#include "Component/Collision/CollisionComponent.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief A system to handle collisions.
|
||||
class CollisionSystem : public WAL::System
|
||||
class CollisionSystem : public WAL::System<PositionComponent, CollisionComponent>
|
||||
{
|
||||
private:
|
||||
//! @brief reference to the ECS engine to get other entities
|
||||
WAL::Wal &_wal;
|
||||
public:
|
||||
//! @inherit
|
||||
void onFixedUpdate(WAL::Entity &entity) override;
|
||||
void onFixedUpdate(WAL::ViewEntity<PositionComponent, CollisionComponent> &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
CollisionSystem(WAL::Wal &wal);
|
||||
explicit CollisionSystem(WAL::Wal &wal);
|
||||
//! @brief A Collision system is copy constructable
|
||||
CollisionSystem(const CollisionSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~CollisionSystem() override = default;
|
||||
//! @brief A Collision system is assignable.
|
||||
CollisionSystem &operator=(const CollisionSystem &) = default;
|
||||
//! @brief A system is not assignable.
|
||||
CollisionSystem &operator=(const CollisionSystem &) = delete;
|
||||
|
||||
//! @brief check AABB collision
|
||||
static bool collide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB);
|
||||
|
||||
@@ -10,17 +10,14 @@
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
ControllableSystem::ControllableSystem()
|
||||
: WAL::System({
|
||||
typeid(ControllableComponent),
|
||||
typeid(MovableComponent)
|
||||
})
|
||||
ControllableSystem::ControllableSystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void ControllableSystem::onFixedUpdate(WAL::Entity &entity)
|
||||
void ControllableSystem::onFixedUpdate(WAL::ViewEntity<ControllableComponent, MovableComponent> &entity)
|
||||
{
|
||||
auto &controllable = entity.getComponent<ControllableComponent>();
|
||||
auto &movable = entity.getComponent<MovableComponent>();
|
||||
auto &controllable = entity.get<ControllableComponent>();
|
||||
auto &movable = entity.get<MovableComponent>();
|
||||
Vector2f move = controllable.move.normalized() * ControllableSystem::speed;
|
||||
|
||||
movable.addForce(Vector3f(move.x, controllable.jump, move.y));
|
||||
|
||||
@@ -5,27 +5,29 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Component/Movable/MovableComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
#include "System/System.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief A system to handle Controllable entities.
|
||||
class ControllableSystem : public WAL::System
|
||||
class ControllableSystem : public WAL::System<ControllableComponent, MovableComponent>
|
||||
{
|
||||
public:
|
||||
//! @brief The speed applied to every controllable entities.
|
||||
static constexpr const float speed = .25f;
|
||||
|
||||
//! @inherit
|
||||
void onFixedUpdate(WAL::Entity &entity) override;
|
||||
void onFixedUpdate(WAL::ViewEntity<ControllableComponent, MovableComponent> &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
ControllableSystem();
|
||||
explicit ControllableSystem(WAL::Wal &wal);
|
||||
//! @brief A Controllable system is copy constructable
|
||||
ControllableSystem(const ControllableSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~ControllableSystem() override = default;
|
||||
//! @brief A Controllable system is assignable.
|
||||
ControllableSystem &operator=(const ControllableSystem &) = default;
|
||||
//! @brief A system is not assignable.
|
||||
ControllableSystem &operator=(const ControllableSystem &) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,17 +13,14 @@ using Gamepad = RAY::Controller::GamePad;
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
GamepadSystem::GamepadSystem()
|
||||
: WAL::System({
|
||||
typeid(GamepadComponent),
|
||||
typeid(ControllableComponent)
|
||||
})
|
||||
GamepadSystem::GamepadSystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void GamepadSystem::onFixedUpdate(WAL::Entity &entity)
|
||||
void GamepadSystem::onFixedUpdate(WAL::ViewEntity<GamepadComponent, ControllableComponent> &entity)
|
||||
{
|
||||
const auto &gamepadComponent = entity.getComponent<GamepadComponent>();
|
||||
auto &controllable = entity.getComponent<ControllableComponent>();
|
||||
const auto &gamepadComponent = entity.get<GamepadComponent>();
|
||||
auto &controllable = entity.get<ControllableComponent>();
|
||||
Gamepad gamepad(gamepadComponent.getID());
|
||||
|
||||
const std::map<Button, bool &> keyPressedMap = {
|
||||
|
||||
@@ -6,23 +6,25 @@
|
||||
|
||||
#include "System/System.hpp"
|
||||
#include <map>
|
||||
#include "Component/Gamepad/GamepadComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief A system to handle Gamepad entities.
|
||||
class GamepadSystem : public WAL::System
|
||||
class GamepadSystem : public WAL::System<GamepadComponent, ControllableComponent>
|
||||
{
|
||||
public:
|
||||
//! @inherit
|
||||
void onFixedUpdate(WAL::Entity &entity) override;
|
||||
void onFixedUpdate(WAL::ViewEntity<GamepadComponent, ControllableComponent> &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
GamepadSystem();
|
||||
explicit GamepadSystem(WAL::Wal &wal);
|
||||
//! @brief A Gamepad system is copy constructable
|
||||
GamepadSystem(const GamepadSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~GamepadSystem() override = default;
|
||||
//! @brief A Gamepad system is assignable.
|
||||
GamepadSystem &operator=(const GamepadSystem &) = default;
|
||||
//! @brief A system is not assignable.
|
||||
GamepadSystem &operator=(const GamepadSystem &) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,18 +8,14 @@
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
GridCenteredSystem::GridCenteredSystem()
|
||||
: WAL::System({
|
||||
typeid(GridCenteredComponent),
|
||||
typeid(MovableComponent),
|
||||
// typeid(PositionComponent)
|
||||
})
|
||||
GridCenteredSystem::GridCenteredSystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void GridCenteredSystem::onFixedUpdate(WAL::Entity &entity)
|
||||
void GridCenteredSystem::onFixedUpdate(WAL::ViewEntity<GridCenteredComponent, MovableComponent, PositionComponent> &entity)
|
||||
{
|
||||
auto &grid = entity.getComponent<GridCenteredComponent>();
|
||||
auto &movement = entity.getComponent<MovableComponent>();
|
||||
auto &grid = entity.get<GridCenteredComponent>();
|
||||
auto &movement = entity.get<MovableComponent>();
|
||||
// movement.addForce(grid.force * )
|
||||
}
|
||||
}
|
||||
@@ -5,22 +5,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <System/System.hpp>
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief The system handling GridCenteredComponent
|
||||
class GridCenteredSystem : public WAL::System
|
||||
class GridCenteredSystem : public WAL::System<GridCenteredComponent, MovableComponent, PositionComponent>
|
||||
{
|
||||
public:
|
||||
void onFixedUpdate(WAL::Entity &entity) override;
|
||||
void onFixedUpdate(WAL::ViewEntity<GridCenteredComponent, MovableComponent, PositionComponent> &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
GridCenteredSystem();
|
||||
explicit GridCenteredSystem(WAL::Wal &wal);
|
||||
//! @brief A GridCenteredSystem is copyable.
|
||||
GridCenteredSystem(const GridCenteredSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~GridCenteredSystem() override = default;
|
||||
//! @brief A GridCenteredSystem is assignable
|
||||
GridCenteredSystem &operator=(const GridCenteredSystem &) = default;
|
||||
//! @brief A system is not assignable
|
||||
GridCenteredSystem &operator=(const GridCenteredSystem &) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,15 +10,13 @@
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
HealthSystem::HealthSystem()
|
||||
: WAL::System({
|
||||
typeid(HealthComponent)
|
||||
})
|
||||
HealthSystem::HealthSystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void HealthSystem::onFixedUpdate(WAL::Entity &entity)
|
||||
void HealthSystem::onFixedUpdate(WAL::ViewEntity<HealthComponent> &entity)
|
||||
{
|
||||
auto &health = entity.getComponent<HealthComponent>();
|
||||
auto &health = entity.get<HealthComponent>();
|
||||
|
||||
if (health.getHealthPoint() == 0)
|
||||
health.onDeath(entity);
|
||||
|
||||
@@ -5,24 +5,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Component/Health/HealthComponent.hpp"
|
||||
#include "System/System.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief A system to handle Health entities.
|
||||
class HealthSystem : public WAL::System
|
||||
class HealthSystem : public WAL::System<HealthComponent>
|
||||
{
|
||||
public:
|
||||
//! @inherit
|
||||
void onFixedUpdate(WAL::Entity &entity) override;
|
||||
void onFixedUpdate(WAL::ViewEntity<HealthComponent> &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
HealthSystem();
|
||||
explicit HealthSystem(WAL::Wal &wal);
|
||||
//! @brief A Health system is copy constructable
|
||||
HealthSystem(const HealthSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~HealthSystem() override = default;
|
||||
//! @brief A Health system is assignable.
|
||||
HealthSystem &operator=(const HealthSystem &) = default;
|
||||
//! @brief A system is not assignable.
|
||||
HealthSystem &operator=(const HealthSystem &) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,28 +3,23 @@
|
||||
// Edited by Benjamin Henry on 2021-05-20.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include "KeyboardSystem.hpp"
|
||||
#include "Component/Keyboard/KeyboardComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Controllers/Keyboard.hpp"
|
||||
|
||||
using Keyboard = RAY::Controller::Keyboard;
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
KeyboardSystem::KeyboardSystem()
|
||||
: WAL::System({
|
||||
typeid(KeyboardComponent),
|
||||
typeid(ControllableComponent)
|
||||
})
|
||||
KeyboardSystem::KeyboardSystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void KeyboardSystem::onFixedUpdate(WAL::Entity &entity)
|
||||
void KeyboardSystem::onFixedUpdate(WAL::ViewEntity<KeyboardComponent, ControllableComponent> &entity)
|
||||
{
|
||||
const auto &keyboard = entity.getComponent<KeyboardComponent>();
|
||||
auto &controllable = entity.getComponent<ControllableComponent>();
|
||||
const auto &keyboard = entity.get<KeyboardComponent>();
|
||||
auto &controllable = entity.get<ControllableComponent>();
|
||||
|
||||
const std::map<KeyboardKey, bool &> keyPressedMap = {
|
||||
{keyboard.keyJump, controllable.jump},
|
||||
|
||||
@@ -7,23 +7,25 @@
|
||||
|
||||
#include "System/System.hpp"
|
||||
#include <map>
|
||||
#include "Component/Keyboard/KeyboardComponent.hpp"
|
||||
#include "Component/Controllable/ControllableComponent.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief A system to handle keyboard entities.
|
||||
class KeyboardSystem : public WAL::System
|
||||
class KeyboardSystem : public WAL::System<KeyboardComponent, ControllableComponent>
|
||||
{
|
||||
public:
|
||||
//! @inherit
|
||||
void onFixedUpdate(WAL::Entity &entity) override;
|
||||
void onFixedUpdate(WAL::ViewEntity<KeyboardComponent, ControllableComponent> &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
KeyboardSystem();
|
||||
explicit KeyboardSystem(WAL::Wal &wal);
|
||||
//! @brief A keyboard system is copy constructable
|
||||
KeyboardSystem(const KeyboardSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~KeyboardSystem() override = default;
|
||||
//! @brief A keyboard system is assignable.
|
||||
KeyboardSystem &operator=(const KeyboardSystem &) = default;
|
||||
//! @brief A system is not assignable.
|
||||
KeyboardSystem &operator=(const KeyboardSystem &) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
MovableSystem::MovableSystem()
|
||||
: WAL::System({
|
||||
typeid(MovableComponent),
|
||||
typeid(PositionComponent)
|
||||
})
|
||||
MovableSystem::MovableSystem(WAL::Wal &wal)
|
||||
: System(wal)
|
||||
{}
|
||||
|
||||
void MovableSystem::onFixedUpdate(WAL::Entity &entity)
|
||||
void MovableSystem::onFixedUpdate(WAL::ViewEntity<MovableComponent, PositionComponent> &entity)
|
||||
{
|
||||
auto &movable = entity.getComponent<MovableComponent>();
|
||||
auto &position = entity.getComponent<PositionComponent>();
|
||||
auto &movable = entity.get<MovableComponent>();
|
||||
auto &position = entity.get<PositionComponent>();
|
||||
|
||||
position.position += movable._velocity;
|
||||
movable._velocity = movable._acceleration;
|
||||
|
||||
@@ -5,25 +5,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Component/Movable/MovableComponent.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include "System/System.hpp"
|
||||
#include "Entity/Entity.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
//! @brief A system to handle movable entities. This system update velocity based on accelerations and positions based on velocity.
|
||||
class MovableSystem : public WAL::System
|
||||
class MovableSystem : public WAL::System<MovableComponent, PositionComponent>
|
||||
{
|
||||
public:
|
||||
//! @inherit
|
||||
void onFixedUpdate(WAL::Entity &entity) override;
|
||||
void onFixedUpdate(WAL::ViewEntity<MovableComponent, PositionComponent> &entity) override;
|
||||
|
||||
//! @brief A default constructor
|
||||
MovableSystem();
|
||||
explicit MovableSystem(WAL::Wal &wal);
|
||||
//! @brief A movable system is copy constructable
|
||||
MovableSystem(const MovableSystem &) = default;
|
||||
//! @brief A default destructor
|
||||
~MovableSystem() override = default;
|
||||
//! @brief A movable system is assignable.
|
||||
MovableSystem &operator=(const MovableSystem &) = default;
|
||||
//! @brief A system is not assignable.
|
||||
MovableSystem &operator=(const MovableSystem &) = delete;
|
||||
};
|
||||
} // namespace WAL
|
||||
|
||||
@@ -8,17 +8,12 @@
|
||||
#include "Component/Renderer/CameraComponent.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include "Component/Renderer/Drawable2DComponent.hpp"
|
||||
#include "Drawables/ADrawable2D.hpp"
|
||||
#include "Drawables/ADrawable3D.hpp"
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
RenderSystem::RenderSystem(WAL::Wal &wal, RAY::Window &window, bool debugMode)
|
||||
: WAL::System({
|
||||
typeid(CameraComponent),
|
||||
typeid(PositionComponent)
|
||||
}),
|
||||
_wal(wal),
|
||||
: System(wal),
|
||||
_window(window),
|
||||
_camera(Vector3f(), Vector3f(), Vector3f(0, 1, 0), 50, CAMERA_PERSPECTIVE),
|
||||
_debugMode(debugMode)
|
||||
@@ -33,26 +28,14 @@ namespace BBM
|
||||
this->_window.clear();
|
||||
|
||||
this->_window.useCamera(this->_camera);
|
||||
for (auto &entity : this->_wal.scene->getEntities()) {
|
||||
if (!entity.hasComponent<Drawable3DComponent>()
|
||||
|| !entity.hasComponent<PositionComponent>())
|
||||
continue;
|
||||
auto &drawable = entity.getComponent<Drawable3DComponent>();
|
||||
auto &pos = entity.getComponent<PositionComponent>();
|
||||
|
||||
for (auto &[_, pos, drawable] : this->_wal.scene->view<PositionComponent, Drawable3DComponent>()) {
|
||||
drawable.drawable->setPosition(pos.position);
|
||||
drawable.drawable->drawOn(this->_window);
|
||||
}
|
||||
this->_window.unuseCamera();
|
||||
|
||||
// TODO sort entities based on the Z axis
|
||||
for (auto &entity : this->_wal.scene->getEntities()) {
|
||||
if (!entity.hasComponent<Drawable2DComponent>()
|
||||
|| !entity.hasComponent<PositionComponent>())
|
||||
continue;
|
||||
auto &drawable = entity.getComponent<Drawable2DComponent>();
|
||||
auto &pos = entity.getComponent<PositionComponent>();
|
||||
|
||||
for (auto &[_, pos, drawable] : this->_wal.scene->view<PositionComponent, Drawable2DComponent>()) {
|
||||
drawable.drawable->setPosition(Vector2f(pos.position.x, pos.position.y));
|
||||
drawable.drawable->drawOn(this->_window);
|
||||
}
|
||||
@@ -61,10 +44,10 @@ namespace BBM
|
||||
this->_window.endDrawing();
|
||||
}
|
||||
|
||||
void RenderSystem::onUpdate(WAL::Entity &entity, std::chrono::nanoseconds dtime)
|
||||
void RenderSystem::onUpdate(WAL::ViewEntity<CameraComponent, PositionComponent> &entity, std::chrono::nanoseconds dtime)
|
||||
{
|
||||
const auto &pos = entity.getComponent<PositionComponent>();
|
||||
const auto &cam = entity.getComponent<CameraComponent>();
|
||||
const auto &pos = entity.get<PositionComponent>();
|
||||
const auto &cam = entity.get<CameraComponent>();
|
||||
_camera.setPosition(pos.position);
|
||||
_camera.setTarget(cam.target);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Component/Renderer/CameraComponent.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include "System/System.hpp"
|
||||
#include "Camera/Camera2D.hpp"
|
||||
#include "Window.hpp"
|
||||
@@ -11,10 +13,8 @@
|
||||
|
||||
namespace BBM
|
||||
{
|
||||
class RenderSystem : public WAL::System
|
||||
class RenderSystem : public WAL::System<CameraComponent, PositionComponent>
|
||||
{
|
||||
//! @brief The ECS to update.
|
||||
WAL::Wal &_wal;
|
||||
|
||||
//! @brief The window to render on
|
||||
RAY::Window &_window;
|
||||
@@ -34,7 +34,7 @@ namespace BBM
|
||||
void onSelfUpdate() override;
|
||||
|
||||
//! @inherit
|
||||
void onUpdate(WAL::Entity &entity, std::chrono::nanoseconds dtime) override;
|
||||
void onUpdate(WAL::ViewEntity<CameraComponent, PositionComponent> &entity, std::chrono::nanoseconds dtime) override;
|
||||
|
||||
//! @brief ctor
|
||||
RenderSystem(WAL::Wal &wal, RAY::Window &window, bool debugMode = true);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Wal.hpp>
|
||||
#include <Scene/Scene.hpp>
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Models/Callback.hpp"
|
||||
|
||||
@@ -36,6 +38,7 @@ TEST_CASE("Callback multiple arguments", "[Callback]")
|
||||
callback.addCallback([](const std::string& str, int a, unsigned *value, Entity &entity) {
|
||||
throw std::runtime_error("");
|
||||
});
|
||||
Entity entity("name");
|
||||
Scene scene;
|
||||
Entity entity(scene, "name");
|
||||
REQUIRE_THROWS_AS(callback("1", 0, nullptr, entity), std::runtime_error);
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#include <catch2/catch.hpp>
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include "Component/Movable/MovableComponent.hpp"
|
||||
#include "System/Movable/MovableSystem.hpp"
|
||||
#include "System/Collision/CollisionSystem.hpp"
|
||||
#include "Wal.hpp"
|
||||
|
||||
#define private public
|
||||
#include "System/Collision/CollisionSystem.hpp"
|
||||
#include "System/Movable/MovableSystem.hpp"
|
||||
#include "Component/Movable/MovableComponent.hpp"
|
||||
#include "Component/Collision/CollisionComponent.hpp"
|
||||
|
||||
using namespace WAL;
|
||||
@@ -21,7 +21,7 @@ TEST_CASE("Collision test", "[Component][System]")
|
||||
{
|
||||
Wal wal;
|
||||
CollisionSystem collision(wal);
|
||||
wal.scene = std::shared_ptr<Scene>(new Scene);
|
||||
wal.scene = std::make_shared<Scene>();
|
||||
wal.scene->addEntity("player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<CollisionComponent>([](Entity &actual, const Entity &) {
|
||||
@@ -32,15 +32,15 @@ TEST_CASE("Collision test", "[Component][System]")
|
||||
pos.position.z = 1;
|
||||
} catch (std::exception &e) {};
|
||||
}, [](Entity &, const Entity &){}, 5.0);
|
||||
Entity &entity = wal.scene->getEntities()[0];
|
||||
Entity &entity = wal.scene->getEntities().front();
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position == Vector3f());
|
||||
|
||||
entity.getComponent<CollisionComponent>().bound.x = 5;
|
||||
entity.getComponent<CollisionComponent>().bound.y = 5;
|
||||
entity.getComponent<CollisionComponent>().bound.z = 5;
|
||||
|
||||
collision.onUpdate(entity, std::chrono::nanoseconds(1));
|
||||
collision.onFixedUpdate(entity);
|
||||
collision.update(std::chrono::nanoseconds(1));
|
||||
collision.fixedUpdate();
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.x == 0.0);
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.y == 0.0);
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.z == 0.0);
|
||||
@@ -48,10 +48,10 @@ TEST_CASE("Collision test", "[Component][System]")
|
||||
wal.scene->addEntity("block")
|
||||
.addComponent<PositionComponent>(2,2,2)
|
||||
.addComponent<CollisionComponent>(1);
|
||||
Entity &player = wal.scene->getEntities()[0];
|
||||
collision.onUpdate(entity, std::chrono::nanoseconds(1));
|
||||
Entity &player = wal.scene->getEntities().front();
|
||||
collision.update(std::chrono::nanoseconds(1));
|
||||
REQUIRE(player.hasComponent(typeid(PositionComponent)));
|
||||
collision.onFixedUpdate(player);
|
||||
collision.fixedUpdate();
|
||||
REQUIRE(wal.scene->getEntities().size() == 2);
|
||||
REQUIRE(player.hasComponent(typeid(PositionComponent)));
|
||||
REQUIRE(player.getComponent<PositionComponent>().position.x == 1.0);
|
||||
@@ -64,8 +64,8 @@ TEST_CASE("Collsion test with movable", "[Component][System]")
|
||||
{
|
||||
Wal wal;
|
||||
CollisionSystem collision(wal);
|
||||
MovableSystem movable;
|
||||
wal.scene = std::shared_ptr<Scene>(new Scene);
|
||||
MovableSystem movable(wal);
|
||||
wal.scene = std::make_shared<Scene>();
|
||||
wal.scene->addEntity("player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<CollisionComponent>([](Entity &actual, const Entity &) {}, [](Entity &actual, const Entity &) {}, 5.0)
|
||||
@@ -76,10 +76,10 @@ TEST_CASE("Collsion test with movable", "[Component][System]")
|
||||
.addComponent<CollisionComponent>([](Entity &actual, const Entity &){}, [](Entity &actual, const Entity &) {
|
||||
try {
|
||||
auto &mov = actual.getComponent<MovableComponent>();
|
||||
mov.resetVelocity();
|
||||
mov._velocity = Vector3f();
|
||||
} catch (std::exception &e) {};
|
||||
}, 1);
|
||||
Entity &entity = wal.scene->getEntities()[0];
|
||||
Entity &entity = wal.scene->getEntities().front();
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position == Vector3f());
|
||||
|
||||
entity.getComponent<CollisionComponent>().bound.x = 5;
|
||||
@@ -87,10 +87,10 @@ TEST_CASE("Collsion test with movable", "[Component][System]")
|
||||
entity.getComponent<CollisionComponent>().bound.z = 5;
|
||||
|
||||
entity.getComponent<MovableComponent>().addForce({1, 1, 1});
|
||||
collision.onUpdate(entity, std::chrono::nanoseconds(1));
|
||||
collision.onFixedUpdate(entity);
|
||||
movable.onUpdate(entity, std::chrono::nanoseconds(1));
|
||||
movable.onFixedUpdate(entity);
|
||||
collision.update(std::chrono::nanoseconds(1));
|
||||
collision.fixedUpdate();
|
||||
movable.update(std::chrono::nanoseconds(1));
|
||||
movable.fixedUpdate();
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.x == 0.0);
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.y == 0.0);
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.z == 0.0);
|
||||
|
||||
@@ -31,7 +31,7 @@ TEST_CASE("Create system", "[Engine][System]")
|
||||
TEST_CASE("Create system by reference", "[Engine][System]")
|
||||
{
|
||||
Wal wal;
|
||||
MovableSystem system;
|
||||
MovableSystem system(wal);
|
||||
wal.addSystem(system);
|
||||
REQUIRE_THROWS_AS(wal.addSystem<MovableSystem>(), DuplicateError);
|
||||
}
|
||||
@@ -5,13 +5,16 @@
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
#include <Wal.hpp>
|
||||
#include <Scene/Scene.hpp>
|
||||
|
||||
using namespace WAL;
|
||||
using namespace BBM;
|
||||
|
||||
TEST_CASE("Component", "[Entity]")
|
||||
{
|
||||
Entity entity("Bob");
|
||||
Scene scene;
|
||||
Entity entity(scene, "Bob");
|
||||
entity.addComponent<PositionComponent>(2, 3, 4);
|
||||
|
||||
SECTION("Check value") {
|
||||
@@ -31,13 +34,15 @@ TEST_CASE("Component", "[Entity]")
|
||||
|
||||
TEST_CASE("ComponentNotFound", "[Entity]")
|
||||
{
|
||||
Entity entity("Bob");
|
||||
Scene scene;
|
||||
Entity entity(scene, "Bob");
|
||||
REQUIRE_THROWS_AS(entity.getComponent<PositionComponent>(), NotFoundError);
|
||||
}
|
||||
|
||||
TEST_CASE("Add component by reference", "[Entity]")
|
||||
{
|
||||
Entity entity("Bob");
|
||||
Scene scene;
|
||||
Entity entity(scene, "Bob");
|
||||
PositionComponent component(entity, 4, 5, 6);
|
||||
|
||||
REQUIRE(&entity.addComponent(component) == &entity);
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include "System/Movable/MovableSystem.hpp"
|
||||
#include "System/Controllable/ControllableSystem.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
#include <Wal.hpp>
|
||||
#include <Component/Controllable/ControllableComponent.hpp>
|
||||
|
||||
#define private public
|
||||
#include "System/Controllable/ControllableSystem.hpp"
|
||||
#include "System/Movable/MovableSystem.hpp"
|
||||
#include <Component/Controllable/ControllableComponent.hpp>
|
||||
#include <Component/Movable/MovableComponent.hpp>
|
||||
|
||||
using namespace WAL;
|
||||
@@ -19,32 +19,33 @@ using namespace BBM;
|
||||
|
||||
TEST_CASE("Move test", "[Component][System]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
Wal wal;
|
||||
wal.scene = std::make_shared<Scene>();
|
||||
wal.scene->addEntity("player")
|
||||
.addComponent<ControllableComponent>()
|
||||
.addComponent<MovableComponent>()
|
||||
.addComponent<PositionComponent>();
|
||||
Entity &entity = scene.getEntities()[0];
|
||||
Entity &entity = wal.scene->getEntities().front();
|
||||
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position == Vector3f());
|
||||
|
||||
entity.getComponent<ControllableComponent>().move = Vector2f(1, 1);
|
||||
|
||||
ControllableSystem controllable;
|
||||
controllable.onUpdate(entity, std::chrono::nanoseconds(1));
|
||||
controllable.onFixedUpdate(entity);
|
||||
ControllableSystem controllable(wal);
|
||||
controllable.update(std::chrono::nanoseconds(1));
|
||||
controllable.fixedUpdate();
|
||||
REQUIRE(entity.getComponent<MovableComponent>()._acceleration.x > 0);
|
||||
REQUIRE(entity.getComponent<MovableComponent>()._acceleration.z > 0);
|
||||
|
||||
MovableSystem movable;
|
||||
movable.onUpdate(entity, std::chrono::nanoseconds(1));
|
||||
movable.onFixedUpdate(entity);
|
||||
MovableSystem movable(wal);
|
||||
movable.update(std::chrono::nanoseconds(1));
|
||||
movable.fixedUpdate();
|
||||
REQUIRE(entity.getComponent<MovableComponent>()._velocity.x > 0);
|
||||
REQUIRE(entity.getComponent<MovableComponent>()._velocity.z > 0);
|
||||
REQUIRE(entity.getComponent<MovableComponent>()._acceleration.x == 0);
|
||||
REQUIRE(entity.getComponent<MovableComponent>()._acceleration.z == 0);
|
||||
movable.onUpdate(entity, std::chrono::nanoseconds(1));
|
||||
movable.onFixedUpdate(entity);
|
||||
movable.update(std::chrono::nanoseconds(1));
|
||||
movable.fixedUpdate();
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.x > 0);
|
||||
REQUIRE(entity.getComponent<PositionComponent>().position.z > 0);
|
||||
|
||||
|
||||
126
tests/ViewTest.cpp
Normal file
126
tests/ViewTest.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// Created by Zoe Roux on 6/3/21.
|
||||
//
|
||||
|
||||
#include "Entity/Entity.hpp"
|
||||
#include "Component/Position/PositionComponent.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
#include <Wal.hpp>
|
||||
#include <Component/Controllable/ControllableComponent.hpp>
|
||||
|
||||
using namespace WAL;
|
||||
using namespace BBM;
|
||||
|
||||
TEST_CASE("View creation", "[View]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<ControllableComponent>();
|
||||
scene.addEntity("Box")
|
||||
.addComponent<PositionComponent>();
|
||||
REQUIRE(scene.view<PositionComponent>().size() == 2);
|
||||
REQUIRE(scene.view<PositionComponent, ControllableComponent>().size() == 1);
|
||||
Entity &entity = *scene.getEntities().begin();
|
||||
Entity &firstView = scene.view<PositionComponent, ControllableComponent>().front();
|
||||
REQUIRE(&entity == &firstView);
|
||||
}
|
||||
|
||||
TEST_CASE("View update", "[View]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<ControllableComponent>();
|
||||
auto &view = scene.view<PositionComponent>();
|
||||
auto &entity = scene.addEntity("Box")
|
||||
.addComponent<PositionComponent>();
|
||||
REQUIRE(view.size() == 2);
|
||||
entity.removeComponent<PositionComponent>();
|
||||
REQUIRE(view.size() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("View cache", "[View]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<ControllableComponent>();
|
||||
auto &view = scene.view<PositionComponent>();
|
||||
REQUIRE(&view == &scene.view<PositionComponent>());
|
||||
}
|
||||
|
||||
TEST_CASE("View cache switch", "[View]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<ControllableComponent>();
|
||||
auto &view = scene.view<PositionComponent>();
|
||||
Scene scene2;
|
||||
scene2.addEntity("box")
|
||||
.addComponent<PositionComponent>();
|
||||
|
||||
REQUIRE(&view == &scene.view<PositionComponent>());
|
||||
REQUIRE(view.front()->getName() == "player");
|
||||
REQUIRE(scene2.view<PositionComponent>().front()->getName() == "box");
|
||||
}
|
||||
|
||||
TEST_CASE("View entity iteration", "[View]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
.addComponent<PositionComponent>()
|
||||
.addComponent<ControllableComponent>();
|
||||
scene.addEntity("Box")
|
||||
.addComponent<PositionComponent>();
|
||||
int i = 0;
|
||||
for (Entity &entity : scene.view<PositionComponent>()) {
|
||||
if (i == 0)
|
||||
REQUIRE(entity.getName() == "player");
|
||||
else
|
||||
REQUIRE(entity.getName() == "Box");
|
||||
i++;
|
||||
}
|
||||
REQUIRE(i == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("ViewEntity<> iteration", "[View]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
.addComponent<PositionComponent>(1, 1, 1)
|
||||
.addComponent<ControllableComponent>();
|
||||
scene.addEntity("Box")
|
||||
.addComponent<PositionComponent>(1, 1, 1);
|
||||
int i = 0;
|
||||
for (auto entity : scene.view<PositionComponent>()) {
|
||||
if (i == 0)
|
||||
REQUIRE(entity->getName() == "player");
|
||||
else
|
||||
REQUIRE(entity->getName() == "Box");
|
||||
REQUIRE(entity.get<PositionComponent>().position == Vector3f(1, 1, 1));
|
||||
i++;
|
||||
}
|
||||
REQUIRE(i == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("View [entity, component] iteration", "[View]")
|
||||
{
|
||||
Scene scene;
|
||||
scene.addEntity("player")
|
||||
.addComponent<PositionComponent>(1, 1, 1)
|
||||
.addComponent<ControllableComponent>();
|
||||
scene.addEntity("Box")
|
||||
.addComponent<PositionComponent>(1, 1, 1);
|
||||
int i = 0;
|
||||
for (auto &[entity, position] : scene.view<PositionComponent>()) {
|
||||
if (i == 0)
|
||||
REQUIRE(entity.getName() == "player");
|
||||
else
|
||||
REQUIRE(entity.getName() == "Box");
|
||||
REQUIRE(position.position == Vector3f(1, 1, 1));
|
||||
i++;
|
||||
}
|
||||
REQUIRE(i == 2);
|
||||
}
|
||||
Reference in New Issue
Block a user