Entity update + components

This commit is contained in:
2026-03-24 09:00:23 +01:00
parent 0c0e7c41af
commit 8f2a4e9ecb
11 changed files with 197 additions and 7 deletions

View File

@@ -15,6 +15,7 @@ namespace Game::AGame {
setText("Hello, World!");
mIsActive = false;
mIsVisible = false;
}
void update(float deltaTime) override {
// Call the base class update to handle input and text refreshing

View File

@@ -0,0 +1,12 @@
#pragma once
#include <game/gamemanager.hpp>
#include <object/entity.hpp>
#include <renderer/texture.hpp>
#include <renderer/font.hpp>
#include <object/sound.hpp>
namespace Game::AGame {
GAME_ENTITY(Trash)
END_GAME_ENTITY()
}

View File

@@ -50,6 +50,13 @@ namespace Game {
static GameStateEnum getCurrentGameState() { return mCurrentGameState; }
static void setCurrentGameState(GameStateEnum newState) { mCurrentGameState = newState; }
template<typename T>
static bool instantiateEntity(std::unique_ptr<T> entity);
template<typename T>
static T* getEntityByName(const std::string& name);
template<typename T>
static void destroyEntity(T* entity);
private:
int mTargetUpdatesPerSecond = TARGET_UPDATE_RATE;
clock::time_point mLastUpdate;
@@ -114,4 +121,26 @@ namespace Game {
return T{};
}
template<typename T>
bool GameManager::instantiateEntity(std::unique_ptr<T> entity) {
static_assert(std::is_base_of_v<Object::Entity, T>, "T must derive from Object::Entity");
State::GameState::getInstance().addEntity(std::move(entity));
return true;
}
template<typename T>
T* GameManager::getEntityByName(const std::string& name) {
static_assert(std::is_base_of_v<Object::Entity, T>, "T must derive from Object::Entity");
Object::Entity* entity = State::GameState::getInstance().getEntityByName(name);
return dynamic_cast<T*>(entity);
}
template<typename T>
void GameManager::destroyEntity(T* entity) {
static_assert(std::is_base_of_v<Object::Entity, T>, "T must derive from Object::Entity");
if (entity) {
State::GameState::getInstance().removeEntity(entity->getName());
}
}
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <utils.hpp>
#include <string>
namespace Game::Object {
class Entity;
}
namespace Game::Object::Components {
class Component {
public:
Component() = default;
// Declare copy and move; in case components declare some other things, we want to make sure those are properly copied/moved as well, so we'll just define these as virtual and implement them in the .cpp file
Component(const Component&);
Component& operator=(const Component&);
Component(Component&&) noexcept;
Component& operator=(Component&&) noexcept;
virtual ~Component() = 0;
virtual void start() = 0;
virtual void update(float deltaTime, Object::Entity* thisEntity) = 0;
// Getters and setters
void setName(const std::string& name);
std::string getName();
void setActive(bool active);
bool isActive();
protected:
// Uniqueness is NOT enforced; be careful when naming!
std::string mName;
bool mIsActive = true;
};
}

View File

@@ -8,6 +8,8 @@
#include <utility>
#include <memory>
#include <renderer/renderer.hpp>
#include <vector>
#include <object/components/component.hpp>
namespace Game::Renderer {
class Renderer;
@@ -44,14 +46,57 @@ namespace Game::Object {
bool isActive() { return mIsActive; }
int getZIndex() const { return mZIndex; }
// Component management
template<typename T, typename... Args>
T* addComponent(Args&&... args);
template<typename T>
T* getComponent();
template<typename T>
bool removeComponent();
void updateComponents(float deltaTime);
protected:
std::string mName;
std::shared_ptr<Game::Renderer::Texture> mTex;
Transform mTransform;
bool mIsFlipped = false; // Whether the texture should be rendered flipped horizontally or not
bool mIsActive;
bool mIsActive = true;
bool mIsVisible = true;
int mZIndex = 0; // For rendering order; higher zIndex renders on top of lower zIndex
float mTiledScale = 1.f; // Only used if the texture is tiled, to determine how much to scale the texture when rendering (since the entire texture is rendered as a single tile, this is necessary to be able to have different sized tiles)
std::vector<std::unique_ptr<Object::Components::Component>> mComponents; // Components attached to this entity; TODO
private:
};
template<typename T, typename... Args>
T* Entity::addComponent(Args&&... args) {
static_assert(std::is_base_of_v<Object::Components::Component, T>, "T must derive from Component");
auto component = std::make_unique<T>(std::forward<Args>(args)...);
T* componentPtr = component.get();
mComponents.push_back(std::move(component));
return componentPtr;
}
template<typename T>
T* Entity::getComponent() {
static_assert(std::is_base_of_v<Object::Components::Component, T>, "T must derive from Component");
for (const auto& component : mComponents) {
if (auto casted = dynamic_cast<T*>(component.get())) {
return casted;
}
}
return nullptr;
}
template<typename T>
bool Entity::removeComponent() {
static_assert(std::is_base_of_v<Object::Components::Component, T>, "T must derive from Component");
for (auto it = mComponents.begin(); it != mComponents.end(); it++) {
if (dynamic_cast<T*>(it->get())) {
mComponents.erase(it);
return true;
}
}
return false;
}
}