TriggerSystem implemented and working.
This commit is contained in:
@@ -6,6 +6,10 @@
|
|||||||
#include "Core/Ray.h"
|
#include "Core/Ray.h"
|
||||||
#include "Core/AABB.h"
|
#include "Core/AABB.h"
|
||||||
#include "Engine/Rendering/RawModel.h"
|
#include "Engine/Rendering/RawModel.h"
|
||||||
|
#include "Core/Entity.h"
|
||||||
|
|
||||||
|
class World;
|
||||||
|
struct ComponentWrapper;
|
||||||
|
|
||||||
namespace Collision
|
namespace Collision
|
||||||
{
|
{
|
||||||
@@ -39,6 +43,10 @@ bool RayVsModel(const Ray& ray,
|
|||||||
bool AABBVsAABB(const AABB& a, const AABB& b);
|
bool AABBVsAABB(const AABB& a, const AABB& b);
|
||||||
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon = 0.0001f);
|
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
|
#endif
|
||||||
@@ -10,23 +10,21 @@
|
|||||||
|
|
||||||
class AABB;
|
class AABB;
|
||||||
|
|
||||||
class TriggerSystem : public System
|
class TriggerSystem : public PureSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TriggerSystem(EventBroker* eventBroker)
|
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:
|
private:
|
||||||
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
|
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
|
||||||
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
|
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
|
||||||
|
|
||||||
bool getEntityBox(World* world, EntityID id, AABB& outBox);
|
|
||||||
//True if leave event was thrown.
|
//True if leave event was thrown.
|
||||||
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId);
|
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId);
|
||||||
void attachAABBComponentFromModel(World* world, EntityID id);
|
|
||||||
template<typename Event>
|
template<typename Event>
|
||||||
void publish(EntityID pId, EntityID tId)
|
void publish(EntityID pId, EntityID tId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "Collision/Collision.h"
|
#include "Collision/Collision.h"
|
||||||
#include "Engine/GLM.h"
|
#include "Engine/GLM.h"
|
||||||
|
#include "Core/World.h"
|
||||||
|
#include "Rendering/Model.h"
|
||||||
|
|
||||||
namespace Collision
|
namespace Collision
|
||||||
{
|
{
|
||||||
@@ -176,4 +178,59 @@ bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilo
|
|||||||
(std::abs(mi1.y - mi2.y) < epsilon);
|
(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>(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>(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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "Core/AABB.h"
|
#include "Core/AABB.h"
|
||||||
#include "Rendering/Model.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.
|
//Currently only players can trigger things.
|
||||||
auto players = world->GetComponents("Player");
|
auto players = world->GetComponents("Player");
|
||||||
@@ -13,14 +13,14 @@ void TriggerSystem::Update(World* world, ComponentWrapper& trigger, double dt)
|
|||||||
EntityID tId = trigger.EntityID;
|
EntityID tId = trigger.EntityID;
|
||||||
AABB triggerBox;
|
AABB triggerBox;
|
||||||
//The trigger *should* have a bounding box, or something, to test against so it can be triggered.
|
//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;
|
return;
|
||||||
}
|
}
|
||||||
for (auto& pc : *players) {
|
for (auto& pc : *players) {
|
||||||
EntityID pId = pc.EntityID;
|
EntityID pId = pc.EntityID;
|
||||||
AABB playerBox;
|
AABB playerBox;
|
||||||
//The player can't trigger anything without an AABB.
|
//The player can't trigger anything without an AABB.
|
||||||
if (!getEntityBox(world, pId, playerBox)) {
|
if (!Collision::GetEntityBox(world, pId, playerBox, true)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!Collision::AABBVsAABB(triggerBox, playerBox)) {
|
if (!Collision::AABBVsAABB(triggerBox, playerBox)) {
|
||||||
@@ -35,8 +35,9 @@ void TriggerSystem::Update(World* world, ComponentWrapper& trigger, double dt)
|
|||||||
} else {
|
} else {
|
||||||
//Entity is at least touching the trigger.
|
//Entity is at least touching the trigger.
|
||||||
AABB completelyInsideBox;
|
AABB completelyInsideBox;
|
||||||
completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - playerBox.Size());
|
completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - 2.0f * playerBox.Size());
|
||||||
if (Collision::AABBVsAABB(completelyInsideBox, playerBox)) {
|
if (Collision::AABBVsAABB(completelyInsideBox, playerBox) &&
|
||||||
|
glm::all(glm::greaterThan(triggerBox.Size(), playerBox.Size()))) {
|
||||||
//Entity is completely inside the trigger.
|
//Entity is completely inside the trigger.
|
||||||
//If it was only touching before, it is erased.
|
//If it was only touching before, it is erased.
|
||||||
m_EntitiesTouchingTrigger[tId].erase(pId);
|
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<EntityID>& triggerSet, EntityID pId, EntityID tId)
|
bool TriggerSystem::throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId)
|
||||||
{
|
{
|
||||||
const auto& it = triggerSet.find(pId);
|
const auto& it = triggerSet.find(pId);
|
||||||
@@ -95,29 +79,3 @@ bool TriggerSystem::throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& trigg
|
|||||||
return false;
|
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>(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;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ void PlayerSystem::UpdateComponent(World * world, ComponentWrapper & player, dou
|
|||||||
} else {
|
} else {
|
||||||
m_Direction.x = 0;
|
m_Direction.x = 0;
|
||||||
}
|
}
|
||||||
m_EventBroker->Process<PlayerSystem>();
|
|
||||||
ComponentWrapper& transform = world->GetComponent(player.EntityID, "Transform");
|
ComponentWrapper& transform = world->GetComponent(player.EntityID, "Transform");
|
||||||
(glm::vec3&)player["Velocity"] = m_Speed * float(dt) * m_Direction;
|
(glm::vec3&)player["Velocity"] = m_Speed * float(dt) * m_Direction;
|
||||||
(glm::vec3&)transform["Position"] += (glm::vec3)player["Velocity"];
|
(glm::vec3&)transform["Position"] += (glm::vec3)player["Velocity"];
|
||||||
|
|||||||
Reference in New Issue
Block a user