201 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * ECS.h
 | |
|  *
 | |
|  *  Created on: Feb 21, 2020
 | |
|  *      Author: ayoungblood
 | |
|  */
 | |
| 
 | |
| #ifndef SRC_ECS_H_
 | |
| #define SRC_ECS_H_
 | |
| 
 | |
| #include <iostream>
 | |
| #include <vector>
 | |
| #include <memory>
 | |
| #include <algorithm>
 | |
| #include <bitset>
 | |
| #include <array>
 | |
| 
 | |
| class Component;
 | |
| class Entity;
 | |
| class Manager;
 | |
| 
 | |
| using ComponentID = std::size_t;
 | |
| using Group = std::size_t;
 | |
| 
 | |
| inline ComponentID getNewComponentTypeID()
 | |
| {
 | |
| 	static ComponentID lastID = 0u;
 | |
| 	return lastID++;
 | |
| }
 | |
| 
 | |
| 
 | |
| template <typename T> inline ComponentID getComponentTypeID() noexcept
 | |
| {
 | |
| 	static_assert (std::is_base_of<Component, T>::value, "");
 | |
| 	static ComponentID typeID = getNewComponentTypeID();
 | |
| 	return typeID;
 | |
| }
 | |
| 
 | |
| constexpr std::size_t maxComponents = 32;
 | |
| constexpr std::size_t maxGroups = 32;
 | |
| constexpr std::size_t maxEntities = 32;
 | |
| 
 | |
| using ComponentBitSet = std::bitset<maxComponents>;
 | |
| using GroupBitset = std::bitset<maxGroups>;
 | |
| 
 | |
| using ComponentArray = std::array<Component*, maxComponents>;
 | |
| 
 | |
| class Component
 | |
| {
 | |
| public:
 | |
| 	Entity* entity;
 | |
| 
 | |
| 	virtual void init() {}
 | |
| 	virtual void update() {}
 | |
| 	virtual void draw() {}
 | |
| 
 | |
| 	virtual ~Component() {}
 | |
| 
 | |
| };
 | |
| 
 | |
| class Entity
 | |
| {
 | |
| private:
 | |
| 	Manager& manager;
 | |
| 	bool active = true;
 | |
| 	std::vector<std::unique_ptr<Component>> components;
 | |
| 	ComponentArray componentArray;
 | |
| 	ComponentBitSet componentBitSet;
 | |
| 	GroupBitset groupBitset;
 | |
| 
 | |
| public:
 | |
| 	Entity(Manager& mManager) : manager(mManager) {}
 | |
| 
 | |
| 	void update()
 | |
| 	{
 | |
| 		for(auto& c : components) c->update();
 | |
| 	}
 | |
| 	void draw()
 | |
| 	{
 | |
| 		for(auto& c : components) c->draw();
 | |
| 	}
 | |
| 	bool isActive() const { return active; }
 | |
| 	void destroy() { active = false; }
 | |
| 	bool hasGroup(Group mGroup)
 | |
| 	{
 | |
| 		return groupBitset[mGroup];
 | |
| 	}
 | |
| 
 | |
| 	void addGroup(Group mGroup);
 | |
| 	void delGroup(Group mGroup)
 | |
| 	{
 | |
| 		groupBitset[mGroup] = false;
 | |
| 	}
 | |
| 	
 | |
| 	std::string tag;
 | |
|     void setTag(std::string t);
 | |
|     
 | |
|     Entity* getEntity()
 | |
|     {
 | |
|        return this; 
 | |
|     }
 | |
| 
 | |
| 	template <typename T> bool hasComponent() const
 | |
| 	{
 | |
| 		return componentBitSet[getComponentTypeID<T>()];
 | |
| 	}
 | |
| 
 | |
| 	template <typename T, typename... TArgs>
 | |
| 	T& addComponent(TArgs&&... mArgs)
 | |
| 	{
 | |
| 		T* c(new T(std::forward<TArgs>(mArgs)...));
 | |
| 		c->entity = this;
 | |
| 		std::unique_ptr<Component> uPtr{ c };
 | |
| 		components.emplace_back(std::move(uPtr));
 | |
| 
 | |
| 		componentArray[getComponentTypeID<T>()] = c;
 | |
| 		componentBitSet[getComponentTypeID<T>()] = true;
 | |
| 
 | |
| 		c->init();
 | |
| 		return *c;
 | |
| 	}
 | |
| 
 | |
| 	template<typename T> T& getComponent() const
 | |
| 	{
 | |
| 		auto ptr(componentArray[getComponentTypeID<T>()]);
 | |
| 		return *static_cast<T*>(ptr);
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| class Manager
 | |
| {
 | |
| private:
 | |
| 	std::vector<std::unique_ptr<Entity>> entities;
 | |
| 	std::array<std::vector<Entity*>, maxGroups> groupedEntities;
 | |
|     std::vector<std::vector<Entity*>> taggedEntities;
 | |
| public:
 | |
| 	void update()
 | |
| 	{
 | |
| 		for (auto& e : entities) e->update();
 | |
| 	}
 | |
| 	void draw()
 | |
| 	{
 | |
| 		for (auto& e : entities) e->draw();
 | |
| 	}
 | |
| 	void refresh()
 | |
| 	{
 | |
| 		for (auto i(0u); i < maxGroups; i++)
 | |
| 		{
 | |
| 			auto& v(groupedEntities[i]);
 | |
| 			v.erase(
 | |
| 					std::remove_if(std::begin(v), std::end(v),
 | |
| 							[i](Entity* mEntity)
 | |
| 			{
 | |
| 				return !mEntity->isActive() || !mEntity->hasGroup(i);
 | |
| 			}),
 | |
| 			std::end(v));
 | |
| 		}
 | |
| 
 | |
| 		entities.erase(std::remove_if(std::begin(entities), std::end(entities),
 | |
| 				[](const std::unique_ptr<Entity> &mEntity)
 | |
| 				{
 | |
| 					return !mEntity->isActive();
 | |
| 				}),
 | |
| 				std::end(entities));
 | |
| 	}
 | |
| 
 | |
| 	void AddToGroup(Entity* mEntity, Group mGroup)
 | |
| 	{
 | |
| 		groupedEntities[mGroup].emplace_back(mEntity);
 | |
| 	}
 | |
| 	
 | |
| 	std::vector<Entity*> getEntitiesByTag(std::string t)
 | |
|     {
 | |
|         std::vector<Entity*> taggedEntities;
 | |
|         for (int e = 0; e<=entities.size(); e++)
 | |
|         {
 | |
|             if (entities[e]->tag == t)
 | |
|             {
 | |
|                 taggedEntities.emplace_back(entities[e]->getEntity());
 | |
|             }
 | |
|         }
 | |
|         return taggedEntities;
 | |
|     }
 | |
| 
 | |
| 	std::vector<Entity*>& getGroup(Group mGroup)
 | |
| 	{
 | |
| 		return groupedEntities[mGroup];
 | |
| 	}
 | |
| 
 | |
| 	Entity& addEntity()
 | |
| 	{
 | |
| 		Entity* e = new Entity(*this);
 | |
| 		std::unique_ptr<Entity> uPtr{ e };
 | |
| 		entities.emplace_back(std::move(uPtr));
 | |
| 		return *e;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| #endif /* SRC_ECS_H_ */
 |