Skip to content

Commit

Permalink
ref (arch): refactored architecture (added entity storage)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sara01-s committed Mar 3, 2025
1 parent d834f71 commit 229dc1a
Show file tree
Hide file tree
Showing 15 changed files with 444 additions and 320 deletions.
4 changes: 2 additions & 2 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
position.x += velocity.dx;
position.y += velocity.dy;
});
}
}>

int main() {
vecs::World world;
vecs::world_t world{};

world.spawn_entity(Player, Position {}, Velocity { 1, 1 });
world.add_system(GameState::Update, move_system);
Expand Down
36 changes: 18 additions & 18 deletions examples/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,34 @@
#include <vecs/vecs.hpp>

struct Position {
vecs::f32 x, y;
float x, y, z;
};

struct Velocity {
vecs::f32 dx, dy;
float dx, dy, dz;
};

struct Health {
vecs::u32 value;
void reset() noexcept { value = 100; };
int value;
constexpr void reset() noexcept { value = 100; };
};

int main() {
vecs::component_storage_t<Position, Velocity, Health> component_storage{};
vecs::debug_t::log("Registered components count: ",
component_storage.get_registered_component_count());

vecs::debug_t::log("-------------------------------------------------");
using log_t = vecs::debug_t;
vecs::world_t<Position, Velocity, Health> world{};
log_t::log("-------------------------------------------------");

auto position { Position { 0.0f, 0.0f } };
auto velocity { Velocity { 0.0f, 0.0f } };
auto health { Health { 100 } };

auto const e_id = component_storage.spawn_entity(position, velocity, health);
auto const e_id2 = component_storage.spawn_entity(position, health);
auto const e_id3 = component_storage.spawn_entity(velocity, health);
auto const e_id4 = component_storage.spawn_entity(velocity);
auto const e_id5 = component_storage.spawn_entity(health);
auto position { Position { 1.0f, 1.0f, 0.0f } };
auto velocity { Velocity { 0.0f, 2.0f, 0.0f } };
auto health { Health { 50 } };

world.spawn_entity(position, velocity, health);
auto const entity_id = world.spawn_entity(velocity, health);

world.despawn_entity(entity_id);

world.spawn_entity(velocity);
world.spawn_entity(health);

return 0;
}
Expand Down
5 changes: 5 additions & 0 deletions tests/integration/test_world.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include <catch2/catch_all.hpp>
#include "vecs/world.hpp"

24 changes: 0 additions & 24 deletions tests/test_component_storage.hpp

This file was deleted.

24 changes: 21 additions & 3 deletions tests/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
#define CATCH_CONFIG_ENABLE_BENCHMARKING
#include <catch2/catch_all.hpp>

// tests
#include "test_slotmap.hpp"
#include "test_component_storage.hpp"
// Test data.
struct Position {
float x, y, z;
};

struct Velocity {
float dx, dy, dz;
};

struct Health {
int value { 100 };
};

struct Player {}; // Marker component.

// Unit tests.
#include "unit/test_slotmap.hpp"
#include "unit/test_component_storage.hpp"

// Integration tests.
#include "integration/test_world.hpp"
6 changes: 6 additions & 0 deletions tests/unit/test_component_storage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

// lib
#include <catch2/catch_all.hpp>
#include <vecs/vecs.hpp>

File renamed without changes.
116 changes: 116 additions & 0 deletions vecs/include/vecs/archetype.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#pragma once

// std
#include <tuple>
#include <vector>

// lib
#include "types.hpp"
#include "data_structures/slotmap.hpp"

namespace vecs {

template <Component... Cs>
struct archetype_t final {
public:
static_assert(sizeof...(Cs) > 0,
"Archetype must have at least one component.");

explicit archetype_t(vecs::mask_t mask) : _mask(mask) {}

constexpr vecs::mask_t
mask() const noexcept {
return _mask;
}

constexpr vecs::usize
entity_count() const noexcept {
return std::get<0>(_component_table).size();
}

std::vector<component_key_t>
add_entity(vecs::entity_id_t const entity_id, Cs&&... components) {
// Add a column.
std::vector<component_key_t> cmp_keys{};

// C++17 fold expression for iterating each element in pack `components`.
([&](auto&& component) {
using component_type_t = std::remove_reference_t<decltype(component)>;
auto& component_row =
std::get<component_row_t<component_type_t>>(_component_table);
vecs::component_key_t const key = component_row.push_back(component);

cmp_keys.push_back(key);
} (std::forward<Cs>(components)), ...);

return cmp_keys;
}

template <Component C>
vecs::component_key_t const
store_component(C&& component) {
auto& component_row = std::get<component_row_t<C>>(_component_table);
auto const key = component_row.push_back(component);

return key;
}

template <typename F>
void
for_each(F&& function) {
assert(!std::get<0>(_component_table).empty()
&& "Component table is empty.");

vecs::usize const entity_count { std::get<0>(_component_table).size() };

for (vecs::usize entity_id{}; entity_id < entity_count; ++entity_id) {
std::apply([&function, entity_id](auto&... component_row) {
std::forward<F>(function)(component_row[entity_id]...);
}, _component_table);
}
}

private:
vecs::usize const _component_count { sizeof...(Cs) };

/* An archetype is identified using unique bitset of component masks.
(e.g.):
PositionMask = 0b0001
VelocityMask = 0b0010
HealthMask = 0b0100
(| = bitwise OR operator)
Archetype (A) = PositionMask | VelocityMask | HealthMask = 0b0111
Archetype (B) = PositionMask | VelocityMask = 0b0011
Archetype (C) = VelocityMask | PositionMask = 0b0011
Archetype (D) = PositionMask = 0b0001
Note:
B == C (order or components does not affect the mask).
*/
vecs::mask_t _mask{};

/* Columns = Entity ids.
Rows = Components Types.
Archetype visualization (Mask is 64-bit, truncated here for brevity):
+---------------------------------------------------+
| ARCHETYPE |
+-----------+---------------------------------------+
| Mask | ...0000 0000 0000 0000 0000 0111 |
+-----------+------------+-------------+------------+
| Table | Entity 0 | Entity 1 | Entity 2 |
+-----------+------------+-------------+------------+
| Position | (0.0, 0.0) | (-1.0, 2.0) | (3.2, 1.0) | <- Component row.
| Velocity | (0.0, 0.0) | (1.0, 1.0) | (2.3, 0.0) |
| Health | 100 | 42 | 7 |
+-----------+------------+-------------+------------+
A column in the table represents an entity an it's components!
*/
template <Component T>
using component_row_t = vecs::slotmap_t<T, MAX_REGISTRABLE_COMPONENTS>;
using component_table_t = std::tuple<component_row_t<Cs>...>;
component_table_t _component_table{};
};

} // namespace vecs
Loading

0 comments on commit 229dc1a

Please sign in to comment.