Skip to content

Instantly share code, notes, and snippets.

@remyroez
Last active July 7, 2017 17:05
Show Gist options
  • Save remyroez/249361d006f50dd1972766accc8795f4 to your computer and use it in GitHub Desktop.
Save remyroez/249361d006f50dd1972766accc8795f4 to your computer and use it in GitHub Desktop.
簡易 Entity Component System 雛形
#include <iostream>
#include <tuple>
#include <vector>
#include <unordered_map>
#include <string>
#include <cassert>
#include <functional>
#include <typeinfo>
#include <deque>
namespace ecs {
using entity_id = unsigned int;
template <typename... Args>
class system {
public:
using data_type = std::tuple<std::vector<Args>...>;
using component_initializer_type = std::tuple<Args...>;
using component_index_type = std::size_t;
using free_component_index_container = std::deque<component_index_type>;
using entity_map_type = std::unordered_map<entity_id, component_index_type>;
system() : _size(0) {}
template <std::size_t Index>
auto get_members() {
return std::get<Index>(data());
}
void add_component(entity_id id, component_initializer_type &&initializer) {
const auto last_size = size();
if (register_entity(id, last_size)) {
get_component_from_index(last_size) = initializer;
_size++;
}
}
void add_component(entity_id id, Args&&... args) {
add_component(id, std::make_tuple(std::forward<Args>(args)...));
}
void remove_component(entity_id id) {
auto index = get_component_index(id);
push_component_index(index);
deregister_entity(id);
}
auto get_component(entity_id id) {
return get_component_from_index(get_component_index(id));
}
const data_type &data() const { return _data; }
data_type &data() { return _data; }
std::size_t size() const { return _size; }
protected:
template <std::size_t Index, typename Tuple>
static decltype(auto) get_element(Tuple &tuple, component_index_type index) {
auto &container = std::get<Index>(tuple);
if (index >= container.size()) {
container.resize(index + 1);
}
return container[index];
}
template <typename T, std::size_t... Indices>
static auto make_component_handle(T &tuple, component_index_type index, std::index_sequence<Indices...>) {
(void)index;
return std::tie(get_element<Indices>(tuple, index)...);
}
auto get_component_from_index(component_index_type index) {
return make_component_handle(data(), index, std::index_sequence_for<Args...>());
}
bool register_entity(entity_id id, component_index_type index) {
return entity_map().emplace(id, index).second;
}
bool deregister_entity(entity_id id) {
return (entity_map().erase(id) > 0);
}
component_index_type get_component_index(entity_id id) const {
return entity_map().at(id);
}
const entity_map_type &entity_map() const { return _entity_map; }
entity_map_type &entity_map() { return _entity_map; }
component_index_type make_component_index() {
component_index_type index = size();
if (has_free_component_index()) {
index = pop_component_index();
}
return index;
}
void push_component_index(component_index_type index) {
_free_component_indices.push_back(index);
}
component_index_type pop_component_index() {
auto index = _free_component_indices.front();
_free_component_indices.pop_back();
return index;
}
bool has_free_component_index() const {
return !_free_component_indices.empty();
}
private:
entity_map_type _entity_map;
free_component_index_container _free_component_indices;
data_type _data;
std::size_t _size;
};
} // namespace ecs
void test_system()
{
std::cout << "test_system ----------" << std::endl;
ecs::system<int, int, std::string> system;
system.add_component(100, 123, 456, "foo");
system.add_component(200, 789, 741, "bar");
system.add_component(300, 852, 963, "baz");
auto component = system.get_component(100);
std::get<0>(component) = 173;
std::cout
<< std::get<0>(component) << ", "
<< std::get<1>(component) << ", "
<< std::get<2>(component)
<< std::endl;
std::cout << std::endl;
for (auto a : system.get_members<2>()) {
std::cout << a << std::endl;
}
std::cout << std::endl;
}
void test_empty_system()
{
std::cout << "test_empty_system ----------" << std::endl;
ecs::system<> system;
system.add_component(123);
auto component = system.get_component(123);
std::cout << typeid(component).name() << std::endl;
std::cout << std::endl;
}
void test_component()
{
std::cout << "test_component ----------" << std::endl;
struct position {
using target = std::tuple<float&, float&>;
constexpr static decltype(auto) x(target &tuple) { return std::get<0>(tuple); }
constexpr static decltype(auto) y(target &tuple) { return std::get<1>(tuple); }
};
ecs::system<float, float> system;
system.add_component(100, 123.456f, 456.0f);
auto component = system.get_component(100);
position::x(component) = 789.123f;
std::cout << position::x(component) << std::endl;
std::cout << std::endl;
}
int main()
{
test_system();
test_empty_system();
test_component();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment