aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax-001 <80035972+Max-001@users.noreply.github.com>2024-10-02 15:26:24 +0200
committerMax-001 <80035972+Max-001@users.noreply.github.com>2024-10-02 15:26:24 +0200
commit2bd37e7d98728d72ba44da18eefea91547a7885a (patch)
tree63ebde9c853c5f683e50ffc4dd8950b08dc48efa
parente409986d9a21ca96ee0b491826eb0008ff6ab8e0 (diff)
Refactored componentManager (it now uses smart pointer, does not return raw pointers (it only returns references) and it is now possible to store multiple components of the same type for the same entity)
-rw-r--r--mwe/ecs-homemade/CMakeLists.txt2
-rw-r--r--mwe/ecs-homemade/inc/ComponentManager.h33
-rw-r--r--mwe/ecs-homemade/inc/ComponentManager.hpp77
-rw-r--r--mwe/ecs-homemade/src/main.cpp20
4 files changed, 65 insertions, 67 deletions
diff --git a/mwe/ecs-homemade/CMakeLists.txt b/mwe/ecs-homemade/CMakeLists.txt
index 2819727..6267c1a 100644
--- a/mwe/ecs-homemade/CMakeLists.txt
+++ b/mwe/ecs-homemade/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.5)
project(ecs-homemade)
# Set the C++ standard (optional, but good practice)
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Use the debug mode (otherwise breakpoints are not compiled)
diff --git a/mwe/ecs-homemade/inc/ComponentManager.h b/mwe/ecs-homemade/inc/ComponentManager.h
index 5b0629f..763c28e 100644
--- a/mwe/ecs-homemade/inc/ComponentManager.h
+++ b/mwe/ecs-homemade/inc/ComponentManager.h
@@ -6,31 +6,38 @@
#include <vector>
#include <typeindex>
#include <memory>
-#include <any>
+#include <utility>
class ComponentManager {
public:
- static ComponentManager& GetInstance();
+ static ComponentManager& GetInstance(); //Singleton
- ComponentManager(const ComponentManager&) = delete;
- ComponentManager(ComponentManager&&) = delete;
- ComponentManager& operator=(const ComponentManager&) = delete;
- ComponentManager& operator=(ComponentManager&&) = delete;
+ 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);
+ void AddComponent(std::uint32_t id, Args&&... args); //Add a component
+ //TODO: void DeleteAllComponentsOfId(std::uint32_t id); //Deletes all components of a specific id
+ //TODO: void DeleteAllComponents(); //Deletes all components
+
template <typename T>
- std::vector<std::reference_wrapper<T>> GetComponentsOfID(std::uint32_t id);
- /*template <typename T>
- std::vector<std::uint32_t> GetAllComponentIDs();
+ std::vector<std::reference_wrapper<T>> GetComponentsByID(std::uint32_t id) const; //Get a vector<> of all components at specific id
template <typename T>
- std::vector<T*> GetAllComponentPointer();*/
+ std::vector<std::pair<std::reference_wrapper<T>, std::uint32_t>> GetComponentsByType() const; //Get a vector<> of all components of a specific type
private:
- static ComponentManager mInstance;
+ static ComponentManager mInstance; //Singleton
- ComponentManager();
+ 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:
+ * 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>>>> mComponents;
};
diff --git a/mwe/ecs-homemade/inc/ComponentManager.hpp b/mwe/ecs-homemade/inc/ComponentManager.hpp
index a7fc30f..03135a8 100644
--- a/mwe/ecs-homemade/inc/ComponentManager.hpp
+++ b/mwe/ecs-homemade/inc/ComponentManager.hpp
@@ -4,68 +4,63 @@ 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 unique_ptr<Component>
+ 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 this automatically)
+ 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 correct 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>
-std::vector<std::reference_wrapper<T>> ComponentManager::GetComponentsOfID(std::uint32_t id) {
- std::type_index type = typeid(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<>
- std::vector<std::reference_wrapper<T>> componentVector;
+ if (mComponents.find(type) != mComponents.end()) { //Find the type (in the unordered_list<>)
- if (mComponents.find(type) != mComponents.end()) {
+ const std::vector<std::vector<std::unique_ptr<Component>>>& componentArray = mComponents.at(type); //Get the correct vector<>
- const auto& componentArray = mComponents[type];
+ 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 (id < componentArray.size()) {
- for (const auto& componentPtr : componentArray[id]) {
- // Use static_cast instead of dynamic_cast
- T* castedComponent = static_cast<T*>(componentPtr.get());
- if (castedComponent) { // Ensure cast was successful
- componentVector.push_back(*castedComponent); // Add the raw pointer to the vector
+ if (castedComponent) { //Ensure that the cast was successful
+ componentVector.push_back(*castedComponent); //Add the dereferenced raw pointer to the vector<>
}
}
}
}
- return componentVector; // Return empty vector if not found
+ return componentVector; //Return the vector<>
}
-/*// GetAllComponentIDs implementation
template <typename T>
-std::vector<std::uint32_t> ComponentManager::GetAllComponentIDs() {
- std::type_index type = typeid(T);
- std::vector<std::uint32_t> ids;
- if (mComponents.find(type) != mComponents.end()) {
- const auto& componentArray = mComponents[type];
- for (std::uint32_t id = 0; id < componentArray.size(); ++id) {
- if (componentArray[id] != nullptr) {
- ids.push_back(id); // Collect IDs of non-null components
- }
- }
- }
- return ids;
-}
+std::vector<std::pair<std::reference_wrapper<T>, std::uint32_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<>)
-// GetAllComponentPointer implementation
-template <typename T>
-std::vector<T*> ComponentManager::GetAllComponentPointer() {
- std::type_index type = typeid(T);
- std::vector<T*> pointers;
- if (mComponents.find(type) != mComponents.end()) {
- const auto& componentArray = mComponents[type];
- for (const auto& component : componentArray) {
- if (component != nullptr) {
- pointers.push_back(static_cast<T*>(component)); // Cast to the correct type
+ std::vector<std::pair<std::reference_wrapper<T>, std::uint32_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_list<>)
+
+ 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
+
+ if (castedComponent) { //Ensure that the cast was successful
+ componentVector.push_back(std::make_pair(std::ref(*castedComponent), id)); //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 pointers;
-}*/
+
+ return componentVector;
+}
diff --git a/mwe/ecs-homemade/src/main.cpp b/mwe/ecs-homemade/src/main.cpp
index 73f710b..f72a044 100644
--- a/mwe/ecs-homemade/src/main.cpp
+++ b/mwe/ecs-homemade/src/main.cpp
@@ -14,6 +14,7 @@ int main() {
//Rigidbody rigidbody0(1, 2, 3);
gameObect0.AddComponent<Sprite>(); //Add a sprite to entity0
gameObect0.AddComponent<Rigidbody>(1, 2, 3); //Also add a rigidbody to entity0
+ gameObect0.AddComponent<Rigidbody>(3, 2, 1); //Add a second rigidbody to entity0
//Rigidbody rigidbody1(4, 5, 6);
gameObect1.AddComponent<Rigidbody>(4, 5, 6); //Only add a rigidbody to entity1
@@ -21,19 +22,14 @@ int main() {
//The entities are now initialized
//Now I will demonstrate some ways of retreiving/getting components
- std::vector<std::reference_wrapper<Rigidbody>> rigidbodyOfEntity0 = ComponentManager::GetInstance().GetComponentsOfID<Rigidbody>(gameObect0.mId); //Get the pointer to the Rigidbody component of entity 0
- std::cout << "rigidbodyOfEntity0: " << rigidbodyOfEntity0[0].get().mMass << " " << rigidbodyOfEntity0[0].get().mGravityScale << " " << rigidbodyOfEntity0[0].get().mBodyType << std::endl;
- std::cout << std::endl;
-
- /*std::vector<std::uint32_t> rigidbodyIDs = ComponentManager::GetInstance().GetAllComponentIDs<Rigidbody>(); //Get all the IDs that have a Rigidbody component
- for(std::uint32_t ID : rigidbodyIDs) {
- std::cout << "Rigidbody ID: " << ID << std::endl;
+ std::vector<std::reference_wrapper<Rigidbody>> rigidbodyOfEntity0 = ComponentManager::GetInstance().GetComponentsByID<Rigidbody>(gameObect0.mId); //Get the pointer to the Rigidbody component of entity 0
+ for(Rigidbody& rigidbodyEntity0 : rigidbodyOfEntity0) {
+ std::cout << "rigidbodyOfEntity0: " << rigidbodyEntity0.mMass << " " << rigidbodyEntity0.mGravityScale << " " << rigidbodyEntity0.mBodyType << std::endl;
+ std::cout << std::endl;
}
- std::cout << std::endl;
- std::vector<Rigidbody*> rigidbodyComponents = ComponentManager::GetInstance().GetAllComponentPointer<Rigidbody>(); //Get all the pointers to the Rigidbody component(s)
- for(Rigidbody* rigidbody : rigidbodyComponents) {
- std::cout << "rigidbody: " << rigidbody->mMass << " " << rigidbody->mGravityScale << " " << rigidbody->mBodyType << std::endl;
+ std::vector<std::pair<std::reference_wrapper<Rigidbody>, std::uint32_t>> rigidBodies = ComponentManager::GetInstance().GetComponentsByType<Rigidbody>();
+ for(auto& [rigidbody, id] : rigidBodies) {
+ std::cout << "Rigidbody of id: " << id << ": " << rigidbody.get().mMass << " " << rigidbody.get().mGravityScale << " " << rigidbody.get().mBodyType << std::endl;
}
- std::cout << std::endl;*/
}