cs381/as6/Entity.hpp

94 lines
2.6 KiB
C++

#pragma once
#include "Component.hpp"
#include <concepts>
#include <functional>
#include <memory>
#include <optional>
#include <vector>
struct Entity;
struct Entity {
std::vector<std::shared_ptr<Component>> components;
GameContext *context = nullptr;
bool queuedForFree = false;
/**
* Injects the global game context/state so the entity and its components can
* stay in sync with the global scroll/meter/reset state and known
* entity references.
*
* @param ctx Current game-wide context containing globals like scroll, entity handles, and
* reset flags.
*/
void SetContext(GameContext *ctx) {
context = ctx;
for (auto &component : components) {
component->context = ctx;
}
}
/**
* Adds a component of type T to the entity, wiring ownership, the game
* context, and calling `Setup` immediately.
*
* @tparam T Component subclass type to add.
* @return Reference to the newly created component.
*/
template <std::derived_from<Component> T> T &AddComponent() {
auto &ptr = components.emplace_back(std::make_shared<T>());
ptr->entity = this;
ptr->context = context;
ptr->Setup();
return static_cast<T &>(*ptr);
}
/**
* Finds the first component of type T in this entity and returns a
* reference_wrapper if found.
*
* @tparam T Component subclass to get.
* @return Optional ref wrapper to the component if found, otherwise empty.
*/
template <std::derived_from<Component> T>
std::optional<std::reference_wrapper<T>> GetComponent() const {
for (auto &c : components) {
T *cast = dynamic_cast<T *>(c.get());
if (cast) {
return *cast;
}
}
return {};
}
/**
* Propagates the delta time to all owned components so they can run their
* per-frame logic while sharing the same global context state.
*
* @param dt Time elapsed since the last frame.
*/
void Update(float dt) {
for (auto &c : components) {
c->Update(dt);
}
}
/**
* Marks the entity for deferred destruction at the end of a systems tick.
* Inspired by Godot!
*/
void QueueFree() { queuedForFree = true; }
/**
* Propagates cleanup call to all owned components so they can release any
* resources or references before the entity is destroyed.
*/
void Cleanup() {
for (auto &c : components) {
c->Cleanup();
}
}
};