diff --git a/CMakeLists.txt b/CMakeLists.txt index 19f1444..4165403 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ CPMAddPackage( URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-26.zip ) -set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra") +#set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra") file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp") file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp") diff --git a/include/Engine/Entity/Camera.h b/include/Engine/Entity/Camera.h index e9af842..03e5ad2 100644 --- a/include/Engine/Entity/Camera.h +++ b/include/Engine/Entity/Camera.h @@ -9,5 +9,5 @@ class Engine::Camera : public Renderable { public: void Render() override {}; public: - explicit Camera(const Vector2& position) : Renderable(position) {} + explicit Camera(const Vector2& position) : Renderable(position, 0) {} }; diff --git a/include/Engine/Entity/Entity.h b/include/Engine/Entity/Entity.h index 20a2b4b..b3f5259 100644 --- a/include/Engine/Entity/Entity.h +++ b/include/Engine/Entity/Entity.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace Engine { class Entity; @@ -8,15 +9,21 @@ namespace Engine { class Engine::Entity { protected: + // nullptr means no parent. + Entity* parent = nullptr; + + // Epoch micro-seconds. + long creation_time = 0.0f; std::vector children{}; Vector2 position = {0, 0}; // Assuming 0 radians is up. float face_angle = 0.0f; void UpdateChildren(); public: - // Movements independent of the rotation. + // Movements independent of the face_angle. void MoveX(float speed); void MoveY(float speed); + void Move(float angle_rad, float speed); // Movements dependent on face angle. void MoveForward(float speed); @@ -24,20 +31,29 @@ public: void MoveLeft(float speed); void MoveRight(float speed); - void Move(float angle_rad, float speed); - void Rotate(float speed); void SetRotation(float new_rotation); + // Parent child structure. [[nodiscard]] bool AppendChild(Entity* entity); void DestroyChild(Entity* entity); void RemoveChild(Entity* entity); public: + [[nodiscard]] std::vector GetChildren() const; + [[nodiscard]] Entity* GetParent() const; + + // Microseconds. + [[nodiscard]] long GetCreationTime() const; + [[nodiscard]] long GetAge() const; + [[nodiscard]] float GetRotation() const; [[nodiscard]] Vector2 GetPosition() const; + public: virtual void Update() {} public: - explicit Entity(const Vector2& position, float rotation = 0.0f) : position(position), face_angle(rotation) {} virtual ~Entity(); + explicit Entity(const Vector2& position, float rotation = 0.0f) : + creation_time(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()), + position(position), face_angle(rotation) {} }; \ No newline at end of file diff --git a/include/Engine/Entity/Hud.h b/include/Engine/Entity/Hud.h index a8c04fa..2982a06 100644 --- a/include/Engine/Entity/Hud.h +++ b/include/Engine/Entity/Hud.h @@ -7,5 +7,5 @@ namespace Engine { class Engine::Hud : public Engine::Renderable { public: - Hud() : Renderable({0, 0}, 0) {}; + Hud() : Renderable({0, 0}, 0, 0) {}; }; diff --git a/include/Engine/Entity/Renderable.h b/include/Engine/Entity/Renderable.h index 7fb396c..2f366b2 100644 --- a/include/Engine/Entity/Renderable.h +++ b/include/Engine/Entity/Renderable.h @@ -8,9 +8,15 @@ namespace Engine { } class Engine::Renderable : public Entity { +protected: + // Higher numbers are farther to the back. + unsigned int depth = 0; +public: + [[nodiscard]] unsigned int GetDepth() const { return depth; } + void SetDepth(unsigned int new_depth) { depth = new_depth; } public: // *must* be overridden. virtual void Render() = 0; public: - explicit Renderable(const Vector2& position, float rotation = 0.0f) : Entity(position, rotation) {} + explicit Renderable(const Vector2& position, unsigned int depth = 0, float rotation = 0.0f) : Entity(position, rotation), depth(depth) {} }; \ No newline at end of file diff --git a/include/Engine/Entity/Sprite.h b/include/Engine/Entity/Sprite.h index 8154f9f..2012970 100644 --- a/include/Engine/Entity/Sprite.h +++ b/include/Engine/Entity/Sprite.h @@ -25,6 +25,6 @@ public: void Render() override; public: ~Sprite() override; - explicit Sprite(const Vector2& pos, const float face_angle = 0.0f, const Color4& base_color = Colors::White, Texture* texture = nullptr, - Texture* alpha_mask = nullptr) : Renderable(pos, face_angle), texture(texture), alpha_mask(alpha_mask), base_color(base_color) {} + explicit Sprite(const Vector2& pos, unsigned int depth = 0, const float face_angle = 0.0f, const Color4& base_color = Colors::White, Texture* texture = nullptr, + Texture* alpha_mask = nullptr) : Renderable(pos, depth,face_angle), texture(texture), alpha_mask(alpha_mask), base_color(base_color) {} }; \ No newline at end of file diff --git a/include/Engine/Level/Scene.h b/include/Engine/Level/Scene.h index 97816fa..599e5b9 100644 --- a/include/Engine/Level/Scene.h +++ b/include/Engine/Level/Scene.h @@ -18,6 +18,8 @@ protected: Camera* active_camera = nullptr; std::vector fixed_list{}; std::vector entity_list{}; +protected: + [[nodiscard]] std::vector GetFlatEntityList(const std::vector& entity_list) const; public: [[nodiscard]] bool EntityListContains(const Entity* entity) const; [[nodiscard]] bool FixedListContains(const Fixed* fixed) const; diff --git a/include/Game/Entity/Box.h b/include/Game/Entity/Box.h index 23ed758..bfae2e1 100644 --- a/include/Game/Entity/Box.h +++ b/include/Game/Entity/Box.h @@ -12,5 +12,5 @@ public: void Render() final; void Update() final; public: - explicit Box(const Vector2& position, float rotation = 0.0f) : Renderable(position, rotation) {} + explicit Box(const Vector2& position, unsigned int depth = 0, float rotation = 0.0f) : Renderable(position, depth, rotation) {} }; \ No newline at end of file diff --git a/src/Engine/Entity/Entity.cpp b/src/Engine/Entity/Entity.cpp index fd9cc1f..f9bdd59 100644 --- a/src/Engine/Entity/Entity.cpp +++ b/src/Engine/Entity/Entity.cpp @@ -59,8 +59,11 @@ Vector2 Engine::Entity::GetPosition() const { bool Engine::Entity::AppendChild(Entity* entity) { bool success = false; - if (!Globals::CurrentScene->EntityListContains(entity)) - children.push_back(entity), success = true; + if (!Globals::CurrentScene->EntityListContains(entity)) { + entity->parent = this; + children.push_back(entity); + success = true; + } return success; } @@ -88,3 +91,19 @@ void Engine::Entity::RemoveChild(Entity* entity) { if (it != children.end()) children.erase(it); } + +long Engine::Entity::GetCreationTime() const { + return creation_time; +} + +long Engine::Entity::GetAge() const { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count() - creation_time; +} + +Engine::Entity* Engine::Entity::GetParent() const { + return parent; +} + +std::vector Engine::Entity::GetChildren() const { + return children; +} diff --git a/src/Engine/Level/Scene.cpp b/src/Engine/Level/Scene.cpp index da44098..733b3b9 100644 --- a/src/Engine/Level/Scene.cpp +++ b/src/Engine/Level/Scene.cpp @@ -1,5 +1,6 @@ #include #include +#include bool Engine::Scene::EntityListContains(const Entity* entity) const { for (auto* e : entity_list) @@ -20,7 +21,7 @@ size_t Engine::Scene::FixedCount() const { } size_t Engine::Scene::EntityCount() const { - return entity_list.size(); + return GetFlatEntityList(entity_list).size(); } void Engine::Scene::Update() { @@ -33,24 +34,33 @@ void Engine::Scene::Update() { } void Engine::Scene::Render(RenderTarget* render_target) { - for (auto& f : fixed_list) - if (f->Enabled()) - f->Render(); + // The Camera and the HUD are ignored here because they're special cases. + std::vector display_list{}; + for (auto* e : GetFlatEntityList(entity_list)) + if (auto* r = dynamic_cast(e)) + if (auto* c = dynamic_cast(r); c == nullptr) + if (auto* h = dynamic_cast(c); h == nullptr) + display_list.push_back(r); - // TODO Render order. In this system it's not possible for child entities to be rendered before the parent. + std::sort(display_list.begin(), display_list.end(), [](Renderable* a, Renderable* b) { + return a->GetDepth() > b->GetDepth(); + }); - J2D::Begin(render_target, true); + J2D::Begin( render_target, true); if (active_camera) active_camera->Render(); - for (auto& e : entity_list) - if (auto* r = dynamic_cast(e)) - if (auto* c = dynamic_cast(r); c == nullptr) - r->Render(); + for (auto& f : fixed_list) + if (f->Enabled()) + f->Render(); + + for (auto& r : display_list) + r->Render(); if (heads_up_display) heads_up_display->Render(); + J2D::End(); } @@ -118,3 +128,15 @@ Engine::Camera* Engine::Scene::GetActiveCamera() const { return active_camera; } +std::vector Engine::Scene::GetFlatEntityList(const std::vector& ent_list) const { + std::vector result{}; + + for (auto* e : ent_list) { + auto children = GetFlatEntityList(e->GetChildren()); + for (auto* c : children) + result.push_back(c); + result.push_back(e); + } + return result; +} + diff --git a/src/Game/Scene/ControllableBox.cpp b/src/Game/Scene/ControllableBox.cpp index 42351f3..24575f3 100644 --- a/src/Game/Scene/ControllableBox.cpp +++ b/src/Game/Scene/ControllableBox.cpp @@ -4,7 +4,7 @@ void ControllableBox::Init() { auto* hud = new Game::DemoGameHud(); - auto* b = new Game::Box({0, 0}); - heads_up_display = hud; + auto *b = new Game::Box({0, 0}); AppendEntity(b); + heads_up_display = hud; }