diff options
author | jaroWMR <jarorutjes07@gmail.com> | 2024-10-20 13:07:02 +0200 |
---|---|---|
committer | jaroWMR <jarorutjes07@gmail.com> | 2024-10-20 13:07:02 +0200 |
commit | 4ff1159fe5f6ee6dd8becc662bc95a93acda545a (patch) | |
tree | 670caa42ad4ffbf007a6d7cba683f4f84af87592 | |
parent | 0f03cdbf23f57116b7664a7c98c4605fd69bb961 (diff) | |
parent | 77555730e3ddb811b9ce8470659663e3f1573de2 (diff) |
Merge branch 'master' of github.com:lonkaars/crepe into jaro/poc-physics
33 files changed, 614 insertions, 192 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 160d242..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Debug with Ninja", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/mwe/ecs-homemade/build/ecs-homemade.exe", - "args": [], - "stopAtEntry": true, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "preLaunchTask": "build", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "logging": { - "engineLogging": true - } - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 19afa6f..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "configure", - "type": "shell", - "command": "cmake", - "args": [ - "-G", - "Ninja", - "-B", - "${workspaceFolder}/mwe/ecs-homemade/build", // Create build folder here - "${workspaceFolder}/mwe/ecs-homemade" // Path to your source directory - ], - "group": { - "kind": "build", - "isDefault": false - }, - "problemMatcher": [] - }, - { - "label": "build", - "type": "shell", - "command": "cmake", - "args": [ - "--build", - "${workspaceFolder}/mwe/ecs-homemade/build" // Build directory - ], - "dependsOn": "configure", // Ensure the configure task runs first - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": ["$gcc"], - "detail": "Generated task for building the project." - } - ] -} diff --git a/mwe/ecs-homemade/inc/ComponentManager.h b/mwe/ecs-homemade/inc/ComponentManager.h index d368516..0ba358e 100644 --- a/mwe/ecs-homemade/inc/ComponentManager.h +++ b/mwe/ecs-homemade/inc/ComponentManager.h @@ -17,24 +17,27 @@ public: ComponentManager & operator=(const ComponentManager &) = delete; //Singleton ComponentManager & operator=(ComponentManager &&) = delete; //Singleton + //Add a component of a specific type template <typename T, typename... Args> - void AddComponent(std::uint32_t id, - Args &&... args); //Add a component of a specific type + T & 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 and id + void DeleteComponentsById(std::uint32_t id); + //Deletes all components of a specific type 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 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 at specific type and id + 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; //Get a vector<> of all components of a specific type + std::vector<std::reference_wrapper<T>> GetComponentsByType() const; private: static ComponentManager mInstance; //Singleton diff --git a/mwe/ecs-homemade/inc/ComponentManager.hpp b/mwe/ecs-homemade/inc/ComponentManager.hpp index d6da8e8..92db1d4 100644 --- a/mwe/ecs-homemade/inc/ComponentManager.hpp +++ b/mwe/ecs-homemade/inc/ComponentManager.hpp @@ -1,121 +1,128 @@ 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>> +T & 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 (mComponents.find(type) == mComponents.end()) { + //If not, create a new (empty) vector<> of vector<unique_ptr<Component>> + mComponents[type] + = std::vector<std::vector<std::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) + //Resize the vector<> if the id is greater than the current size + if (id >= mComponents[type].size()) { + //Initialize new slots to nullptr (resize does automatically init to nullptr) + mComponents[type].resize(id + 1); } - 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<> + //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)...)); + + return static_cast<T &>(*mComponents[type][id].back().get()); } 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<>) + //Determine the type of T (this is used as the key of the unordered_map<>) + std::type_index type = typeid(T); - if (mComponents.find(type) - != mComponents.end()) { //Find the type (in the unordered_map<>) + //Find the type (in the unordered_map<>) + if (mComponents.find(type) != mComponents.end()) { + //Get the correct vector<> std::vector<std::vector<std::unique_ptr<Component>>> & componentArray - = mComponents[type]; //Get the correct vector<> + = mComponents[type]; - 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 + //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() { - std::type_index type = typeid( - T); //Determine the type of T (this is used as the key of the unordered_map<>) + //Determine the type of T (this is used as the key of the unordered_map<>) + std::type_index type = typeid(T); - if (mComponents.find(type) - != mComponents.end()) { //Find the type (in the unordered_map<>) - mComponents[type] - .clear(); //Clear the whole vector<> of this specific type + //Find the type (in the unordered_map<>) + if (mComponents.find(type) != mComponents.end()) { + //Clear the whole vector<> of this specific type + mComponents[type].clear(); } } 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<>) + //Determine the type of T (this is used as the key of the unordered_map<>) + std::type_index type = typeid(T); - std::vector<std::reference_wrapper<T>> - componentVector; //Create an empty vector<> + //Create an empty vector<> + std::vector<std::reference_wrapper<T>> componentVector; - if (mComponents.find(type) - != mComponents.end()) { //Find the type (in the unordered_map<>) + //Find the type (in the unordered_map<>) + if (mComponents.find(type) != mComponents.end()) { + //Get the correct vector<> const std::vector<std::vector<std::unique_ptr<Component>>> & componentArray - = mComponents.at(type); //Get the correct vector<> + = mComponents.at(type); - if (id - < componentArray - .size()) { //Make sure that the id (that we are looking for) is within the boundaries of the vector<> + //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]) { //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<> + 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 componentVector; //Return the vector<> + //Return the vector<> + return componentVector; } 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<>) + //Determine the type of T (this is used as the key of the unordered_map<>) + std::type_index type = typeid(T); - std::vector<std::reference_wrapper<T>> - componentVector; //Create an empty vector<> + //Create an empty vector<> + std::vector<std::reference_wrapper<T>> componentVector; //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<>) + //Find the type (in the unordered_map<>) + if (mComponents.find(type) != mComponents.end()) { + //Get the correct vector<> const std::vector<std::vector<std::unique_ptr<Component>>> & componentArray - = mComponents.at(type); //Get the correct vector<> + = mComponents.at(type); + //Loop through the whole 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.emplace_back(std::ref( - *castedComponent)); //Pair the dereferenced raw pointer and the id and add it to the vector<> + 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)); } } @@ -123,5 +130,6 @@ ComponentManager::GetComponentsByType() const { } } - return componentVector; //Return the vector<> + //Return the vector<> + return componentVector; } diff --git a/mwe/ecs-homemade/inc/Components.h b/mwe/ecs-homemade/inc/Components.h index 98c5fe7..ad491e7 100644 --- a/mwe/ecs-homemade/inc/Components.h +++ b/mwe/ecs-homemade/inc/Components.h @@ -1,5 +1,6 @@ #pragma once +#include <memory> #include <string> class Component { @@ -31,3 +32,35 @@ public: int mSize; }; + +class IBehaviour { +public: + virtual ~IBehaviour() = default; + virtual void onStart() = 0; + virtual void onUpdate() = 0; +}; + +template <typename T> +class BehaviourWrapper : public IBehaviour { +public: + BehaviourWrapper(); + void onStart() override; + void onUpdate() override; + +private: + T instance; +}; + +class BehaviourScript : public Component { +public: + template <typename T> + void addScript(); + + void onStart(); + void onUpdate(); + +private: + std::unique_ptr<IBehaviour> behaviour; +}; + +#include "Components.hpp" diff --git a/mwe/ecs-homemade/inc/Components.hpp b/mwe/ecs-homemade/inc/Components.hpp new file mode 100644 index 0000000..436a28c --- /dev/null +++ b/mwe/ecs-homemade/inc/Components.hpp @@ -0,0 +1,20 @@ +#include "Components.h" +#include <iostream> + +template <typename T> +BehaviourWrapper<T>::BehaviourWrapper() : instance() {} + +template <typename T> +void BehaviourWrapper<T>::onStart() { + instance.onStart(); +} + +template <typename T> +void BehaviourWrapper<T>::onUpdate() { + instance.onUpdate(); +} + +template <typename T> +void BehaviourScript::addScript() { + behaviour = std::make_unique<BehaviourWrapper<T>>(); +} diff --git a/mwe/ecs-homemade/inc/GameObjectMax.h b/mwe/ecs-homemade/inc/GameObjectMax.h index 3029053..5fab44a 100644 --- a/mwe/ecs-homemade/inc/GameObjectMax.h +++ b/mwe/ecs-homemade/inc/GameObjectMax.h @@ -8,7 +8,7 @@ public: GameObject(std::uint32_t id, std::string name, std::string tag, int layer); template <typename T, typename... Args> - void AddComponent(Args &&... args); + T & 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 91d51ea..2f433bb 100644 --- a/mwe/ecs-homemade/inc/GameObjectMax.hpp +++ b/mwe/ecs-homemade/inc/GameObjectMax.hpp @@ -1,7 +1,7 @@ #include "ComponentManager.h" template <typename T, typename... Args> -void GameObject::AddComponent(Args &&... args) { - ComponentManager::GetInstance().AddComponent<T>( +T & GameObject::AddComponent(Args &&... args) { + return ComponentManager::GetInstance().AddComponent<T>( mId, std::forward<Args>(args)...); } diff --git a/mwe/ecs-homemade/src/Components.cpp b/mwe/ecs-homemade/src/Components.cpp index c8347b3..de8753e 100644 --- a/mwe/ecs-homemade/src/Components.cpp +++ b/mwe/ecs-homemade/src/Components.cpp @@ -9,3 +9,15 @@ Rigidbody::Rigidbody(int mass, int gravityScale, int bodyType) : mMass(mass), mGravityScale(gravityScale), mBodyType(bodyType) {} Colider::Colider(int size) : mSize(size) {} + +void BehaviourScript::onStart() { + if (behaviour) { + behaviour->onStart(); + } +} + +void BehaviourScript::onUpdate() { + if (behaviour) { + behaviour->onUpdate(); + } +} diff --git a/mwe/ecs-homemade/src/main.cpp b/mwe/ecs-homemade/src/main.cpp index 330e154..70c5d2c 100644 --- a/mwe/ecs-homemade/src/main.cpp +++ b/mwe/ecs-homemade/src/main.cpp @@ -7,6 +7,13 @@ #include "Components.h" #include "GameObjectMax.h" +class myScript { +public: + void onStart() { std::cout << "In onStart" << std::endl; } + + void onUpdate() { std::cout << "In onUpdate" << std::endl; } +}; + int main() { auto startAdding = std::chrono::high_resolution_clock::now(); @@ -18,6 +25,7 @@ int main() { gameObject[i]->AddComponent<Sprite>("C:/Test"); gameObject[i]->AddComponent<Rigidbody>(0, 0, i); gameObject[i]->AddComponent<Colider>(i); + gameObject[i]->AddComponent<BehaviourScript>().addScript<myScript>(); } auto stopAdding = std::chrono::high_resolution_clock::now(); @@ -44,6 +52,14 @@ int main() { //std::cout << colider.get().mSize << std::endl; } + std::vector<std::reference_wrapper<BehaviourScript>> scripts + = ComponentManager::GetInstance() + .GetComponentsByType<BehaviourScript>(); + for (BehaviourScript & script : scripts) { + //script.onStart(); + //script.onUpdate(); + } + auto stopLooping = std::chrono::high_resolution_clock::now(); for (int i = 0; i < 100000; ++i) { diff --git a/mwe/ecs-memory-efficient/CMakeLists.txt b/mwe/ecs-memory-efficient/CMakeLists.txt new file mode 100644 index 0000000..d072907 --- /dev/null +++ b/mwe/ecs-memory-efficient/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.5) +project(ecs-memory-efficient) + +# Set the C++ standard (optional, but good practice) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# Use the debug mode (otherwise breakpoints are not compiled) +set(CMAKE_BUILD_TYPE Debug) + +add_executable(ecs-memory-efficient + src/main.cpp + src/ComponentManager.cpp + src/Components.cpp + src/GameObjectMax.cpp +) +target_include_directories(ecs-memory-efficient PRIVATE "${CMAKE_SOURCE_DIR}/inc") diff --git a/mwe/ecs-memory-efficient/inc/ComponentManager.h b/mwe/ecs-memory-efficient/inc/ComponentManager.h new file mode 100644 index 0000000..8279a9a --- /dev/null +++ b/mwe/ecs-memory-efficient/inc/ComponentManager.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Components.h" +#include "ContiguousContainer.h" + +class ComponentManager { +public: + static ComponentManager & GetInstance(); //Singleton + + ComponentManager(const ComponentManager &) = delete; //Singleton + ComponentManager(ComponentManager &&) = delete; //Singleton + ComponentManager & operator=(const ComponentManager &) = delete; //Singleton + ComponentManager & operator=(ComponentManager &&) = delete; //Singleton + + template <typename... Args> + void addSpriteComponent(Args &&... args); + template <typename... Args> + void addRigidbodyComponent(Args &&... args); + template <typename... Args> + void addColiderComponent(Args &&... args); + + std::vector<std::reference_wrapper<Sprite>> getAllSpriteReferences(); + std::vector<std::reference_wrapper<Rigidbody>> getAllRigidbodyReferences(); + std::vector<std::reference_wrapper<Colider>> getAllColiderReferences(); + +private: + static ComponentManager mInstance; //Singleton + + ComponentManager(); //Singleton + + ContiguousContainer<Sprite> mSpriteContainer; + ContiguousContainer<Rigidbody> mRigidbodyContainer; + ContiguousContainer<Colider> mColiderContainer; +}; + +#include "ComponentManager.hpp" diff --git a/mwe/ecs-memory-efficient/inc/ComponentManager.hpp b/mwe/ecs-memory-efficient/inc/ComponentManager.hpp new file mode 100644 index 0000000..a914a6b --- /dev/null +++ b/mwe/ecs-memory-efficient/inc/ComponentManager.hpp @@ -0,0 +1,15 @@ + +template <typename... Args> +void ComponentManager::addSpriteComponent(Args &&... args) { + mSpriteContainer.pushBack(std::forward<Args>(args)...); +} + +template <typename... Args> +void ComponentManager::addRigidbodyComponent(Args &&... args) { + mRigidbodyContainer.pushBack(std::forward<Args>(args)...); +} + +template <typename... Args> +void ComponentManager::addColiderComponent(Args &&... args) { + mColiderContainer.pushBack(std::forward<Args>(args)...); +} diff --git a/mwe/ecs-memory-efficient/inc/Components.h b/mwe/ecs-memory-efficient/inc/Components.h new file mode 100644 index 0000000..98c5fe7 --- /dev/null +++ b/mwe/ecs-memory-efficient/inc/Components.h @@ -0,0 +1,33 @@ +#pragma once + +#include <string> + +class Component { +public: + Component(); + + bool mActive; +}; + +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/mwe/ecs-memory-efficient/inc/ContiguousContainer.h b/mwe/ecs-memory-efficient/inc/ContiguousContainer.h new file mode 100644 index 0000000..e3b57ba --- /dev/null +++ b/mwe/ecs-memory-efficient/inc/ContiguousContainer.h @@ -0,0 +1,34 @@ +#pragma once + +#include <cstdlib> // For malloc and free +#include <new> // For placement new +#include <stdexcept> // For std::bad_alloc +#include <utility> // For std::move and std::forward +#include <vector> // For returning references + +template <typename T> +class ContiguousContainer { +public: + ContiguousContainer(); + ~ContiguousContainer(); + + // Use perfect forwarding for pushBack + template <typename... Args> + void pushBack(Args &&... args); + + void popBack(); + T & operator[](size_t index); + size_t getSize() const; + + // Function to return references to all stored objects + std::vector<std::reference_wrapper<T>> getAllReferences(); + +private: + T * mData; + size_t mSize; + size_t mCapacity; + + void resize(size_t new_capacity); // Resize function to allocate more space +}; + +#include "ContiguousContainer.hpp" diff --git a/mwe/ecs-memory-efficient/inc/ContiguousContainer.hpp b/mwe/ecs-memory-efficient/inc/ContiguousContainer.hpp new file mode 100644 index 0000000..408d5aa --- /dev/null +++ b/mwe/ecs-memory-efficient/inc/ContiguousContainer.hpp @@ -0,0 +1,84 @@ +template <typename T> +ContiguousContainer<T>::ContiguousContainer() : mSize(0), mCapacity(10) { + // Allocate memory for 10 objects initially + mData = static_cast<T *>(malloc(mCapacity * sizeof(T))); + if (!mData) { + throw std::bad_alloc(); + } +} + +template <typename T> +ContiguousContainer<T>::~ContiguousContainer() { + // Destroy all constructed objects + for (size_t i = 0; i < mSize; ++i) { + mData[i].~T(); + } + // Free the allocated memory + free(mData); +} + +template <typename T> +template <typename... Args> +void ContiguousContainer<T>::pushBack(Args &&... args) { + if (mSize == mCapacity) { + // Double the capacity if the container is full + resize(mCapacity * 2); + } + // Use placement new with perfect forwarding to construct the object in place + new (mData + mSize) T(std::forward<Args>(args)...); + ++mSize; +} + +template <typename T> +void ContiguousContainer<T>::popBack() { + if (mSize > 0) { + --mSize; + // Explicitly call the destructor + mData[mSize].~T(); + } +} + +template <typename T> +T & ContiguousContainer<T>::operator[](size_t index) { + if (index >= mSize) { + throw std::out_of_range("Index out of range"); + } + return mData[index]; +} + +template <typename T> +size_t ContiguousContainer<T>::getSize() const { + return mSize; +} + +// Function that returns a vector of references to all stored objects +template <typename T> +std::vector<std::reference_wrapper<T>> +ContiguousContainer<T>::getAllReferences() { + std::vector<std::reference_wrapper<T>> references; + references.reserve(mSize); // Reserve space to avoid reallocation + for (size_t i = 0; i < mSize; ++i) { + references.push_back(std::ref(mData[i])); + } + return references; +} + +template <typename T> +void ContiguousContainer<T>::resize(size_t new_capacity) { + // Allocate new memory block with the updated capacity + T * new_data = static_cast<T *>(malloc(new_capacity * sizeof(T))); + if (!new_data) { + throw std::bad_alloc(); + } + + // Move or copy existing objects to the new memory block + for (size_t i = 0; i < mSize; ++i) { + new (new_data + i) T(std::move(mData[i])); // Move the objects + mData[i].~T(); // Call the destructor for the old object + } + + // Free the old memory block + free(mData); + mData = new_data; + mCapacity = new_capacity; +} diff --git a/mwe/ecs-memory-efficient/inc/GameObjectMax.h b/mwe/ecs-memory-efficient/inc/GameObjectMax.h new file mode 100644 index 0000000..760e330 --- /dev/null +++ b/mwe/ecs-memory-efficient/inc/GameObjectMax.h @@ -0,0 +1,24 @@ +#pragma once + +#include <cstdint> +#include <string> + +class GameObject { +public: + GameObject(std::uint32_t id, std::string name, std::string tag, int layer); + + template <typename... Args> + void addSpriteComponent(Args &&... args); + template <typename... Args> + void addRigidbodyComponent(Args &&... args); + template <typename... Args> + void addColiderComponent(Args &&... args); + + std::uint32_t mId; + std::string mName; + std::string mTag; + bool mActive; + int mLayer; +}; + +#include "GameObjectMax.hpp" diff --git a/mwe/ecs-memory-efficient/inc/GameObjectMax.hpp b/mwe/ecs-memory-efficient/inc/GameObjectMax.hpp new file mode 100644 index 0000000..be3ffa2 --- /dev/null +++ b/mwe/ecs-memory-efficient/inc/GameObjectMax.hpp @@ -0,0 +1,19 @@ +#include "ComponentManager.h" + +template <typename... Args> +void GameObject::addSpriteComponent(Args &&... args) { + ComponentManager::GetInstance().addSpriteComponent( + std::forward<Args>(args)...); +} + +template <typename... Args> +void GameObject::addRigidbodyComponent(Args &&... args) { + ComponentManager::GetInstance().addRigidbodyComponent( + std::forward<Args>(args)...); +} + +template <typename... Args> +void GameObject::addColiderComponent(Args &&... args) { + ComponentManager::GetInstance().addColiderComponent( + std::forward<Args>(args)...); +} diff --git a/mwe/ecs-memory-efficient/src/ComponentManager.cpp b/mwe/ecs-memory-efficient/src/ComponentManager.cpp new file mode 100644 index 0000000..8c1fd23 --- /dev/null +++ b/mwe/ecs-memory-efficient/src/ComponentManager.cpp @@ -0,0 +1,22 @@ +#include "ComponentManager.h" + +ComponentManager ComponentManager::mInstance; + +ComponentManager & ComponentManager::GetInstance() { return mInstance; } + +ComponentManager::ComponentManager() {} + +std::vector<std::reference_wrapper<Sprite>> +ComponentManager::getAllSpriteReferences() { + return mSpriteContainer.getAllReferences(); +} + +std::vector<std::reference_wrapper<Rigidbody>> +ComponentManager::getAllRigidbodyReferences() { + return mRigidbodyContainer.getAllReferences(); +} + +std::vector<std::reference_wrapper<Colider>> +ComponentManager::getAllColiderReferences() { + return mColiderContainer.getAllReferences(); +} diff --git a/mwe/ecs-memory-efficient/src/Components.cpp b/mwe/ecs-memory-efficient/src/Components.cpp new file mode 100644 index 0000000..c8347b3 --- /dev/null +++ b/mwe/ecs-memory-efficient/src/Components.cpp @@ -0,0 +1,11 @@ +#include "Components.h" +#include <iostream> + +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/mwe/ecs-memory-efficient/src/GameObjectMax.cpp b/mwe/ecs-memory-efficient/src/GameObjectMax.cpp new file mode 100644 index 0000000..b0c5af7 --- /dev/null +++ b/mwe/ecs-memory-efficient/src/GameObjectMax.cpp @@ -0,0 +1,7 @@ +#include "GameObjectMax.h" + +#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) {} diff --git a/mwe/ecs-memory-efficient/src/main.cpp b/mwe/ecs-memory-efficient/src/main.cpp new file mode 100644 index 0000000..9c6f2aa --- /dev/null +++ b/mwe/ecs-memory-efficient/src/main.cpp @@ -0,0 +1,59 @@ +#include <chrono> +#include <cstdint> +#include <iostream> +#include <vector> + +#include "ComponentManager.h" +#include "Components.h" +#include "GameObjectMax.h" + +int main() { + auto startAdding = std::chrono::high_resolution_clock::now(); + + GameObject * gameObject[100000]; + + for (int i = 0; i < 100000; ++i) { + gameObject[i] = new GameObject(i, "Name", "Tag", 0); + + gameObject[i]->addSpriteComponent("C:/Test"); + gameObject[i]->addRigidbodyComponent(0, 0, i); + gameObject[i]->addColiderComponent(i); + } + + auto stopAdding = std::chrono::high_resolution_clock::now(); + + //This is what systems would do: + + std::vector<std::reference_wrapper<Sprite>> allSprites + = ComponentManager::GetInstance().getAllSpriteReferences(); + for (Sprite & sprite : allSprites) { + //std::cout << sprite.mPath << std::endl; + } + //std::cout << std::endl; + + std::vector<std::reference_wrapper<Rigidbody>> allRigidbody + = ComponentManager::GetInstance().getAllRigidbodyReferences(); + for (Rigidbody & rigidbody : allRigidbody) { + //std::cout << rigidbody.mMass << " " << rigidbody.mGravityScale << " " << rigidbody.mBodyType << std::endl; + } + //std::cout << std::endl; + + std::vector<std::reference_wrapper<Colider>> allColider + = ComponentManager::GetInstance().getAllColiderReferences(); + for (Colider & colider : allColider) { + //std::cout << colider.mSize << std::endl; + } + + auto stopLooping = std::chrono::high_resolution_clock::now(); + + for (int i = 0; i < 100000; ++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); + std::cout << "AddTime: " << Addtime.count() << " us" << std::endl; + std::cout << "LoopTime: " << LoopTime.count() << " us" << std::endl; +} @@ -8,18 +8,45 @@ This repository contains: |`mwe/`|minimal working examples and proof-of-concepts| |`src/crepe/`|game engine source code| |`src/test/`|unit tests| -|`src/example`|standalone examples using game engine| +|`src/example/`|standalone examples using game engine| ## Compilation This repository uses CMake (the makefile in the root of this repository is for -running auxiliary tasks only). Make sure you have initialized and updated the -submodules before compiling. +running auxiliary tasks only). See [src/readme.md](src/readme.md) for detailed +building instructions. + +## Installing libraries + +The expected library (source) versions are included in this repository as git +submodules. Follow these steps for manually building one of the required +libraries from source: + +1. Ensure the git submodules are initialized: + ``` + $ git submodule update --init --recursive --depth 1 + ``` +2. `cd` into the library source folder: + ``` + $ cd lib/googletest + or + $ cd lib/sdl2 + or + $ cd lib/soloud/contrib + ``` +3. Configure the build, run the build and install: + ``` + $ cmake -B build -G Ninja + $ ninja -C build + # ninja -C build install + ``` ## Documentation -API documentation is done using Doxygen. To generate the docs, run `make -doxygen`. +API documentation is done using Doxygen. To generate the docs, run +``` +$ make doxygen +``` ## Code style diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/ComponentManager.hpp index 084cd33..2ea0c70 100644 --- a/src/crepe/ComponentManager.hpp +++ b/src/crepe/ComponentManager.hpp @@ -10,7 +10,8 @@ template <class T, typename... Args> void ComponentManager::add_component(uint32_t id, Args &&... args) { using namespace std; - static_assert(is_base_of<Component, T>::value, "add_component must recieve a derivative class of Component"); + static_assert(is_base_of<Component, T>::value, + "add_component must recieve a derivative class of Component"); // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); diff --git a/src/crepe/Script.cpp b/src/crepe/Script.cpp index 42e3666..3b83b7c 100644 --- a/src/crepe/Script.cpp +++ b/src/crepe/Script.cpp @@ -2,6 +2,5 @@ using namespace crepe; -void Script::init() { } -void Script::update() { } - +void Script::init() {} +void Script::update() {} diff --git a/src/crepe/Script.h b/src/crepe/Script.h index ba4073a..cdd6814 100644 --- a/src/crepe/Script.h +++ b/src/crepe/Script.h @@ -12,5 +12,4 @@ protected: // added event. }; -} - +} // namespace crepe diff --git a/src/crepe/ScriptSystem.cpp b/src/crepe/ScriptSystem.cpp index e301c71..988bb71 100644 --- a/src/crepe/ScriptSystem.cpp +++ b/src/crepe/ScriptSystem.cpp @@ -4,19 +4,12 @@ using namespace crepe; -ScriptSystem::ScriptSystem() { - dbg_trace(); -} -ScriptSystem::~ScriptSystem() { - dbg_trace(); -} +ScriptSystem::ScriptSystem() { dbg_trace(); } +ScriptSystem::~ScriptSystem() { dbg_trace(); } ScriptSystem & ScriptSystem::get_instance() { static ScriptSystem instance; return instance; } -void ScriptSystem::update() { - dbg_trace(); -} - +void ScriptSystem::update() { dbg_trace(); } diff --git a/src/crepe/ScriptSystem.h b/src/crepe/ScriptSystem.h index e1ed290..72e360b 100644 --- a/src/crepe/ScriptSystem.h +++ b/src/crepe/ScriptSystem.h @@ -14,5 +14,4 @@ private: ~ScriptSystem(); }; -} - +} // namespace crepe diff --git a/src/crepe/System.h b/src/crepe/System.h index 3fe3d66..ecbb7f5 100644 --- a/src/crepe/System.h +++ b/src/crepe/System.h @@ -8,8 +8,8 @@ public: virtual void update() = 0; protected: - System() { }; - virtual ~System() { }; + System() {}; + virtual ~System() {}; private: // singleton @@ -19,5 +19,4 @@ private: System & operator=(System &&) = delete; }; -} - +} // namespace crepe diff --git a/src/crepe/api/BehaviorScript.cpp b/src/crepe/api/BehaviorScript.cpp index 2dd933e..84bfd4c 100644 --- a/src/crepe/api/BehaviorScript.cpp +++ b/src/crepe/api/BehaviorScript.cpp @@ -4,7 +4,4 @@ using namespace crepe::api; -BehaviorScript::BehaviorScript() { - dbg_trace(); -} - +BehaviorScript::BehaviorScript() { dbg_trace(); } diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h index e9542c1..1d05a75 100644 --- a/src/crepe/api/BehaviorScript.h +++ b/src/crepe/api/BehaviorScript.h @@ -1,7 +1,7 @@ #pragma once -#include "../Script.h" #include "../Component.h" +#include "../Script.h" namespace crepe::api { @@ -13,5 +13,4 @@ protected: BehaviorScript(); }; -} - +} // namespace crepe::api diff --git a/src/example/script.cpp b/src/example/script.cpp index 28605c7..a610b83 100644 --- a/src/example/script.cpp +++ b/src/example/script.cpp @@ -3,10 +3,10 @@ * Standalone example for usage of the script component and system */ -#include <crepe/util/log.h> -#include <crepe/ScriptSystem.h> #include <crepe/ComponentManager.h> #include <crepe/GameObject.h> +#include <crepe/ScriptSystem.h> +#include <crepe/util/log.h> #include <crepe/api/BehaviorScript.h> @@ -14,9 +14,7 @@ using namespace crepe; using namespace std; class MyScript : public api::BehaviorScript { - void update() { - dbg_trace(); - } + void update() { dbg_trace(); } }; int main() { @@ -30,4 +28,3 @@ int main() { return 0; } - diff --git a/src/readme.md b/src/readme.md index 1c5d3a2..a4a71e7 100644 --- a/src/readme.md +++ b/src/readme.md @@ -2,7 +2,32 @@ This folder contains the crêpe engine source files, unit tests, and some toy examples. The only target built by default by the CMakeLists.txt in this folder -is the crêpe shared library object. Unit tests can be built by explicitly -specifying the target `test_main` when running the build command. Each source -file in the example/ folder corresponds to a CMake target as well. +is the crêpe shared library object. + +Examples (using Ninja): + +``` +$ cmake -B build -G Ninja +$ ninja -C build +``` + +Unit tests can be built by explicitly specifying the target `test_main` when +running the build command: + +``` +$ ninja -C build test_main +``` + +Each source file in the example/ folder corresponds to a CMake target as well: + +``` +$ ninja -C build audio_internal components_internal +``` + +For installing crêpe system-wide after building (install must be run with +elevated privileges): + +``` +# ninja -C build install +``` |