From 2279b3ff4597493c3f8ecfb76a9c5892ac7abb5f Mon Sep 17 00:00:00 2001 From: Joey Pollack Date: Wed, 14 Sep 2022 15:05:38 -0400 Subject: [PATCH] Entity parent/child hierarchies implemented --- docs/tasks/Bugs.todo | 1 + src/main.cpp | 18 +-- src/run_modes/editor/panels/world_tree.cpp | 12 +- src/world/components.h | 22 ++- src/world/entity.cpp | 153 ++++++++++++++++----- src/world/entity.h | 13 +- src/world/world.cpp | 85 ++++++++++-- src/world/world.h | 5 +- 8 files changed, 242 insertions(+), 67 deletions(-) diff --git a/docs/tasks/Bugs.todo b/docs/tasks/Bugs.todo index dc75f6d..5c588f3 100644 --- a/docs/tasks/Bugs.todo +++ b/docs/tasks/Bugs.todo @@ -1,5 +1,6 @@ High Importance: + ☐ Colors are not saved accurately ✔ Add Component button on properties view no longer works @critical @done(22-09-07 13:44) ✔ AssetBrowser back button does not stop at the asset root directory @high @done(22-07-05 13:53) ✔ Editor does not get absolute paths from the file browser - replace with NFD dialogs @critical @done(22-05-20 18:36) diff --git a/src/main.cpp b/src/main.cpp index b20ccd2..134ca25 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,15 +52,15 @@ int main(int argc, char** argv) } //std::cout << "\nEngine core successfully initialized!\n"; - - try - { - core.RunGameLoop(); - } - catch(const std::exception& e) - { - lunarium::Logger::Fatal(lunarium::LogCategory::CORE, "Unhandled exception: %s", e.what()); - } +core.RunGameLoop(); + // try + // { + // core.RunGameLoop(); + // } + // catch(const std::exception& e) + // { + // lunarium::Logger::Fatal(lunarium::LogCategory::CORE, "Unhandled exception: %s", e.what()); + // } core.Shutdown(); diff --git a/src/run_modes/editor/panels/world_tree.cpp b/src/run_modes/editor/panels/world_tree.cpp index b79fe36..1470374 100644 --- a/src/run_modes/editor/panels/world_tree.cpp +++ b/src/run_modes/editor/panels/world_tree.cpp @@ -120,12 +120,16 @@ namespace lunarium { namespace editor was_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left); was_right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right); - const std::vector& children = pEnt->GetChildren(); - for (auto iter = children.begin(); iter != children.end(); iter++) + if (pEnt->HasChildren()) { - Entity* pe = mpWorld->GetEntity((*iter)); - ShowEntity(pe); + const std::vector& children = pEnt->GetChildren(); + for (auto iter = children.begin(); iter != children.end(); iter++) + { + Entity* pe = mpWorld->GetEntity((*iter)); + ShowEntity(pe); + } } + ImGui::TreePop(); } diff --git a/src/world/components.h b/src/world/components.h index e05e17d..af8314b 100644 --- a/src/world/components.h +++ b/src/world/components.h @@ -19,6 +19,7 @@ #include #include +#include namespace lunarium { @@ -86,13 +87,30 @@ namespace lunarium // UTILITY COMPONENTS ///////////////////////////////////////////////////////////////////// // These components are for internal use only. They do not show up in the editor. + + struct UUIDComponent + { + LUUID UUID; + + UUIDComponent() = default; + UUIDComponent(const UUIDComponent&) = default; + }; + struct ParentEntityComponent { - LUUID parent; - + LUUID Parent; + ParentEntityComponent() = default; ParentEntityComponent(const ParentEntityComponent&) = default; }; + + struct ChildrenComponent + { + std::vector Children; + + ChildrenComponent() = default; + ChildrenComponent(const ChildrenComponent&) = default; + }; } #endif // LUNARIUM_COMPONENTS_H_ \ No newline at end of file diff --git a/src/world/entity.cpp b/src/world/entity.cpp index 2a4fa5a..f1290ea 100644 --- a/src/world/entity.cpp +++ b/src/world/entity.cpp @@ -41,6 +41,11 @@ namespace lunarium { return mUUID; } + + entt::entity Entity::GetEnttHandle() const + { + return mHandle; + } std::string Entity::GetName() const { @@ -53,9 +58,10 @@ namespace lunarium } - bool Entity::HasChildren() const + bool Entity::HasChildren() { - return mChildren.size() > 0; + return HasComponent(); + //return mChildren.size() > 0; } @@ -63,7 +69,16 @@ namespace lunarium { Entity* e = mWorld.GetEntity(child); e->AddComponent(mUUID); - mChildren.push_back(child); + + if (!HasComponent()) + { + AddComponent(); + } + + ChildrenComponent& ccomp = GetComponent(); + ccomp.Children.push_back(child); + + //mChildren.push_back(child); } @@ -71,40 +86,61 @@ namespace lunarium { Entity* e = mWorld.GetEntity(child); e->ClearParent(); - for (auto iter = mChildren.begin(); iter != mChildren.end(); iter++) + + if (!HasChildren()) + { + Logger::Error(LogCategory::GAME_SYSTEM, "RemoveChild called on entity that does not have children"); + return; + } + + ChildrenComponent& ccomp = GetComponent(); + for (auto iter = ccomp.Children.begin(); iter != ccomp.Children.end(); iter++) { if ((*iter) == child) { - mChildren.erase(iter); + ccomp.Children.erase(iter); break; } } + + if (ccomp.Children.size() < 1) + { + RemoveComponent(); + } } - const std::vector& Entity::GetChildren() const + std::vector& Entity::GetChildren() { - return mChildren; + if (!HasChildren()) + { + Logger::Error(LogCategory::GAME_SYSTEM, "GetChildren called on entity that does not have children"); + return std::move(std::vector()); + } + + ChildrenComponent& ccomp = GetComponent(); + return ccomp.Children; } - bool Entity::HasParent() const - { - return mParentSet; - } + // bool Entity::HasParent() const + // { + // return mParentSet; + // } - LUUID Entity::GetParent() const - { - return mParent; - } + // LUUID Entity::GetParent() const + // { + // return mParent; + // } - void Entity::SetParent(LUUID parent) - { - mParent = parent; - } + // void Entity::SetParent(LUUID parent) + // { + // mParent = parent; + // } void Entity::ClearParent() { mParentSet = false; + RemoveComponent(); } @@ -119,6 +155,15 @@ namespace lunarium node["name"] = mName; auto& components = node["components"]; + + if (HasComponent()) + { + nlohmann::ordered_json uuid; + uuid["type_name"] = "UUIDComponent"; + uuid["UUID"] = (u64)GetComponent().UUID; + components.emplace_back(uuid); + } + if (HasComponent()) { nlohmann::ordered_json tag; @@ -210,22 +255,39 @@ namespace lunarium nlohmann::ordered_json parent; ParentEntityComponent& comp = GetComponent(); parent["type_name"] = "ParentEntityComponent"; - parent["UUID"] = (u64)comp.parent; + parent["UUID"] = (u64)comp.Parent; components.emplace_back(parent); } + if (HasComponent()) + { + nlohmann::ordered_json children_node; + ChildrenComponent& comp = GetComponent(); + children_node["type_name"] = "ChildrenComponent"; + + auto& children = children_node["children"]; + for (int i = 0; i < comp.Children.size(); i++) + { + nlohmann::ordered_json child; + child["UUID"] = comp.Children[i]; + children.emplace_back(child); + } + + components.emplace_back(children_node); + } + // TODO: ADD CODE TO SERIALIZE ANY NEW COMPONENTS // Children - auto& children = node["children"]; - for (int i = 0; i < mChildren.size(); i++) - { - nlohmann::ordered_json child; - child["UUID"] = mChildren[i]; - children.emplace_back(child); - } + // auto& children = node["children"]; + // for (int i = 0; i < mChildren.size(); i++) + // { + // nlohmann::ordered_json child; + // child["UUID"] = mChildren[i]; + // children.emplace_back(child); + // } #endif return OpRes::OK(); @@ -246,6 +308,12 @@ namespace lunarium std::string comp_type_name = comp["type_name"].get(); + if ("UUIDComponent" == comp_type_name) + { + LUUID uuid = comp["UUID"].get(); + AddComponent(uuid); + } + if ("TagComponent" == comp_type_name) { std::string info = comp["info"].get(); @@ -325,20 +393,35 @@ namespace lunarium AddComponent(parent); } + if ("ChildrenComponent" == comp_type_name) + { + auto& children = comp["children"]; + std::vector children_vec; + for (auto iter = children.begin(); iter != children.end(); iter++) + { + auto& child = *iter; + + LUUID ne = child["UUID"].get(); + children_vec.push_back(ne); + } + + AddComponent(children_vec); + } + // TODO: ADD CODE TO DESERIALIZE ANY NEW COMPONENTS } // TODO: Load children - auto& children = node["children"]; - for (auto iter = children.begin(); iter != children.end(); iter++) - { - auto& child = *iter; - - LUUID ne = child["UUID"].get(); - mChildren.push_back(ne); - } + // auto& children = node["children"]; + // for (auto iter = children.begin(); iter != children.end(); iter++) + // { + // auto& child = *iter; + + // LUUID ne = child["UUID"].get(); + // mChildren.push_back(ne); + // } #endif return OpRes::OK(); diff --git a/src/world/entity.h b/src/world/entity.h index b5fdaa1..0923a87 100644 --- a/src/world/entity.h +++ b/src/world/entity.h @@ -65,17 +65,18 @@ namespace lunarium // TODO: : public JSONSerializable } LUUID GetUUID() const; + entt::entity GetEnttHandle() const; std::string GetName() const; void SetName(std::string name); - bool HasChildren() const; + bool HasChildren(); void AddChild(LUUID child); void RemoveChild(LUUID child); - const std::vector& GetChildren() const; + std::vector& GetChildren(); - bool HasParent() const; - LUUID GetParent() const; - void SetParent(LUUID parent); + // bool HasParent() const; + // LUUID GetParent() const; + // void SetParent(LUUID parent); void ClearParent(); // Serializing @@ -91,7 +92,7 @@ namespace lunarium // TODO: : public JSONSerializable std::string mName; entt::entity mHandle; World& mWorld; // The world the entity is contained within - std::vector mChildren; + //std::vector mChildren; private: void Init(); diff --git a/src/world/world.cpp b/src/world/world.cpp index fa9fb08..f165cee 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -16,7 +16,6 @@ #include #include #include "entity.h" -#include "components.h" namespace lunarium { @@ -58,24 +57,37 @@ namespace lunarium } - void World::Render(lunarium::Renderer2D* pGraphics) const + void World::Render(lunarium::Renderer2D* pGraphics) { - // switch (mMode) + // Draw the Renderables that also have a transform + // Code from: + // https://github.com/skypjack/entt/wiki/Crash-Course:-entity-component-system#views-and-groups + // mECSRegistry.view().each([&](auto entity, auto &transform, auto &blockout) // { - // case RunMode::EDITOR: RenderEditor(pGraphics); break; - // } + // Rectangle rect(transform.Position.x, transform.Position.y, blockout.Size.x, blockout.Size.y); + // Color color(blockout.Color.x, blockout.Color.y, blockout.Color.z, blockout.Color.w); - // TODO: Modify to handle parent/child rendering + // glm::mat4 parent_transform(1.0f); + // if (mECSRegistry.all_of(entity)) + // { + // // UUIDComponent uuid = mECSRegistry.get(entity); + // // LUUID uid = uuid.UUID; + // ParentEntityComponent& parent = mECSRegistry.get(entity); + // parent_transform = GetParentTransform(parent.Parent); + // } + // pGraphics->DrawQuad(rect, color, nullptr, 0.0f, Rectangle(-1, -1, -1, -1), parent_transform); + // }); - // Draw the Renderables that also have a transform - // Code from: - // https://github.com/skypjack/entt/wiki/Crash-Course:-entity-component-system#views-and-groups mECSRegistry.view().each([&](auto entity, auto &transform, auto &blockout) { Rectangle rect(transform.Position.x, transform.Position.y, blockout.Size.x, blockout.Size.y); Color color(blockout.Color.x, blockout.Color.y, blockout.Color.z, blockout.Color.w); - pGraphics->DrawQuad(rect, color); + + if (!mECSRegistry.all_of(entity)) + { + DrawHeirarchy(pGraphics, entity, transform, blockout, glm::mat4(1.0f)); + } }); } @@ -134,6 +146,59 @@ namespace lunarium ///////////////////////////////////////////////////////////////////// // RUN MODE HELPERS ///////////////////////////////////////////////////////////////////// + + + void World::DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform) + { + // Draw current entity + Rectangle rect(my_trans.Position.x, my_trans.Position.y, bo_comp.Size.x, bo_comp.Size.y); + Color color(bo_comp.Color.x, bo_comp.Color.y, bo_comp.Color.z, bo_comp.Color.w); + g->DrawQuad(rect, color, nullptr, -my_trans.Rotation.z, Rectangle(-1, -1, -1, -1), current_transform); + + // Apply transform to children's transforms + current_transform *= my_trans.GetTransform(); + + // Iterate and draw children + if (mECSRegistry.all_of(entity)) + { + ChildrenComponent& children_comp = mECSRegistry.get(entity); + for (int i = 0; i < children_comp.Children.size(); i++) + { + Entity* pEnt = GetEntity(children_comp.Children[i]); + entt::entity handle = pEnt->GetEnttHandle(); + + if (pEnt->HasComponent() && pEnt->HasComponent()) + { + TransformComponent& trans_comp = pEnt->GetComponent(); + BlockOutComponent& bo_comp = pEnt->GetComponent(); + + DrawHeirarchy(g, handle, trans_comp, bo_comp, current_transform); + } + + } + } + + } + + glm::mat4 World::GetParentTransform(LUUID parent) + { + glm::mat4 transform(1.0f); + Entity* p = GetEntity(parent); + + if (p->HasComponent()) + { + TransformComponent t = p->GetComponent(); + transform = t.GetTransform(); + + if (p->HasComponent()) + { + transform *= GetParentTransform(p->GetComponent().Parent); + } + + } + + return transform; + } void World::RenderEditor(lunarium::Renderer2D* pGraphics) const { diff --git a/src/world/world.h b/src/world/world.h index c78f4bf..ab35674 100644 --- a/src/world/world.h +++ b/src/world/world.h @@ -17,6 +17,7 @@ #include #include #include +#include "components.h" #include #include @@ -68,7 +69,7 @@ namespace lunarium void OnLoad(); void OnUnload(); void Update(float dt); - void Render(lunarium::Renderer2D* pGraphics) const; + void Render(lunarium::Renderer2D* pGraphics); void SetActiveCamera(OrthographicCamera* pCam); void SetRunMode(RunMode mode); @@ -109,6 +110,8 @@ namespace lunarium private: // HELPERS void RenderEditor(lunarium::Renderer2D* pGraphics) const; + glm::mat4 GetParentTransform(LUUID parent); + void DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform); }; }