Skip to content

Commit

Permalink
[Tests/System] Test systems use custom components
Browse files Browse the repository at this point in the history
- Updating a world doesn't (un)link entities that are disabled anymore, nor does it do it for inactive systems

- Reworked the main System unit test by using a World
  - Manually linking them made no sense as it's the World's job
  • Loading branch information
Razakhel committed Feb 27, 2024
1 parent 4007ca0 commit ad9df17
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 142 deletions.
8 changes: 3 additions & 5 deletions include/RaZ/Data/Bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ class Bitset {
explicit Bitset(std::size_t bitCount, bool initVal = false) : m_bits(bitCount, initVal) {}
Bitset(std::initializer_list<bool> values) : m_bits(values) {}

const std::vector<bool>& getBits() const noexcept { return m_bits; }
std::vector<bool>& getBits() noexcept { return m_bits; }
std::size_t getSize() const noexcept { return m_bits.size(); }

bool isEmpty() const noexcept { return (std::find(m_bits.cbegin(), m_bits.cend(), true) == m_bits.cend()); }
std::size_t getEnabledBitCount() const noexcept { return static_cast<std::size_t>(std::count(m_bits.cbegin(), m_bits.cend(), true)); }
std::size_t getDisabledBitCount() const noexcept { return m_bits.size() - getEnabledBitCount(); }
void setBit(std::size_t position, bool value = true);
std::size_t getDisabledBitCount() const noexcept { return (m_bits.size() - getEnabledBitCount()); }
void setBit(std::size_t index, bool value = true);
void resize(std::size_t newSize) { m_bits.resize(newSize); }
void reset() { std::fill(m_bits.begin(), m_bits.end(), false); }
void clear() noexcept { m_bits.clear(); }
Expand All @@ -40,7 +38,7 @@ class Bitset {
Bitset& operator<<=(std::size_t shift);
Bitset& operator>>=(std::size_t shift);
bool operator[](std::size_t index) const noexcept { return m_bits[index]; }
bool operator==(const Bitset& bitset) const noexcept { return std::equal(m_bits.cbegin(), m_bits.cend(), bitset.getBits().cbegin()); }
bool operator==(const Bitset& bitset) const noexcept { return std::equal(m_bits.cbegin(), m_bits.cend(), bitset.m_bits.cbegin()); }
bool operator!=(const Bitset& bitset) const noexcept { return !(*this == bitset); }
friend std::ostream& operator<<(std::ostream& stream, const Bitset& bitset);

Expand Down
24 changes: 12 additions & 12 deletions include/RaZ/Entity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,38 +36,38 @@ class Entity {
/// Disables the entity.
void disable() noexcept { enable(false); }
/// Adds a component to be held by the entity.
/// \tparam Comp Type of the component to be added.
/// \tparam CompT Type of the component to be added.
/// \tparam Args Types of the arguments to be forwarded to the given component.
/// \param args Arguments to be forwarded to the given component.
/// \return Reference to the newly added component.
template <typename Comp, typename... Args> Comp& addComponent(Args&&... args);
template <typename CompT, typename... Args> CompT& addComponent(Args&&... args);
/// Adds a last component to be held by the entity.
/// \tparam Comp Type of the last component to be added.
/// \tparam CompT Type of the last component to be added.
/// \return A tuple containing a reference to the last newly added component.
template <typename Comp> std::tuple<Comp&> addComponents();
template <typename CompT> std::tuple<CompT&> addComponents();
/// Adds several components at once to be held by the entity.
/// \tparam Comp1 Type of the first component to be added.
/// \tparam Comp2 Type of the second component to be added.
/// \tparam C Types of the other components to be added.
/// \return A tuple containing references to all the newly added components.
template <typename Comp1, typename Comp2, typename... C> std::tuple<Comp1&, Comp2&, C...> addComponents();
/// Tells if a given component is held by the entity.
/// \tparam Comp Type of the component to be checked.
/// \tparam CompT Type of the component to be checked.
/// \return True if the entity holds the given component, false otherwise.
template <typename Comp> bool hasComponent() const;
template <typename CompT> bool hasComponent() const;
/// Gets a given component held by the entity.
/// The entity must have this component. If not, an exception is thrown.
/// \tparam Comp Type of the component to be fetched.
/// \tparam CompT Type of the component to be fetched.
/// \return Reference to the found component.
template <typename Comp> const Comp& getComponent() const;
template <typename CompT> const CompT& getComponent() const;
/// Gets a given component held by the entity.
/// The entity must have this component. If not, an exception is thrown.
/// \tparam Comp Type of the component to be fetched.
/// \tparam CompT Type of the component to be fetched.
/// \return Reference to the found component.
template <typename Comp> Comp& getComponent() { return const_cast<Comp&>(static_cast<const Entity*>(this)->getComponent<Comp>()); }
template <typename CompT> CompT& getComponent() { return const_cast<CompT&>(static_cast<const Entity*>(this)->getComponent<CompT>()); }
/// Removes the given component from the entity.
/// \tparam Comp Type of the component to be removed.
template <typename Comp> void removeComponent();
/// \tparam CompT Type of the component to be removed.
template <typename CompT> void removeComponent();

Entity& operator=(const Entity&) = delete;
Entity& operator=(Entity&&) noexcept = delete;
Expand Down
52 changes: 26 additions & 26 deletions include/RaZ/Entity.inl
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,59 @@

namespace Raz {

template <typename Comp, typename... Args>
Comp& Entity::addComponent(Args&&... args) {
static_assert(std::is_base_of_v<Component, Comp>, "Error: The added component must be derived from Component.");
template <typename CompT, typename... Args>
CompT& Entity::addComponent(Args&&... args) {
static_assert(std::is_base_of_v<Component, CompT>, "Error: The added component must be derived from Component.");

const std::size_t compId = Component::getId<Comp>();
const std::size_t compId = Component::getId<CompT>();

if (compId >= m_components.size())
m_components.resize(compId + 1);

m_components[compId] = std::make_unique<Comp>(std::forward<Args>(args)...);
m_components[compId] = std::make_unique<CompT>(std::forward<Args>(args)...);
m_enabledComponents.setBit(compId);

return static_cast<Comp&>(*m_components[compId]);
return static_cast<CompT&>(*m_components[compId]);
}

template <typename Comp>
std::tuple<Comp&> Entity::addComponents() {
static_assert(std::is_base_of_v<Component, Comp>, "Error: The added component must be derived from Component.");
template <typename CompT>
std::tuple<CompT&> Entity::addComponents() {
static_assert(std::is_base_of_v<Component, CompT>, "Error: The added component must be derived from Component.");

return std::forward_as_tuple(addComponent<Comp>());
return std::forward_as_tuple(addComponent<CompT>());
}

template <typename Comp1, typename Comp2, typename... C>
std::tuple<Comp1&, Comp2&, C...> Entity::addComponents() {
static_assert(std::is_base_of_v<Component, Comp1>, "Error: The added component must be derived from Component.");
template <typename CompT1, typename CompT2, typename... C>
std::tuple<CompT1&, CompT2&, C...> Entity::addComponents() {
static_assert(std::is_base_of_v<Component, CompT1>, "Error: The added component must be derived from Component.");

return std::tuple_cat(std::forward_as_tuple(addComponent<Comp1>()), addComponents<Comp2, C...>());
return std::tuple_cat(std::forward_as_tuple(addComponent<CompT1>()), addComponents<CompT2, C...>());
}

template <typename Comp>
template <typename CompT>
bool Entity::hasComponent() const {
static_assert(std::is_base_of_v<Component, Comp>, "Error: The checked component must be derived from Component.");
static_assert(std::is_base_of_v<Component, CompT>, "Error: The checked component must be derived from Component.");

const std::size_t compId = Component::getId<Comp>();
const std::size_t compId = Component::getId<CompT>();
return ((compId < m_components.size()) && m_enabledComponents[compId]);
}

template <typename Comp>
const Comp& Entity::getComponent() const {
static_assert(std::is_base_of_v<Component, Comp>, "Error: The fetched component must be derived from Component.");
template <typename CompT>
const CompT& Entity::getComponent() const {
static_assert(std::is_base_of_v<Component, CompT>, "Error: The fetched component must be derived from Component.");

if (hasComponent<Comp>())
return static_cast<const Comp&>(*m_components[Component::getId<Comp>()]);
if (hasComponent<CompT>())
return static_cast<const CompT&>(*m_components[Component::getId<CompT>()]);

throw std::runtime_error("Error: No component available of specified type");
}

template <typename Comp>
template <typename CompT>
void Entity::removeComponent() {
static_assert(std::is_base_of_v<Component, Comp>, "Error: The removed component must be derived from Component.");
static_assert(std::is_base_of_v<Component, CompT>, "Error: The removed component must be derived from Component.");

if (hasComponent<Comp>()) {
const std::size_t compId = Component::getId<Comp>();
if (hasComponent<CompT>()) {
const std::size_t compId = Component::getId<CompT>();

m_components[compId].reset();
m_enabledComponents.setBit(compId, false);
Expand Down
32 changes: 16 additions & 16 deletions include/RaZ/World.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,47 +24,47 @@ class World {
const std::vector<EntityPtr>& getEntities() const { return m_entities; }

/// Adds a given system to the world.
/// \tparam Sys Type of the system to be added.
/// \tparam SysT Type of the system to be added.
/// \tparam Args Types of the arguments to be forwarded to the given system.
/// \param args Arguments to be forwarded to the given system.
/// \return Reference to the newly added system.
template <typename Sys, typename... Args> Sys& addSystem(Args&&... args);
template <typename SysT, typename... Args> SysT& addSystem(Args&&... args);
/// Tells if a given system exists within the world.
/// \tparam Sys Type of the system to be checked.
/// \tparam SysT Type of the system to be checked.
/// \return True if the given system is present, false otherwise.
template <typename Sys> bool hasSystem() const;
template <typename SysT> bool hasSystem() const;
/// Gets a given system contained by the world.
/// This system must be present within the world. If not, an exception is thrown.
/// \tparam Sys Type of the system to be fetched.
/// \tparam SysT Type of the system to be fetched.
/// \return Constant reference to the found system.
template <typename Sys> const Sys& getSystem() const;
template <typename SysT> const SysT& getSystem() const;
/// Gets a given system contained by the world.
/// This system must be present within the world. If not, an exception is thrown.
/// \tparam Sys Type of the system to be fetched.
/// \tparam SysT Type of the system to be fetched.
/// \return Reference to the found system.
template <typename Sys> Sys& getSystem() { return const_cast<Sys&>(static_cast<const World*>(this)->getSystem<Sys>()); }
template <typename SysT> SysT& getSystem() { return const_cast<SysT&>(static_cast<const World*>(this)->getSystem<SysT>()); }
/// Removes the given system from the world.
/// \tparam Sys Type of the system to be removed.
template <typename Sys> void removeSystem();
/// \tparam SysT Type of the system to be removed.
template <typename SysT> void removeSystem();
/// Adds an entity into the world.
/// \param enabled True if the entity should be active immediately, false otherwise.
/// \return Reference to the newly created entity.
Entity& addEntity(bool enabled = true);
/// Adds an entity into the world with a given component. This entity will be automatically enabled.
/// \tparam Comp Type of the component to be added into the entity.
/// \tparam CompT Type of the component to be added into the entity.
/// \tparam Args Types of the arguments to be forwarded to the given component.
/// \param args Arguments to be forwarded to the given component.
/// \return Reference to the newly added entity.
template <typename Comp, typename... Args> Entity& addEntityWithComponent(Args&&... args);
template <typename CompT, typename... Args> Entity& addEntityWithComponent(Args&&... args);
/// Adds an entity into the world with several components at once.
/// \tparam Comps Types of the components to be added into the entity.
/// \tparam CompsTs Types of the components to be added into the entity.
/// \param enabled True if the entity should be active immediately, false otherwise.
/// \return Reference to the newly added entity.
template <typename... Comps> Entity& addEntityWithComponents(bool enabled = true);
template <typename... CompsTs> Entity& addEntityWithComponents(bool enabled = true);
/// Fetches entities which contain specific component(s).
/// \tparam Comps Types of the components to query.
/// \tparam CompsTs Types of the components to query.
/// \return List of entities containing all given components.
template <typename... Comps> std::vector<Entity*> recoverEntitiesWithComponents();
template <typename... CompsTs> std::vector<Entity*> recoverEntitiesWithComponents();
/// Removes an entity from the world. It *must* be an entity created by this world.
/// \param entity Entity to be removed.
void removeEntity(const Entity& entity);
Expand Down
58 changes: 29 additions & 29 deletions include/RaZ/World.inl
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,71 @@

namespace Raz {

template <typename Sys, typename... Args>
Sys& World::addSystem(Args&&... args) {
static_assert(std::is_base_of_v<System, Sys>, "Error: The added system must be derived from System.");
template <typename SysT, typename... Args>
SysT& World::addSystem(Args&&... args) {
static_assert(std::is_base_of_v<System, SysT>, "Error: The added system must be derived from System.");

const std::size_t sysId = System::getId<Sys>();
const std::size_t systemId = System::getId<SysT>();

if (sysId >= m_systems.size())
m_systems.resize(sysId + 1);
if (systemId >= m_systems.size())
m_systems.resize(systemId + 1);

m_systems[sysId] = std::make_unique<Sys>(std::forward<Args>(args)...);
m_activeSystems.setBit(sysId);
m_systems[systemId] = std::make_unique<SysT>(std::forward<Args>(args)...);
m_activeSystems.setBit(systemId);

return static_cast<Sys&>(*m_systems[sysId]);
return static_cast<SysT&>(*m_systems[systemId]);
}

template <typename Sys>
template <typename SysT>
bool World::hasSystem() const {
static_assert(std::is_base_of_v<System, Sys>, "Error: The checked system must be derived from System.");
static_assert(std::is_base_of_v<System, SysT>, "Error: The checked system must be derived from System.");

const std::size_t sysId = System::getId<Sys>();
return ((sysId < m_systems.size()) && m_systems[sysId]);
const std::size_t systemId = System::getId<SysT>();
return ((systemId < m_systems.size()) && m_systems[systemId]);
}

template <typename Sys>
const Sys& World::getSystem() const {
static_assert(std::is_base_of_v<System, Sys>, "Error: The fetched system must be derived from System.");
template <typename SysT>
const SysT& World::getSystem() const {
static_assert(std::is_base_of_v<System, SysT>, "Error: The fetched system must be derived from System.");

if (hasSystem<Sys>())
return static_cast<const Sys&>(*m_systems[System::getId<Sys>()]);
if (hasSystem<SysT>())
return static_cast<const SysT&>(*m_systems[System::getId<SysT>()]);

throw std::runtime_error("Error: No system available of specified type");
}

template <typename Sys>
template <typename SysT>
void World::removeSystem() {
static_assert(std::is_base_of_v<System, Sys>, "Error: The removed system must be derived from System.");
static_assert(std::is_base_of_v<System, SysT>, "Error: The removed system must be derived from System.");

if (hasSystem<Sys>())
m_systems[System::getId<Sys>()].reset();
if (hasSystem<SysT>())
m_systems[System::getId<SysT>()].reset();
}

template <typename Comp, typename... Args>
template <typename CompT, typename... Args>
Entity& World::addEntityWithComponent(Args&&... args) {
Entity& entity = addEntity();
entity.addComponent<Comp>(std::forward<Args>(args)...);
entity.addComponent<CompT>(std::forward<Args>(args)...);

return entity;
}

template <typename... Comps>
template <typename... CompsTs>
Entity& World::addEntityWithComponents(bool enabled) {
Entity& entity = addEntity(enabled);
entity.addComponents<Comps...>();
entity.addComponents<CompsTs...>();

return entity;
}

template <typename... Comps>
template <typename... CompsTs>
std::vector<Entity*> World::recoverEntitiesWithComponents() {
static_assert((std::is_base_of_v<Component, Comps> && ...), "Error: Components to query the entity with must all be derived from Component.");
static_assert((std::is_base_of_v<Component, CompsTs> && ...), "Error: The components to query the entity with must all be derived from Component.");

std::vector<Entity*> entities;

for (const EntityPtr& entity : m_entities) {
if ((entity->hasComponent<Comps>() && ...))
if ((entity->hasComponent<CompsTs>() && ...))
entities.emplace_back(entity.get());
}

Expand Down
16 changes: 8 additions & 8 deletions src/RaZ/Data/Bitset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,41 @@

namespace Raz {

void Bitset::setBit(std::size_t position, bool value) {
if (position >= m_bits.size())
m_bits.resize(position + 1);
void Bitset::setBit(std::size_t index, bool value) {
if (index >= m_bits.size())
m_bits.resize(index + 1);

m_bits[position] = value;
m_bits[index] = value;
}

Bitset Bitset::operator~() const noexcept {
Bitset res = *this;

for (auto bit : res.getBits())
for (auto bit : res.m_bits)
bit = !bit;

return res;
}

Bitset Bitset::operator&(const Bitset& bitset) const noexcept {
Bitset res(std::min(m_bits.size(), bitset.getSize()));
std::copy(m_bits.cbegin(), m_bits.cbegin() + static_cast<std::ptrdiff_t>(res.getSize()), res.getBits().begin());
std::copy(m_bits.cbegin(), m_bits.cbegin() + static_cast<std::ptrdiff_t>(res.getSize()), res.m_bits.begin());

res &= bitset;
return res;
}

Bitset Bitset::operator|(const Bitset& bitset) const noexcept {
Bitset res(std::min(m_bits.size(), bitset.getSize()));
std::copy(m_bits.cbegin(), m_bits.cbegin() + static_cast<std::ptrdiff_t>(res.getSize()), res.getBits().begin());
std::copy(m_bits.cbegin(), m_bits.cbegin() + static_cast<std::ptrdiff_t>(res.getSize()), res.m_bits.begin());

res |= bitset;
return res;
}

Bitset Bitset::operator^(const Bitset& bitset) const noexcept {
Bitset res(std::min(m_bits.size(), bitset.getSize()));
std::copy(m_bits.cbegin(), m_bits.cbegin() + static_cast<std::ptrdiff_t>(res.getSize()), res.getBits().begin());
std::copy(m_bits.cbegin(), m_bits.cbegin() + static_cast<std::ptrdiff_t>(res.getSize()), res.m_bits.begin());

res ^= bitset;
return res;
Expand Down
Loading

0 comments on commit ad9df17

Please sign in to comment.