diff options
| -rw-r--r-- | .clang-format | 1 | ||||
| -rw-r--r-- | contributing.md | 5 | ||||
| -rw-r--r-- | mwe/ecs-homemade/inc/ComponentManager.h | 43 | ||||
| -rw-r--r-- | mwe/ecs-homemade/inc/ComponentManager.hpp | 154 | ||||
| -rw-r--r-- | mwe/ecs-homemade/inc/GameObjectMax.h | 3 | ||||
| -rw-r--r-- | mwe/ecs-homemade/inc/GameObjectMax.hpp | 5 | ||||
| -rw-r--r-- | mwe/ecs-homemade/src/ComponentManager.cpp | 20 | ||||
| -rw-r--r-- | mwe/ecs-homemade/src/Components.cpp | 3 | ||||
| -rw-r--r-- | mwe/ecs-homemade/src/GameObjectMax.cpp | 4 | ||||
| -rw-r--r-- | mwe/ecs-homemade/src/main.cpp | 35 | ||||
| -rw-r--r-- | src/crepe/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | src/crepe/ComponentManager.cpp | 25 | ||||
| -rw-r--r-- | src/crepe/ComponentManager.h | 55 | ||||
| -rw-r--r-- | src/crepe/ComponentManager.hpp | 134 | ||||
| -rw-r--r-- | src/crepe/Components.cpp | 13 | ||||
| -rw-r--r-- | src/crepe/Components.h | 39 | ||||
| -rw-r--r-- | src/crepe/GameObject.cpp | 9 | ||||
| -rw-r--r-- | src/crepe/GameObject.h | 22 | ||||
| -rw-r--r-- | src/crepe/GameObject.hpp | 15 | 
19 files changed, 487 insertions, 106 deletions
diff --git a/.clang-format b/.clang-format index 5d233eb..d2918db 100644 --- a/.clang-format +++ b/.clang-format @@ -22,6 +22,7 @@ AlignTrailingComments:  ReflowComments: false  AlignEscapedNewlines: DontAlign  BreakBeforeBinaryOperators: All +BreakTemplateDeclarations: Yes  ...  # vim: ft=yaml diff --git a/contributing.md b/contributing.md index 2ff411a..933f1bf 100644 --- a/contributing.md +++ b/contributing.md @@ -17,6 +17,11 @@  # Code style  - ASCII only +- Explanatory comments are placed above the line(s) they are explaining +- Source files should only contain comments that plainly state what the code is +  supposed to do +- Explanatory comments in headers may be used to clarify implementation design +  decisions  - Formatting nitty-gritty is handled by clang-format/clang-tidy (run `make    format` in the root folder of this repository to format all sources files)  - When using libraries of which the header include order is important, make diff --git a/mwe/ecs-homemade/inc/ComponentManager.h b/mwe/ecs-homemade/inc/ComponentManager.h index 1a58b01..d368516 100644 --- a/mwe/ecs-homemade/inc/ComponentManager.h +++ b/mwe/ecs-homemade/inc/ComponentManager.h @@ -2,39 +2,44 @@  #include "Components.h"  #include <cstdint> -#include <unordered_map> -#include <vector> -#include <typeindex>  #include <memory> +#include <typeindex> +#include <unordered_map>  #include <utility> +#include <vector>  class ComponentManager {  public: -	static ComponentManager& GetInstance();	//Singleton +	static ComponentManager & GetInstance(); //Singleton -	ComponentManager(const ComponentManager&) = delete;	//Singleton -    ComponentManager(ComponentManager&&) = delete;	//Singleton -    ComponentManager& operator=(const ComponentManager&) = delete;	//Singleton -    ComponentManager& operator=(ComponentManager&&) = delete;	//Singleton +	ComponentManager(const ComponentManager &) = delete; //Singleton +	ComponentManager(ComponentManager &&) = delete; //Singleton +	ComponentManager & operator=(const ComponentManager &) = delete; //Singleton +	ComponentManager & operator=(ComponentManager &&) = delete; //Singleton  	template <typename T, typename... Args> -	void AddComponent(std::uint32_t id, Args&&... args);	//Add a component of a specific type +	void AddComponent(std::uint32_t id, +					  Args &&... args); //Add a component of a specific type  	template <typename T> -	void DeleteComponentsById(std::uint32_t id);	//Deletes all components of a specific type and id +	void DeleteComponentsById( +		std::uint32_t id); //Deletes all components of a specific type and id  	template <typename T> -	void DeleteComponents();	//Deletes all components of a specific type -	void DeleteAllComponentsOfId(std::uint32_t id);	//Deletes all components of a specific id -	void DeleteAllComponents();	//Deletes all components +	void DeleteComponents(); //Deletes all components of a specific type +	void DeleteAllComponentsOfId( +		std::uint32_t id); //Deletes all components of a specific id +	void DeleteAllComponents(); //Deletes all components  	template <typename T> -    std::vector<std::reference_wrapper<T>> GetComponentsByID(std::uint32_t id) const;	//Get a vector<> of all components at specific type and id +	std::vector<std::reference_wrapper<T>> GetComponentsByID(std::uint32_t id) +		const; //Get a vector<> of all components at specific type and id  	template <typename T> -	std::vector<std::reference_wrapper<T>> GetComponentsByType() const;	//Get a vector<> of all components of a specific type +	std::vector<std::reference_wrapper<T>> GetComponentsByType() +		const; //Get a vector<> of all components of a specific type  private: -    static ComponentManager mInstance;	//Singleton +	static ComponentManager mInstance; //Singleton -    ComponentManager();	//Singleton +	ComponentManager(); //Singleton  	/*  	 * The std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>> below might seem a bit strange, let me explain this structure: @@ -42,7 +47,9 @@ private:  	 * The first std::vector<> stores another vector<>. This first vector<> is to bind the entity's id to a component.  	 * The second std::vector<> stores unique_ptrs. Each component can be gathered via an unique_ptr. This second vector<> allows multiple components of the same std::type_index for one entity (id).  	 */ -	std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>> mComponents; +	std::unordered_map<std::type_index, +					   std::vector<std::vector<std::unique_ptr<Component>>>> +		mComponents;  };  #include "ComponentManager.hpp" diff --git a/mwe/ecs-homemade/inc/ComponentManager.hpp b/mwe/ecs-homemade/inc/ComponentManager.hpp index 720ee79..161ce71 100644 --- a/mwe/ecs-homemade/inc/ComponentManager.hpp +++ b/mwe/ecs-homemade/inc/ComponentManager.hpp @@ -1,88 +1,126 @@  template <typename T, typename... Args> -void ComponentManager::AddComponent(std::uint32_t id, Args&&... args) { -    std::type_index type = typeid(T);	//Determine the type of T (this is used as the key of the unordered_map<>) - -    if (mComponents.find(type) == mComponents.end()) {	//Check if this component type is already in the unordered_map<> -        mComponents[type] = std::vector<std::vector<std::unique_ptr<Component>>>();	//If not, create a new (empty) vector<> of vector<unique_ptr<Component>> -    } +void ComponentManager::AddComponent(std::uint32_t id, Args &&... args) { +	std::type_index type = typeid( +		T); //Determine the type of T (this is used as the key of the unordered_map<>) + +	if (mComponents.find(type) +		== mComponents +			   .end()) { //Check if this component type is already in the unordered_map<> +		mComponents[type] = std::vector<std::vector<std::unique_ptr< +			Component>>>(); //If not, create a new (empty) vector<> of vector<unique_ptr<Component>> +	} -    if (id >= mComponents[type].size()) {	//Resize the vector<> if the id is greater than the current size -        mComponents[type].resize(id + 1);	//Initialize new slots to nullptr (resize does automatically init to nullptr) -    } +	if (id +		>= mComponents[type] +			   .size()) { //Resize the vector<> if the id is greater than the current size +		mComponents[type].resize( +			id +			+ 1); //Initialize new slots to nullptr (resize does automatically init to nullptr) +	} -    mComponents[type][id].push_back(std::make_unique<T>(std::forward<Args>(args)...));	//Create a new component of type T using perfect forwarding and store its unique_ptr in the vector<> +	mComponents[type][id].push_back(std::make_unique<T>(std::forward<Args>( +		args)...)); //Create a new component of type T using perfect forwarding and store its unique_ptr in the vector<>  }  template <typename T>  void ComponentManager::DeleteComponentsById(std::uint32_t id) { -	std::type_index type = typeid(T);	//Determine the type of T (this is used as the key of the unordered_map<>) - -	if (mComponents.find(type) != mComponents.end()) {	//Find the type (in the unordered_map<>) -		std::vector<std::vector<std::unique_ptr<Component>>>& componentArray = mComponents[type];	//Get the correct vector<> - -        if (id < componentArray.size()) {	//Make sure that the id (that we are looking for) is within the boundaries of the vector<> -            componentArray[id].clear();	//Clear the whole vector<> of this specific type and id -        } +	std::type_index type = typeid( +		T); //Determine the type of T (this is used as the key of the unordered_map<>) + +	if (mComponents.find(type) +		!= mComponents.end()) { //Find the type (in the unordered_map<>) +		std::vector<std::vector<std::unique_ptr<Component>>> & componentArray +			= mComponents[type]; //Get the correct vector<> + +		if (id +			< componentArray +				  .size()) { //Make sure that the id (that we are looking for) is within the boundaries of the vector<> +			componentArray[id] +				.clear(); //Clear the whole vector<> of this specific type and id +		}  	}  } -template <typename T> -void ComponentManager::DeleteComponents() { -	std::type_index type = typeid(T);	//Determine the type of T (this is used as the key of the unordered_map<>) +template <typename T> void ComponentManager::DeleteComponents() { +	std::type_index type = typeid( +		T); //Determine the type of T (this is used as the key of the unordered_map<>) -	if (mComponents.find(type) != mComponents.end()) {	//Find the type (in the unordered_map<>) -		mComponents[type].clear();	//Clear the whole vector<> of this specific type +	if (mComponents.find(type) +		!= mComponents.end()) { //Find the type (in the unordered_map<>) +		mComponents[type] +			.clear(); //Clear the whole vector<> of this specific type  	}  }  template <typename T> -std::vector<std::reference_wrapper<T>> ComponentManager::GetComponentsByID(std::uint32_t id) const { -    std::type_index type = typeid(T);	//Determine the type of T (this is used as the key of the unordered_map<>) - -	std::vector<std::reference_wrapper<T>> componentVector;	//Create an empty vector<> - -    if (mComponents.find(type) != mComponents.end()) {	//Find the type (in the unordered_map<>) - -        const std::vector<std::vector<std::unique_ptr<Component>>>& componentArray = mComponents.at(type);	//Get the correct vector<> - -        if (id < componentArray.size()) {	//Make sure that the id (that we are looking for) is within the boundaries of the vector<> -            for (const std::unique_ptr<Component>& componentPtr : componentArray[id]) {	//Loop trough the whole vector<> -                T* castedComponent = static_cast<T*>(componentPtr.get());	//Cast the unique_ptr to a raw pointer - -                if (castedComponent) {	//Ensure that the cast was successful -                    componentVector.push_back(*castedComponent); //Add the dereferenced raw pointer to the vector<> -                } -            } -        } -    } +std::vector<std::reference_wrapper<T>> +ComponentManager::GetComponentsByID(std::uint32_t id) const { +	std::type_index type = typeid( +		T); //Determine the type of T (this is used as the key of the unordered_map<>) + +	std::vector<std::reference_wrapper<T>> +		componentVector; //Create an empty vector<> + +	if (mComponents.find(type) +		!= mComponents.end()) { //Find the type (in the unordered_map<>) + +		const std::vector<std::vector<std::unique_ptr<Component>>> & +			componentArray +			= mComponents.at(type); //Get the correct vector<> + +		if (id +			< componentArray +				  .size()) { //Make sure that the id (that we are looking for) is within the boundaries of the vector<> +			for (const std::unique_ptr<Component> & componentPtr : +				 componentArray[id]) { //Loop trough the whole vector<> +				T * castedComponent = static_cast<T *>( +					componentPtr.get()); //Cast the unique_ptr to a raw pointer + +				if (castedComponent) { //Ensure that the cast was successful +					componentVector.push_back( +						*castedComponent); //Add the dereferenced raw pointer to the vector<> +				} +			} +		} +	} -    return componentVector; //Return the vector<> +	return componentVector; //Return the vector<>  }  template <typename T> -std::vector<std::reference_wrapper<T>> ComponentManager::GetComponentsByType() const { -    std::type_index type = typeid(T);	//Determine the type of T (this is used as the key of the unordered_map<>) +std::vector<std::reference_wrapper<T>> +ComponentManager::GetComponentsByType() const { +	std::type_index type = typeid( +		T); //Determine the type of T (this is used as the key of the unordered_map<>) -    std::vector<std::reference_wrapper<T>> componentVector;	//Create an empty vector<> +	std::vector<std::reference_wrapper<T>> +		componentVector; //Create an empty vector<>  	//std::uint32_t id = 0;	//Set the id to 0 (the id will also be stored in the returned vector<>) -    if (mComponents.find(type) != mComponents.end()) {	//Find the type (in the unordered_map<>) +	if (mComponents.find(type) +		!= mComponents.end()) { //Find the type (in the unordered_map<>) -        const std::vector<std::vector<std::unique_ptr<Component>>>& componentArray = mComponents.at(type);	//Get the correct vector<> +		const std::vector<std::vector<std::unique_ptr<Component>>> & +			componentArray +			= mComponents.at(type); //Get the correct vector<> -        for (const std::vector<std::unique_ptr<Component>>& component : componentArray) {	//Loop through the whole vector<> -            for (const std::unique_ptr<Component>& componentPtr : component) {	//Loop trough the whole vector<> -                T* castedComponent = static_cast<T*>(componentPtr.get());	//Cast the unique_ptr to a raw pointer +		for (const std::vector<std::unique_ptr<Component>> & component : +			 componentArray) { //Loop through the whole vector<> +			for (const std::unique_ptr<Component> & componentPtr : +				 component) { //Loop trough the whole vector<> +				T * castedComponent = static_cast<T *>( +					componentPtr.get()); //Cast the unique_ptr to a raw pointer -                if (castedComponent) {	//Ensure that the cast was successful -                    componentVector.emplace_back(std::ref(*castedComponent));	//Pair the dereferenced raw pointer and the id and add it to the vector<> -                } -            } +				if (castedComponent) { //Ensure that the cast was successful +					componentVector.emplace_back(std::ref( +						*castedComponent)); //Pair the dereferenced raw pointer and the id and add it to the vector<> +				} +			}  			//++id;	//Increase the id (the id will also be stored in the returned vector<>) -        } -    } +		} +	} -    return componentVector;	//Return the vector<> +	return componentVector; //Return the vector<>  } diff --git a/mwe/ecs-homemade/inc/GameObjectMax.h b/mwe/ecs-homemade/inc/GameObjectMax.h index f0bcec9..c88a834 100644 --- a/mwe/ecs-homemade/inc/GameObjectMax.h +++ b/mwe/ecs-homemade/inc/GameObjectMax.h @@ -7,8 +7,7 @@ class GameObject {  public:  	GameObject(std::uint32_t id, std::string name, std::string tag, int layer); -	template <typename T, typename... Args> -	void AddComponent(Args&&... args); +	template <typename T, typename... Args> void AddComponent(Args &&... args);  	std::uint32_t mId;  	std::string mName; diff --git a/mwe/ecs-homemade/inc/GameObjectMax.hpp b/mwe/ecs-homemade/inc/GameObjectMax.hpp index 1e952ba..91d51ea 100644 --- a/mwe/ecs-homemade/inc/GameObjectMax.hpp +++ b/mwe/ecs-homemade/inc/GameObjectMax.hpp @@ -1,6 +1,7 @@  #include "ComponentManager.h"  template <typename T, typename... Args> -void GameObject::AddComponent(Args&&... args) { -	ComponentManager::GetInstance().AddComponent<T>(mId, std::forward<Args>(args)...); +void GameObject::AddComponent(Args &&... args) { +	ComponentManager::GetInstance().AddComponent<T>( +		mId, std::forward<Args>(args)...);  } diff --git a/mwe/ecs-homemade/src/ComponentManager.cpp b/mwe/ecs-homemade/src/ComponentManager.cpp index 16cc2b6..536c152 100644 --- a/mwe/ecs-homemade/src/ComponentManager.cpp +++ b/mwe/ecs-homemade/src/ComponentManager.cpp @@ -2,20 +2,22 @@  ComponentManager ComponentManager::mInstance; -ComponentManager& ComponentManager::GetInstance() { -	return mInstance; -} +ComponentManager & ComponentManager::GetInstance() { return mInstance; }  ComponentManager::ComponentManager() {}  void ComponentManager::DeleteAllComponentsOfId(std::uint32_t id) { -    for(auto& [type, componentArray] : mComponents) {	//Loop through all the types (in the unordered_map<>) -        if (id < componentArray.size()) {	//Make sure that the id (that we are looking for) is within the boundaries of the vector<> -            componentArray[id].clear();	//Clear the components at this specific id -        } -    } +	for (auto & [type, componentArray] : +		 mComponents) { //Loop through all the types (in the unordered_map<>) +		if (id +			< componentArray +				  .size()) { //Make sure that the id (that we are looking for) is within the boundaries of the vector<> +			componentArray[id] +				.clear(); //Clear the components at this specific id +		} +	}  }  void ComponentManager::DeleteAllComponents() { -	mComponents.clear();	//Clear the whole unordered_map<> +	mComponents.clear(); //Clear the whole unordered_map<>  } diff --git a/mwe/ecs-homemade/src/Components.cpp b/mwe/ecs-homemade/src/Components.cpp index 69b5eaa..c8347b3 100644 --- a/mwe/ecs-homemade/src/Components.cpp +++ b/mwe/ecs-homemade/src/Components.cpp @@ -5,6 +5,7 @@ Component::Component() : mActive(true) {}  Sprite::Sprite(std::string path) : mPath(path) {} -Rigidbody::Rigidbody(int mass, int gravityScale, int bodyType) : mMass(mass), mGravityScale(gravityScale), mBodyType(bodyType) {} +Rigidbody::Rigidbody(int mass, int gravityScale, int bodyType) +	: mMass(mass), mGravityScale(gravityScale), mBodyType(bodyType) {}  Colider::Colider(int size) : mSize(size) {} diff --git a/mwe/ecs-homemade/src/GameObjectMax.cpp b/mwe/ecs-homemade/src/GameObjectMax.cpp index 62c41de..b0c5af7 100644 --- a/mwe/ecs-homemade/src/GameObjectMax.cpp +++ b/mwe/ecs-homemade/src/GameObjectMax.cpp @@ -2,4 +2,6 @@  #include "ComponentManager.h" -GameObject::GameObject(std::uint32_t id, std::string name, std::string tag, int layer) : mId(id), mName(name), mTag(tag), mActive(true), mLayer(layer) {} +GameObject::GameObject(std::uint32_t id, std::string name, std::string tag, +					   int layer) +	: mId(id), mName(name), mTag(tag), mActive(true), mLayer(layer) {} diff --git a/mwe/ecs-homemade/src/main.cpp b/mwe/ecs-homemade/src/main.cpp index 41f7d6d..330e154 100644 --- a/mwe/ecs-homemade/src/main.cpp +++ b/mwe/ecs-homemade/src/main.cpp @@ -1,54 +1,59 @@ +#include <chrono> +#include <cstdint>  #include <iostream>  #include <vector> -#include <cstdint> -#include <chrono>  #include "ComponentManager.h" -#include "GameObjectMax.h"  #include "Components.h" +#include "GameObjectMax.h"  int main() {  	auto startAdding = std::chrono::high_resolution_clock::now(); -	GameObject* gameObject[100000]; +	GameObject * gameObject[100000]; -	for(int i = 0; i < 100000; ++i) { +	for (int i = 0; i < 100000; ++i) {  		gameObject[i] = new GameObject(i, "Name", "Tag", 0);  		gameObject[i]->AddComponent<Sprite>("C:/Test");  		gameObject[i]->AddComponent<Rigidbody>(0, 0, i);  		gameObject[i]->AddComponent<Colider>(i);  	} -	 +  	auto stopAdding = std::chrono::high_resolution_clock::now();  	//This is what systems would do: -	std::vector<std::reference_wrapper<Sprite>> sprites = ComponentManager::GetInstance().GetComponentsByType<Sprite>(); -	for(Sprite& sprite : sprites) { +	std::vector<std::reference_wrapper<Sprite>> sprites +		= ComponentManager::GetInstance().GetComponentsByType<Sprite>(); +	for (Sprite & sprite : sprites) {  		//std::cout << sprite.get().mPath << std::endl;  	}  	//std::cout << std::endl; -	std::vector<std::reference_wrapper<Rigidbody>> rigidBodies = ComponentManager::GetInstance().GetComponentsByType<Rigidbody>(); -	for(Rigidbody& rigidbody : rigidBodies) { +	std::vector<std::reference_wrapper<Rigidbody>> rigidBodies +		= ComponentManager::GetInstance().GetComponentsByType<Rigidbody>(); +	for (Rigidbody & rigidbody : rigidBodies) {  		//std::cout << rigidbody.get().mMass << " " << rigidbody.get().mGravityScale << " " << rigidbody.get().mBodyType << std::endl;  	}  	//std::cout << std::endl; -	std::vector<std::reference_wrapper<Colider>> coliders = ComponentManager::GetInstance().GetComponentsByType<Colider>(); -	for(Colider& colider : coliders) { +	std::vector<std::reference_wrapper<Colider>> coliders +		= ComponentManager::GetInstance().GetComponentsByType<Colider>(); +	for (Colider & colider : coliders) {  		//std::cout << colider.get().mSize << std::endl;  	}  	auto stopLooping = std::chrono::high_resolution_clock::now();  	for (int i = 0; i < 100000; ++i) { -    	delete gameObject[i]; +		delete gameObject[i];  	} -	auto Addtime = std::chrono::duration_cast<std::chrono::microseconds>(stopAdding - startAdding); -	auto LoopTime = std::chrono::duration_cast<std::chrono::microseconds>(stopLooping - stopAdding); +	auto Addtime = std::chrono::duration_cast<std::chrono::microseconds>( +		stopAdding - startAdding); +	auto LoopTime = std::chrono::duration_cast<std::chrono::microseconds>( +		stopLooping - stopAdding);  	std::cout << "AddTime: " << Addtime.count() << " us" << std::endl;  	std::cout << "LoopTime: " << LoopTime.count() << " us" << std::endl;  } diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index 208ba1f..5840208 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -2,12 +2,20 @@ target_sources(crepe PUBLIC  	Asset.cpp  	Sound.cpp  	SoundContext.cpp +	ComponentManager.cpp +	Components.cpp +	GameObject.cpp  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	Asset.h  	Sound.h  	SoundContext.h +	ComponentManager.h +	ComponentManager.hpp +	Components.h +	GameObject.h +	GameObject.hpp  )  add_subdirectory(api) diff --git a/src/crepe/ComponentManager.cpp b/src/crepe/ComponentManager.cpp new file mode 100644 index 0000000..b7a1bea --- /dev/null +++ b/src/crepe/ComponentManager.cpp @@ -0,0 +1,25 @@ +#include "ComponentManager.h" + +using namespace crepe; + +ComponentManager & ComponentManager::get_instance() { +	static ComponentManager instance; +	return instance; +} + +void ComponentManager::DeleteAllComponentsOfId(std::uint32_t id) { +	// Loop through all the types (in the unordered_map<>) +	for (auto & [type, componentArray] : components) { +		// Make sure that the id (that we are looking for) is within the boundaries of the vector<> +		if (id < componentArray.size()) { +			// Clear the components at this specific id +			componentArray[id].clear(); +		} +	} +} + +void ComponentManager::DeleteAllComponents() { +	// Clear the whole unordered_map<> +	components.clear(); +} + diff --git a/src/crepe/ComponentManager.h b/src/crepe/ComponentManager.h new file mode 100644 index 0000000..003cd0b --- /dev/null +++ b/src/crepe/ComponentManager.h @@ -0,0 +1,55 @@ +#pragma once + +#include <cstdint> +#include <memory> +#include <typeindex> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "Components.h" + +namespace crepe { + +class ComponentManager { +public: +	// Singleton +	static ComponentManager & get_instance(); +	ComponentManager(const ComponentManager &) = delete; +	ComponentManager(ComponentManager &&) = delete; +	ComponentManager & operator=(const ComponentManager &) = delete; +	ComponentManager & operator=(ComponentManager &&) = delete; + +public: +	//! Add a component of a specific type +	template <typename T, typename... Args> void AddComponent(std::uint32_t id, Args &&... args); +	//! Deletes all components of a specific type and id +	template <typename T> void DeleteComponentsById(std::uint32_t id); +	//! Deletes all components of a specific type +	template <typename T> void DeleteComponents(); +	//! Deletes all components of a specific id +	void DeleteAllComponentsOfId(std::uint32_t id); +	//! Deletes all components +	void DeleteAllComponents(); + +	//! Get a vector<> of all components at specific type and id +	template <typename T> std::vector<std::reference_wrapper<T>> GetComponentsByID(std::uint32_t id) const; +	//! Get a vector<> of all components of a specific type +	template <typename T> std::vector<std::reference_wrapper<T>> GetComponentsByType() const; + +private: +	ComponentManager() = default; + +	/* +	 * The std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>> below might seem a bit strange, let me explain this structure: +	 * The std::unordered_map<> has a key and value. The key is a std::type_index and the value is a std::vector. So, a new std::vector will be created for each new std::type_index. +	 * The first std::vector<> stores another vector<>. This first vector<> is to bind the entity's id to a component. +	 * The second std::vector<> stores unique_ptrs. Each component can be gathered via an unique_ptr. This second vector<> allows multiple components of the same std::type_index for one entity (id). +	 */ +	std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>> components; +}; + +} + +// #include "ComponentManager.hpp" + diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/ComponentManager.hpp new file mode 100644 index 0000000..602490e --- /dev/null +++ b/src/crepe/ComponentManager.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include "ComponentManager.h" + +namespace crepe { + +template <typename T, typename... Args> +void ComponentManager::AddComponent(std::uint32_t id, Args &&... args) { +	// Determine the type of T (this is used as the key of the unordered_map<>) +	std::type_index type = typeid(T); + +	// Check if this component type is already in the unordered_map<> +	if (components.find(type) == components.end()) { +		//If not, create a new (empty) vector<> of vector<unique_ptr<Component>> +		components[type] = std::vector<std::vector<std::unique_ptr<Component>>>(); +	} + +	// Resize the vector<> if the id is greater than the current size +	if (id >= components[type].size()) { +		// Initialize new slots to nullptr (resize does automatically init to nullptr) +		components[type].resize(id + 1); +	} + +	// Create a new component of type T using perfect forwarding and store its +	// unique_ptr in the vector<> +	components[type][id].push_back(std::make_unique<T>(std::forward<Args>(args)...)); +} + +template <typename T> +void ComponentManager::DeleteComponentsById(std::uint32_t id) { +	// Determine the type of T (this is used as the key of the unordered_map<>) +	std::type_index type = typeid(T); + +	// Find the type (in the unordered_map<>) +	if (components.find(type) != components.end()) { +		// Get the correct vector<> +		std::vector<std::vector<std::unique_ptr<Component>>> & componentArray = components[type]; + +		// Make sure that the id (that we are looking for) is within the boundaries of the vector<> +		if (id < componentArray.size()) { +			// Clear the whole vector<> of this specific type and id +			componentArray[id].clear(); +		} +	} +} + +template <typename T> +void ComponentManager::DeleteComponents() { +	// Determine the type of T (this is used as the key of the unordered_map<>) +	std::type_index type = typeid(T); + +	// Find the type (in the unordered_map<>) +	if (components.find(type) != components.end()) { +		// Clear the whole vector<> of this specific type +		components[type].clear(); +	} +} + +template <typename T> +std::vector<std::reference_wrapper<T>> +ComponentManager::GetComponentsByID(std::uint32_t id) const { +	// Determine the type of T (this is used as the key of the unordered_map<>) +	std::type_index type = typeid(T); + +	// Create an empty vector<> +	std::vector<std::reference_wrapper<T>> componentVector; + +	// Find the type (in the unordered_map<>) +	if (components.find(type) != components.end()) { +		// Get the correct vector<> +		const std::vector<std::vector<std::unique_ptr<Component>>> & componentArray = components.at(type); + +		// Make sure that the id (that we are looking for) is within the boundaries of the vector<> +		if (id < componentArray .size()) { +			// Loop trough the whole vector<> +			for (const std::unique_ptr<Component> & componentPtr : componentArray[id]) { +				// Cast the unique_ptr to a raw pointer +				T * castedComponent = static_cast<T *>(componentPtr.get()); + +				// Ensure that the cast was successful +				if (castedComponent) { +					// Add the dereferenced raw pointer to the vector<> +					componentVector.push_back(*castedComponent); +				} +			} +		} +	} + +	// Return the vector<> +	return componentVector; +} + +template <typename T> +std::vector<std::reference_wrapper<T>> +ComponentManager::GetComponentsByType() const { +	// Determine the type of T (this is used as the key of the unordered_map<>) +	std::type_index type = typeid(T); + +	// Create an empty vector<> +	std::vector<std::reference_wrapper<T>> componentVector; +	// Set the id to 0 (the id will also be stored in the returned vector<>) +	// std::uint32_t id = 0; + +	// Find the type (in the unordered_map<>) +	if (components.find(type) != components.end()) { + +		// Get the correct vector<> +		const std::vector<std::vector<std::unique_ptr<Component>>> & componentArray = components.at(type); + +		// Loop through the whole vector<> +		for (const std::vector<std::unique_ptr<Component>> & component : componentArray) { +			// Loop trough the whole vector<> +			for (const std::unique_ptr<Component> & componentPtr : component) { +				// Cast the unique_ptr to a raw pointer +				T * castedComponent = static_cast<T *>(componentPtr.get()); + +				// Ensure that the cast was successful +				if (castedComponent) { +					// Pair the dereferenced raw pointer and the id and add it to the vector<> +					componentVector.emplace_back(std::ref(*castedComponent)); +				} +			} + +			// Increase the id (the id will also be stored in the returned vector<>) +			//++id; +		} +	} + +	// Return the vector<> +	return componentVector; +} + +} + diff --git a/src/crepe/Components.cpp b/src/crepe/Components.cpp new file mode 100644 index 0000000..9760daa --- /dev/null +++ b/src/crepe/Components.cpp @@ -0,0 +1,13 @@ +#include "Components.h" +#include <iostream> + +using namespace crepe; + +Component::Component() : mActive(true) {} + +Sprite::Sprite(std::string path) : mPath(path) {} + +Rigidbody::Rigidbody(int mass, int gravityScale, int bodyType) +	: mMass(mass), mGravityScale(gravityScale), mBodyType(bodyType) {} + +Colider::Colider(int size) : mSize(size) {} diff --git a/src/crepe/Components.h b/src/crepe/Components.h new file mode 100644 index 0000000..7cb6fbb --- /dev/null +++ b/src/crepe/Components.h @@ -0,0 +1,39 @@ +#pragma once + +#include <string> + +namespace crepe { + +class Component { +public: +	Component(); + +	bool mActive; +}; + +// TODO: these should be in separate files + +class Sprite : public Component { +public: +	Sprite(std::string path); + +	std::string mPath; +}; + +class Rigidbody : public Component { +public: +	Rigidbody(int mass, int gravityScale, int bodyType); + +	int mMass; +	int mGravityScale; +	int mBodyType; +}; + +class Colider : public Component { +public: +	Colider(int size); + +	int mSize; +}; + +} diff --git a/src/crepe/GameObject.cpp b/src/crepe/GameObject.cpp new file mode 100644 index 0000000..5ac9d7a --- /dev/null +++ b/src/crepe/GameObject.cpp @@ -0,0 +1,9 @@ +#include "GameObject.h" + +#include "ComponentManager.h" + +using namespace crepe; + +GameObject::GameObject(std::uint32_t id, std::string name, std::string tag, +					   int layer) +	: mId(id), mName(name), mTag(tag), mActive(true), mLayer(layer) {} diff --git a/src/crepe/GameObject.h b/src/crepe/GameObject.h new file mode 100644 index 0000000..71ef60d --- /dev/null +++ b/src/crepe/GameObject.h @@ -0,0 +1,22 @@ +#pragma once + +#include <cstdint> +#include <string> + +namespace crepe { + +class GameObject { +public: +	GameObject(std::uint32_t id, std::string name, std::string tag, int layer); + +	template <typename T, typename... Args> void AddComponent(Args &&... args); + +	std::uint32_t mId; +	std::string mName; +	std::string mTag; +	bool mActive; +	int mLayer; +}; + +} + diff --git a/src/crepe/GameObject.hpp b/src/crepe/GameObject.hpp new file mode 100644 index 0000000..5a672cf --- /dev/null +++ b/src/crepe/GameObject.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "GameObject.h" + +#include "ComponentManager.h" + +namespace crepe { + +template <typename T, typename... Args> +void GameObject::AddComponent(Args &&... args) { +	ComponentManager::get_instance().AddComponent<T>(mId, std::forward<Args>(args)...); +} + +} +  |