/****************************************************************************** * File - world.cpp * Author - Joey Pollack * Date - 2022/01/12 (y/m/d) * Mod Date - 2022/01/20 (y/m/d) * Description - Manages a game "world". A world is made up of regions which * are subdivisions of the world. Each region contains: a set * of images for the maps layers, a list of objects that spawn * in this region and static collision data. ******************************************************************************/ #include "world.h" #include #include #include #include #include #include "entity.h" namespace lunarium { // World::World(Camera* pCam, Sizei region_size, Sizei world_size) // : mpCamera(pCam), mRegionSize(region_size), mpWorldScript(nullptr), mWorldSize(world_size) // { // mActiveRegion = { 0, 0 }; // } World::World(std::string name) : mUUID(UUID::GetNewID()), mName(name), mpActiveCamera(nullptr) { } void World::OnLoad() { // TODO: Call OnLoad in the world script and on each region script } void World::OnUnload() { // TODO: Call OnUnLoad in the world script and on each region script } void World::SetRunMode(RunMode mode) { mMode = mode; } World::RunMode World::GetRunMode() { return mMode; } void World::Update(float dt) { // TODO: Update all entities } void World::Render(lunarium::Renderer2D* pGraphics) { // 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); // 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); // }); // OLD RENDER HEIRARCHY RENDER SYSTEM // 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); // if (!mECSRegistry.all_of(entity)) // { // DrawHeirarchy(pGraphics, entity, transform, blockout, glm::mat4(1.0f)); // } // }); // NEW RENDER SYSTEM // First get the group we want auto group = mECSRegistry.group<>(entt::get); // Next sort the group group.sort([](const BlockOutComponent &lhs, const BlockOutComponent &rhs) { return lhs.RenderLayer < rhs.RenderLayer; }); // Render the group for(auto entity: group) { auto &transform = group.get(entity); auto &blockout = group.get(entity); 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); // Get and apply parent transforms LUUID uuid = mECSRegistry.get(entity).UUID; Entity* pEnt = GetEntity(uuid); glm::mat4 parent_transform = glm::mat4(1.0f); if (pEnt->HasComponent()) { parent_transform = GetParentTransform(uuid); } pGraphics->DrawQuad(rect, color, nullptr, -transform.Rotation.z, Rectangle(-1, -1, -1, -1), parent_transform); } } void World::SetActiveCamera(OrthographicCamera* pCam) { mpActiveCamera = pCam; } entt::registry* World::GetEntityRegistry() { return &mECSRegistry; } LUUID World::CreateEntity() { //Logger::Error(LogCategory::GAME_SYSTEM, "World::CreateEntity not implemented!"); Entity* new_ent = new Entity(*this); if (mEntitiesByUUID.find(new_ent->GetUUID()) != mEntitiesByUUID.end()) { Logger::Warn(LogCategory::GAME_SYSTEM, "UUID collision when creating new entity! UUID: %d", new_ent->GetUUID()); } mEntitiesByUUID[new_ent->GetUUID()] = new_ent; mEntities.push_back(new_ent); return new_ent->GetUUID(); } Entity* World::GetEntity(LUUID id) { if (mEntitiesByUUID.find(id) == mEntitiesByUUID.end()) { Logger::Warn(LogCategory::GAME_SYSTEM, "Entity with id: %d not found.", id); } return mEntitiesByUUID[id]; } unsigned int World::GetNumEntities() const { return mEntities.size(); } std::vector::iterator World::EntitiesBegin() { return mEntities.begin(); } bool World::EntitiesIsEnd(std::vector::iterator& iter) { return iter == mEntities.end(); } ///////////////////////////////////////////////////////////////////// // 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 { // NOTE: MAY BE REMOVED } ///////////////////////////////////////////////////////////////////// // SERIALIZING ///////////////////////////////////////////////////////////////////// OpRes World::Serialize(nlohmann::ordered_json& node) { #if !BUILD_NO_EDITOR // Only does this when this is an editor build node["UUID"] = mUUID; node["NumberOfEntities"] = mEntities.size(); auto& ents = node["Entities"]; for (int i = 0; i < mEntities.size(); i++) { nlohmann::ordered_json e; mEntities[i]->Serialize(e).LogIfFailed(LogCategory::GAME_SYSTEM); ents.emplace_back(e); } #endif return OpRes::OK(); } OpRes World::Deserialize(nlohmann::ordered_json& node) { #if !BUILD_NO_EDITOR // Only does this when this is an editor build mUUID = node["UUID"].get(); int num_entities = node["NumberOfEntities"].get(); auto& ents = node["Entities"]; for (auto it = ents.begin(); it != ents.end(); ++it) { auto& ent = (*it); Entity* new_ent = new Entity(*this); if (!new_ent->IsValidNode(ent)) { delete new_ent; return OpRes::Fail("Invalid entity node"); } new_ent->Deserialize(ent).LogIfFailed(LogCategory::GAME_SYSTEM); mEntities.push_back(new_ent); mEntitiesByUUID[new_ent->GetUUID()] = new_ent; } #endif return OpRes::OK(); } bool World::IsValidNode(nlohmann::ordered_json& node) { if (node["UUID"].is_null()) { return false; } if (!node["UUID"].is_number()) { return false; } if (node["NumberOfEntities"].is_null()) { return false; } if (!node["NumberOfEntities"].is_number()) { return false; } if (node["Entities"].is_null()) { return false; } return false; } nlohmann::ordered_json World::AsJSON() { #if !BUILD_NO_EDITOR // Only does this when this is an editor build nlohmann::ordered_json node; Serialize(node).LogIfFailed(LogCategory::GAME_SYSTEM); return node; #endif return nlohmann::ordered_json(); } }