From d10df6ae095b3589b2dc3b7d29b06d7320c04f2e Mon Sep 17 00:00:00 2001 From: William Moberg Date: Wed, 16 Dec 2015 12:22:15 +0100 Subject: [PATCH] TriggerSystem implemented and working. --- include/Engine/Collision/Collision.h | 8 ++++ include/Engine/Collision/TriggerSystem.h | 8 ++-- src/Engine/Collision/Collision.cpp | 57 ++++++++++++++++++++++++ src/Engine/Collision/TriggerSystem.cpp | 54 +++------------------- src/Game/PlayerSystem.cpp | 2 +- 5 files changed, 75 insertions(+), 54 deletions(-) diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 8b1f96b2..1fcb910e 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -6,6 +6,10 @@ #include "Core/Ray.h" #include "Core/AABB.h" #include "Engine/Rendering/RawModel.h" +#include "Core/Entity.h" + +class World; +struct ComponentWrapper; namespace Collision { @@ -39,6 +43,10 @@ bool RayVsModel(const Ray& ray, bool AABBVsAABB(const AABB& a, const AABB& b); bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon = 0.0001f); +//Returns true if the entity has a boundingbox. Outputs the aabb in [outBox]. +bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel = false); +bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox); + } #endif \ No newline at end of file diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index 59718018..7e6ef008 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -10,23 +10,21 @@ class AABB; -class TriggerSystem : public System +class TriggerSystem : public PureSystem { public: TriggerSystem(EventBroker* eventBroker) - : System(eventBroker, "Trigger") + : PureSystem(eventBroker, "Trigger") {} - virtual void Update(World* world, ComponentWrapper& collision, double dt) override; + virtual void UpdateComponent(World* world, ComponentWrapper& collision, double dt) override; private: std::unordered_map> m_EntitiesTouchingTrigger; std::unordered_map> m_EntitiesCompletelyInTrigger; - bool getEntityBox(World* world, EntityID id, AABB& outBox); //True if leave event was thrown. bool throwLeaveIfWasInTrigger(std::unordered_set& triggerSet, EntityID pId, EntityID tId); - void attachAABBComponentFromModel(World* world, EntityID id); template void publish(EntityID pId, EntityID tId) { diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 69bffa1a..500d59bc 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -2,6 +2,8 @@ #include "Collision/Collision.h" #include "Engine/GLM.h" +#include "Core/World.h" +#include "Rendering/Model.h" namespace Collision { @@ -176,4 +178,59 @@ bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilo (std::abs(mi1.y - mi2.y) < epsilon); } +void attachAABBComponentFromModel(World* world, EntityID id) +{ + ComponentWrapper model = world->GetComponent(id, "Model"); + ComponentWrapper collision = world->AttachComponent(id, "AABB"); + Model* modelRes = ResourceManager::Load(model["Resource"]); + + glm::mat4 modelMatrix = modelRes->m_Matrix; + + glm::vec3 mini = glm::vec3(INFINITY, INFINITY, INFINITY); + glm::vec3 maxi = glm::vec3(-INFINITY, -INFINITY, -INFINITY); + for (const auto& v : modelRes->m_Vertices) { + const auto& wPos = modelMatrix * glm::vec4(v.Position.x, v.Position.y, v.Position.z, 1); + maxi.x = std::max(wPos.x, maxi.x); + maxi.y = std::max(wPos.y, maxi.y); + maxi.z = std::max(wPos.z, maxi.z); + mini.x = std::min(wPos.x, mini.x); + mini.y = std::min(wPos.y, mini.y); + mini.z = std::min(wPos.z, mini.z); + } + collision["BoxCenter"] = 0.5f * (maxi + mini); + collision["BoxSize"] = maxi - mini; +} + +bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox) +{ + ComponentWrapper& cTrans = world->GetComponent(AABBComponent.EntityID, "Transform"); + ComponentWrapper model = world->GetComponent(AABBComponent.EntityID, "Model"); + Model* modelRes = ResourceManager::Load(model["Resource"]); + outBox.CreateFromCenter(AABBComponent["BoxCenter"], AABBComponent["BoxSize"]); + glm::vec3 mini = outBox.MinCorner(); + glm::vec3 maxi = outBox.MaxCorner(); + + glm::mat4 modelMatrix = modelRes->m_Matrix * + glm::translate(glm::mat4(), (glm::vec3)cTrans["Position"]) * + glm::scale((glm::vec3)cTrans["Scale"]); + + outBox = AABB(modelMatrix * glm::vec4(mini.x, mini.y, mini.z, 1), + modelMatrix * glm::vec4(maxi.x, maxi.y, maxi.z, 1)); + return true; +} + +bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel) +{ + if (!world->HasComponent(entity, "AABB")) { + if (forceBoxFromModel) { + attachAABBComponentFromModel(world, entity); + } else { + return false; + } + } + + ComponentWrapper& cBox = world->GetComponent(entity, "AABB"); + return GetEntityBox(world, cBox, outBox); +} + } diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index 38a8fac4..09092461 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -3,7 +3,7 @@ #include "Core/AABB.h" #include "Rendering/Model.h" -void TriggerSystem::Update(World* world, ComponentWrapper& trigger, double dt) +void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, double dt) { //Currently only players can trigger things. auto players = world->GetComponents("Player"); @@ -13,14 +13,14 @@ void TriggerSystem::Update(World* world, ComponentWrapper& trigger, double dt) EntityID tId = trigger.EntityID; AABB triggerBox; //The trigger *should* have a bounding box, or something, to test against so it can be triggered. - if (!getEntityBox(world, tId, triggerBox)) { + if (!Collision::GetEntityBox(world, tId, triggerBox, true)) { return; } for (auto& pc : *players) { EntityID pId = pc.EntityID; AABB playerBox; //The player can't trigger anything without an AABB. - if (!getEntityBox(world, pId, playerBox)) { + if (!Collision::GetEntityBox(world, pId, playerBox, true)) { continue; } if (!Collision::AABBVsAABB(triggerBox, playerBox)) { @@ -35,8 +35,9 @@ void TriggerSystem::Update(World* world, ComponentWrapper& trigger, double dt) } else { //Entity is at least touching the trigger. AABB completelyInsideBox; - completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - playerBox.Size()); - if (Collision::AABBVsAABB(completelyInsideBox, playerBox)) { + completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - 2.0f * playerBox.Size()); + if (Collision::AABBVsAABB(completelyInsideBox, playerBox) && + glm::all(glm::greaterThan(triggerBox.Size(), playerBox.Size()))) { //Entity is completely inside the trigger. //If it was only touching before, it is erased. m_EntitiesTouchingTrigger[tId].erase(pId); @@ -66,23 +67,6 @@ void TriggerSystem::Update(World* world, ComponentWrapper& trigger, double dt) } } -bool TriggerSystem::getEntityBox(World* world, EntityID id, AABB& outBox) -{ - //TODO: Improve checking if component exists. Remove try - bool retry; - do { - retry = false; - try { - ComponentWrapper& cBox = world->GetComponent(id, "AABB"); - outBox.CreateFromCenter(cBox["BoxCenter"], cBox["BoxSize"]); - } catch (std::out_of_range e) { - retry = true; - attachAABBComponentFromModel(world, id); - } - } while (retry); - return true; -} - bool TriggerSystem::throwLeaveIfWasInTrigger(std::unordered_set& triggerSet, EntityID pId, EntityID tId) { const auto& it = triggerSet.find(pId); @@ -95,29 +79,3 @@ bool TriggerSystem::throwLeaveIfWasInTrigger(std::unordered_set& trigg return false; } -void TriggerSystem::attachAABBComponentFromModel(World* world, EntityID id) -{ - ComponentWrapper model = world->GetComponent(id, "Model"); - ComponentWrapper transform = world->GetComponent(id, "Transform"); - ComponentWrapper collision = world->AttachComponent(id, "AABB"); - Model* modelRes = ResourceManager::Load(model["Resource"]); - - glm::mat4 modelMatrix = modelRes->m_Matrix * - glm::translate(glm::mat4(), (glm::vec3)transform["Position"]) * - glm::toMat4((glm::quat)transform["Orientation"]) * - glm::scale((glm::vec3)transform["Scale"]); - - glm::vec3 mini = glm::vec3(INFINITY, INFINITY, INFINITY); - glm::vec3 maxi = glm::vec3(-INFINITY, -INFINITY, -INFINITY); - for (const auto& v : modelRes->m_Vertices) { - const auto& wPos = modelMatrix * glm::vec4(v.Position.x, v.Position.y, v.Position.z, 1); - maxi.x = std::max(wPos.x, maxi.x); - maxi.y = std::max(wPos.y, maxi.y); - maxi.z = std::max(wPos.z, maxi.z); - mini.x = std::min(wPos.x, mini.x); - mini.y = std::min(wPos.y, mini.y); - mini.z = std::min(wPos.z, mini.z); - } - collision["BoxCenter"] = 0.5f * (maxi + mini); - collision["BoxSize"] = maxi - mini; -} diff --git a/src/Game/PlayerSystem.cpp b/src/Game/PlayerSystem.cpp index 41d5602c..9f7a14cf 100644 --- a/src/Game/PlayerSystem.cpp +++ b/src/Game/PlayerSystem.cpp @@ -16,7 +16,7 @@ void PlayerSystem::UpdateComponent(World * world, ComponentWrapper & player, dou } else { m_Direction.x = 0; } - m_EventBroker->Process(); + ComponentWrapper& transform = world->GetComponent(player.EntityID, "Transform"); (glm::vec3&)player["Velocity"] = m_Speed * float(dt) * m_Direction; (glm::vec3&)transform["Position"] += (glm::vec3)player["Velocity"];