|
#pragma once
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <chrono>
|
|
#include <utility>
|
|
#include <ranges>
|
|
#include "transform.h"
|
|
#include "component.h"
|
|
|
|
namespace ant::core {
|
|
struct entity {
|
|
[[nodiscard]] auto transform() const -> ant::core::transform<float> {
|
|
return m_transform;
|
|
}
|
|
auto transform() -> ant::core::transform<float>& {
|
|
return m_transform;
|
|
}
|
|
[[nodiscard]] auto world_transform() const -> ant::core::transform<float> {
|
|
ant::core::transform<float> ret{{0,0},0};
|
|
if(auto parent = m_parent.lock(); parent) {
|
|
ret = parent->world_transform();
|
|
}
|
|
auto transform_pivot = transform();
|
|
if(ret.angle != 0.0f) {
|
|
transform_pivot.position.X *= std::cos(ret.angle*std::numbers::pi/180);
|
|
transform_pivot.position.Y *= std::sin(ret.angle*std::numbers::pi/180);
|
|
}
|
|
return ret + transform_pivot;
|
|
}
|
|
[[nodiscard]] auto parent() const -> std::shared_ptr<entity> {
|
|
return m_parent.lock();
|
|
}
|
|
[[nodiscard]] auto is_visible() const -> bool {
|
|
if(auto parent = m_parent.lock(); parent){
|
|
if(not parent->is_visible()) {
|
|
return false;
|
|
}
|
|
}
|
|
return m_is_visible;
|
|
}
|
|
[[nodiscard]] auto visibility_flag() const -> bool {
|
|
return m_is_visible;
|
|
}
|
|
[[nodiscard]] auto find_components(std::string name) const -> std::vector<std::shared_ptr<component>> {
|
|
decltype(m_components) ret;
|
|
auto source = m_components | std::views::filter([&](const auto& elem) {return name == elem->name();});
|
|
std::ranges::copy(source, std::back_inserter(ret));
|
|
return ret;
|
|
}
|
|
[[nodiscard]] auto components_list() const -> const std::vector<std::shared_ptr<component>>& {
|
|
return m_components;
|
|
}
|
|
[[nodiscard]] auto components_list() -> std::vector<std::shared_ptr<component>>& {
|
|
return m_components;
|
|
}
|
|
template<std::derived_from<component> ComponentType, typename... ARGS>
|
|
auto add_component(ARGS&&... constructor_args) -> std::shared_ptr<entity> {
|
|
auto component = std::make_shared<ComponentType>(std::forward<ARGS>(constructor_args)...);
|
|
auto self = m_self.lock();
|
|
component->m_owner = self;
|
|
m_components.push_back(component);
|
|
component->initialize();
|
|
return self;
|
|
}
|
|
auto set_visible(bool visible) -> bool {
|
|
return std::exchange(m_is_visible, visible);
|
|
}
|
|
virtual void initialize() {}
|
|
virtual void render() {
|
|
if(not visibility_flag()) return;
|
|
for(auto& child : m_children | std::views::filter([](const std::shared_ptr<entity>& elem){return elem->visibility_flag();})) {
|
|
child->render();
|
|
}
|
|
for(auto& component : m_components) {
|
|
component->render();
|
|
}
|
|
}
|
|
virtual void update(std::chrono::duration<double> delta_time) {
|
|
for(auto& child : m_children) {
|
|
child->update(delta_time);
|
|
}
|
|
for(auto& component : m_components) {
|
|
component->update(delta_time);
|
|
}
|
|
}
|
|
|
|
entity(const std::shared_ptr<entity>& parent)
|
|
: m_is_visible(true)
|
|
, m_parent(parent)
|
|
, m_children()
|
|
, m_components()
|
|
, m_transform{.position = {0,0}, .angle = 0}
|
|
{}
|
|
|
|
entity()
|
|
: m_is_visible(true)
|
|
, m_parent(std::shared_ptr<entity>(nullptr))
|
|
, m_children()
|
|
, m_components()
|
|
, m_transform{.position = {0,0}, .angle = 0}
|
|
{}
|
|
private:
|
|
bool m_is_visible;
|
|
std::weak_ptr<entity> m_parent;
|
|
std::weak_ptr<entity> m_self;
|
|
std::vector<std::shared_ptr<entity>> m_children;
|
|
std::vector<std::shared_ptr<component>> m_components;
|
|
ant::core::transform<float> m_transform;
|
|
|
|
template<std::derived_from<entity> EntityType>
|
|
friend auto make_entity(const std::shared_ptr<entity>& parent, auto&&... ARGS) -> std::shared_ptr<EntityType>;
|
|
|
|
template<std::derived_from<entity> EntityType>
|
|
friend auto make_entity(auto&&... ARGS) -> std::shared_ptr<EntityType>;
|
|
};
|
|
|
|
template<std::derived_from<entity> EntityType>
|
|
[[nodiscard]] auto make_entity(const std::shared_ptr<entity>& parent, auto&&... ARGS) -> std::shared_ptr<EntityType> {
|
|
auto object = std::make_shared<EntityType>(std::forward<decltype(ARGS)>(ARGS)...);
|
|
const std::shared_ptr<entity>& entity_router = object;
|
|
entity_router->m_parent = parent;
|
|
entity_router->m_self = object;
|
|
if(parent) {
|
|
parent->m_children.push_back(object);
|
|
}
|
|
object->initialize();
|
|
return object;
|
|
}
|
|
|
|
template<std::derived_from<entity> EntityType>
|
|
[[nodiscard]] auto make_entity(auto&&... ARGS) -> std::shared_ptr<EntityType> {
|
|
auto object = std::make_shared<EntityType>(std::shared_ptr<entity>(nullptr), std::forward<decltype(ARGS)>(ARGS)...);
|
|
const std::shared_ptr<entity>& entity_router = object;
|
|
entity_router->m_parent = std::shared_ptr<entity>(nullptr);
|
|
entity_router->m_self = object;
|
|
object->initialize();
|
|
return object;
|
|
}
|
|
}
|