Basic collisions using Octree. Seems buggy over octree boundaries.

This commit is contained in:
2016-01-13 15:34:43 +01:00
parent 8ed4ba1219
commit d6ef527f25
33 changed files with 290 additions and 267 deletions
@@ -0,0 +1,19 @@
#include "../Core/System.h"
#include "../Core/Octree.h"
#include "Collision.h"
class CollidableOctreeSystem : public ImpureSystem, public PureSystem
{
public:
CollidableOctreeSystem(EventBroker* eventBroker, Octree* octree)
: System(eventBroker)
, PureSystem("Collidable")
, m_Octree(octree)
{ }
virtual void Update(World* world, double dt) override;
virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) override;
private:
Octree* m_Octree;
};
+8 -7
View File
@@ -6,11 +6,13 @@
//or you will get "fatal error C1189: #error: gl.h included before glew.h"
#include <vector>
#include <boost/optional.hpp>
#include "Core/Ray.h"
#include "Core/AABB.h"
#include "Engine/Rendering/RawModel.h"
#include "Core/Entity.h"
#include "../Core/Ray.h"
#include "../Core/AABB.h"
#include "../Rendering/RawModel.h"
#include "../Rendering/RenderQueueFactory.h"
#include "../Core/Entity.h"
class World;
struct ComponentWrapper;
@@ -50,9 +52,8 @@ bool AABBVsAABB(const AABB& a, const AABB& b);
bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation);
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);
// Calculates an absolute AABB from an entity AABB component
boost::optional<AABB> EntityAbsoluteAABB(World* world, EntityID entity);
}
+11 -6
View File
@@ -4,16 +4,19 @@
#include <GLFW/glfw3.h>
#include <glm/common.hpp>
#include "Common.h"
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "Core/EKeyUp.h"
#include "../Common.h"
#include "../Core/System.h"
#include "../Core/EventBroker.h"
#include "../Core/EKeyUp.h"
#include "../Core/Octree.h"
class CollisionSystem : public PureSystem
{
public:
CollisionSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "AABB")
CollisionSystem(EventBroker* eventBroker, Octree* octree)
: System(eventBroker)
, PureSystem("AABB")
, m_Octree(octree)
, zPress(false)
{
//TODO: Debug stuff, remove later.
@@ -23,7 +26,9 @@ public:
virtual void UpdateComponent(World* world, ComponentWrapper& cAABB, double dt) override;
private:
Octree* m_Octree;
bool zPress;
EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp;
bool OnKeyUp(const Events::KeyUp &event);
};
+9 -5
View File
@@ -4,8 +4,9 @@
#include <glm/common.hpp>
#include <unordered_set>
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "../Core/System.h"
#include "../Core/EventBroker.h"
#include "../Core/Octree.h"
#include "ETrigger.h"
class AABB;
@@ -13,13 +14,16 @@ class AABB;
class TriggerSystem : public PureSystem
{
public:
TriggerSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Trigger")
{}
TriggerSystem(EventBroker* eventBroker, Octree* octree)
: System(eventBroker)
, PureSystem("Trigger")
, m_Octree(octree)
{ }
virtual void UpdateComponent(World* world, ComponentWrapper& collision, double dt) override;
private:
Octree* m_Octree;
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
+3 -3
View File
@@ -11,18 +11,18 @@ public:
AABB(const glm::vec3& minPos, const glm::vec3& maxPos);
AABB(const glm::vec4& minPos, const glm::vec4& maxPos);
//No checks are made. Size must consist of non-negative numbers.
virtual void CreateFromCenter(const glm::vec3& center, const glm::vec3& size);
static AABB FromOriginSize(const glm::vec3& origin, const glm::vec3& size);
virtual ~AABB();
const glm::vec3& MinCorner() const { return m_MinCorner; }
const glm::vec3& MaxCorner() const { return m_MaxCorner; }
const glm::vec3& Center() const { return m_Center; }
const glm::vec3& Origin() const { return m_Origin; }
const glm::vec3 Size() const { return 2.0f * m_HalfSize; }
const glm::vec3& HalfSize() const { return m_HalfSize; }
private:
glm::vec3 m_MinCorner;
glm::vec3 m_MaxCorner;
glm::vec3 m_Center;
glm::vec3 m_Origin;
glm::vec3 m_HalfSize;
};
+2 -2
View File
@@ -2,7 +2,7 @@
#define Octree_h__
#include "../Common.h"
#include "Core/AABB.h"
#include "AABB.h"
class Ray;
@@ -14,7 +14,7 @@ public:
float CollideDistance;
};
Octree();
Octree() = delete;
~Octree();
//For the root Octree, [octreeBounds] should be a box containing the entire level.
Octree(const AABB& octreeBounds, int subDivisions);
+8 -8
View File
@@ -10,6 +10,9 @@ class System
friend class SystemPipeline;
protected:
System()
: m_EventBroker(nullptr)
{ }
System(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{ }
@@ -18,14 +21,13 @@ protected:
EventBroker* m_EventBroker;
};
class PureSystem : public System
class PureSystem : public virtual System
{
friend class SystemPipeline;
protected:
PureSystem(EventBroker* eventBroker, std::string componentType)
: System(eventBroker)
, m_ComponentType(componentType)
PureSystem(std::string componentType)
: m_ComponentType(componentType)
{ }
virtual ~PureSystem() = default;
@@ -34,14 +36,12 @@ protected:
virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) = 0;
};
class ImpureSystem : public System
class ImpureSystem : public virtual System
{
friend class SystemPipeline;
protected:
ImpureSystem(EventBroker* eventBroker)
: System(eventBroker)
{ }
ImpureSystem() = default;
virtual ~ImpureSystem() = default;
virtual void Update(World* world, double dt) = 0;
+7 -7
View File
@@ -32,8 +32,8 @@ public:
System* system = new T(m_EventBroker, args...);
group.Systems[typeid(T).name()] = system;
if (std::is_base_of<PureSystem, T>::value) {
PureSystem* pureSystem = static_cast<PureSystem*>(system);
PureSystem* pureSystem = dynamic_cast<PureSystem*>(system);
if (pureSystem != nullptr) {
if (!pureSystem->m_ComponentType.empty()) {
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
} else {
@@ -41,8 +41,8 @@ public:
}
}
if (std::is_base_of<ImpureSystem, T>::value) {
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
ImpureSystem* impureSystem = dynamic_cast<ImpureSystem*>(system);
if (impureSystem != nullptr) {
group.ImpureSystems.push_back(impureSystem);
}
}
@@ -56,6 +56,9 @@ public:
}
// Update
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
for (auto& pair : group.PureSystems) {
const std::string& componentName = pair.first;
auto& systems = pair.second;
@@ -69,9 +72,6 @@ public:
}
}
}
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
}
}
+3
View File
@@ -20,6 +20,7 @@
#include "Editor/EditorSystem.h"
#include "Core/EntityFile.h"
#include "Core/EntityFileParser.h"
#include "Core/Octree.h"
// Network
#include <boost/thread.hpp>
@@ -46,6 +47,8 @@ private:
InputProxy* m_InputProxy;
GUI::Frame* m_FrameStack;
World* m_World;
Octree* m_OctreeCollision;
Octree* m_OctreeFrustrumCulling;
SystemPipeline* m_SystemPipeline;
RenderQueueFactory* m_RenderQueueFactory;
// Network variables
+2 -1
View File
@@ -12,7 +12,8 @@ class PlayerSystem : public PureSystem
{
public:
PlayerSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Player")
: System(eventBroker)
, PureSystem("Player")
{
EVENT_SUBSCRIBE_MEMBER(m_ETouch, &PlayerSystem::OnTouch);
EVENT_SUBSCRIBE_MEMBER(m_EEnter, &PlayerSystem::OnEnter);
+2 -1
View File
@@ -5,7 +5,8 @@ class RaptorCopterSystem : public PureSystem
{
public:
RaptorCopterSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "RaptorCopter")
: System(eventBroker)
, PureSystem("RaptorCopter")
{ }
virtual void UpdateComponent(World* world, ComponentWrapper& raptorCopter, double dt) override
+1
View File
@@ -9,4 +9,5 @@
<xs:include schemaLocation="Components/AABB.xsd"/>
<xs:include schemaLocation="Components/Trigger.xsd"/>
<xs:include schemaLocation="Components/Health.xsd"/>
<xs:include schemaLocation="Components/Collidable.xsd"/>
</xs:schema>
+2 -2
View File
@@ -1,4 +1,4 @@
<c:AABB>
<BoxCenter X="0" Y="0" Z="0"/>
<BoxSize X="1" Y="1" Z="1"/>
<Origin X="0" Y="0" Z="0"/>
<Size X="1" Y="1" Z="1"/>
</c:AABB>
+6 -2
View File
@@ -6,8 +6,12 @@
<xs:element name="AABB">
<xs:complexType>
<xs:all>
<xs:element name="BoxCenter" type="t:Vector" minOccurs="0"/>
<xs:element name="BoxSize" type="t:Vector" minOccurs="0"/>
<xs:element name="Origin" type="t:Vector" minOccurs="0">
<xs:annotation><xs:documentation>Middle point of the bounding box</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="Size" type="t:Vector" minOccurs="0">
<xs:annotation><xs:documentation>Size of the bounding box</xs:documentation></xs:annotation>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
@@ -0,0 +1,3 @@
<c:Collidable>
<Static>true</Static>
</c:Collidable>
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:element name="Collidable">
<xs:complexType>
<xs:all>
<xs:element name="Static" type="t:bool" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
@@ -1,122 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components">
<Components>
<c:Transform>
<Orientation X="0" Y="0" Z="0"/>
</c:Transform>
<c:Model>
<Resource>Models/DummyScene.obj</Resource>
</c:Model>
<c:Transform/>
</Components>
<Children>
<Entity>
<Components>
<c:Transform>
<Position X="-1.5"/>
<Scale X="1" Y="1" Z="1"/>
</c:Transform>
<c:Model>
<Resource>Models/ScaleWidget.obj</Resource>
</c:Model>
</Components>
</Entity>
<Entity>
<Components>
<c:Transform>
<Position X="1.5"/>
<Scale X="2" Y="2" Z="2"/>
</c:Transform>
<c:Model>
<Resource>Models/RotationWidgetX.obj</Resource>
</c:Model>
<c:Trigger>
</c:Trigger>
</Components>
</Entity>
<Entity>
<Components>
<c:Player>
<Velocity X="0" Y="0" Z="0"/>
</c:Player>
<c:Transform>
<Position X="2.5"/>
</c:Transform>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
</c:Model>
<c:AABB>
</c:AABB>
</Components>
</Entity>
<Entity>
<Components>
<c:Transform>
<Position X="0" Y="-0"/>
<Scale X="1" Y="1" Z="1"/>
</c:Transform>
<!--<c:Move>
<Speed>1</Speed>
<Direction X="-1"/>
<Rotation Y="3.14"/>
</c:Move>-->
</Components>
<Children>
<Entity>
<Components>
<c:Transform>
<Position X="0" Y="0"/>
<Orientation X="0.0" Y="0" Z="1.0"/>
</c:Transform>
<c:Model>
<Resource>Models/Core/UnitRaptor.obj</Resource>
<Color R="1" G="0.4" B="0.8"/>
</c:Model>
</Components>
<Children>
<Entity>
<Components>
<c:Transform>
<Position X="-0.01" Y="0.55"/>
<Orientation X="0" Y="0" Z="-1"/>
</c:Transform>
<c:RaptorCopter>
<Speed>20</Speed>
<Axis Y="1"/>
</c:RaptorCopter>
</Components>
<Children>
<Entity>
<Components>
<c:Transform>
<Position X="0" Y="0"/>
<Scale X="1.7" Y="0.03" Z="0.1"/>
<Orientation X="0" Y="0" Z="0"/>
</c:Transform>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color R="1" G="0.4" B="0.8"/>
</c:Model>
</Components>
</Entity>
<Entity>
<Components>
<c:Transform>
<Position X="0" Y="0"/>
<Scale X="1.7" Y="0.03" Z="0.1"/>
<Orientation X="0" Y="1.57" Z="0"/>
</c:Transform>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color R="1" G="0.4" B="0.8"/>
<Resource>Models/Test/ObstacleCourse.obj</Resource>
</c:Model>
<c:Transform/>
</Components>
<Children/>
</Entity>
</Children>
</Entity>
</Children>
</Entity>
</Children>
</Entity>
</Children>
</Entity>
+5 -1
View File
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components">
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:Transform/>
</Components>
<Children/>
</Entity>
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:Transform/>
</Components>
<Children>
<Entity>
<Components>
<c:AABB/>
<c:Collidable/>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="1" G="0" R="0"/>
</c:Model>
<c:Transform>
<Position X="-0.104774237" Y="2.44278431" Z="0"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:AABB/>
<c:Collidable/>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="0" G="0" R="1"/>
</c:Model>
<c:Transform>
<Position X="0.548663795" Y="3.91025019" Z="0"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:AABB/>
<c:Collidable/>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="0" G="1" R="0"/>
</c:Model>
<c:Transform>
<Position X="-1.35118687" Y="3.90650201" Z="0"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
</c:Model>
<c:Transform>
<Scale X="48.5000038" Y="0.200000003" Z="0"/>
</c:Transform>
</Components>
<Children/>
</Entity>
</Children>
</Entity>
+3
View File
@@ -15,7 +15,10 @@
<xs:element ref="c:Test" minOccurs="0"/>
<xs:element ref="c:RaptorCopter" minOccurs="0"/>
<xs:element ref="c:Player" minOccurs="0"/>
<xs:element ref="c:AABB" minOccurs="0"/>
<xs:element ref="c:Trigger" minOccurs="0"/>
<xs:element ref="c:Health" minOccurs="0"/>
<xs:element ref="c:Collidable" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
@@ -0,0 +1,20 @@
#include "Collision/CollidableOctreeSystem.h"
void CollidableOctreeSystem::Update(World* world, double dt)
{
m_Octree->ClearDynamicObjects();
}
void CollidableOctreeSystem::UpdateComponent(World* world, ComponentWrapper& cCollidable, double dt)
{
EntityID entity = cCollidable.EntityID;
if (world->HasComponent(entity, "AABB")) {
boost::optional<AABB> absoluteAABB = Collision::EntityAbsoluteAABB(world, entity);
if (absoluteAABB) {
m_Octree->AddDynamicObject(*absoluteAABB);
}
} else if (world->HasComponent(entity, "Model")) {
// TODO: Derive AABB from model
}
}
+15 -37
View File
@@ -13,7 +13,7 @@ bool RayAABBIntr(const Ray& ray, const AABB& box)
{
glm::vec3 w = 75.0f * ray.Direction();
glm::vec3 v = glm::abs(w);
glm::vec3 c = ray.Origin() - box.Center() + w;
glm::vec3 c = ray.Origin() - box.Origin() + w;
glm::vec3 half = box.HalfSize();
if (abs(c.x) > v.x + half.x) {
@@ -68,8 +68,8 @@ bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance)
bool AABBVsAABB(const AABB& a, const AABB& b)
{
const glm::vec3& aCenter = a.Center();
const glm::vec3& bCenter = b.Center();
const glm::vec3& aCenter = a.Origin();
const glm::vec3& bCenter = b.Origin();
const glm::vec3& aHSize = a.HalfSize();
const glm::vec3& bHSize = b.HalfSize();
//Test will probably exit because of the X and Z axes more often, so test them first.
@@ -202,8 +202,8 @@ bool RayVsModel(const Ray& ray,
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon)
{
const glm::vec3& ma1 = first.MaxCorner();
const glm::vec3& ma2 = first.MaxCorner();
const glm::vec3& mi1 = second.MinCorner();
const glm::vec3& ma2 = second.MaxCorner();
const glm::vec3& mi1 = first.MinCorner();
const glm::vec3& mi2 = second.MinCorner();
return (std::abs(ma1.x - ma2.x) < epsilon) &&
(std::abs(mi1.x - mi2.x) < epsilon) &&
@@ -238,45 +238,23 @@ bool attachAABBComponentFromModel(World* world, EntityID id)
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;
collision["Origin"] = 0.5f * (maxi + mini);
collision["Size"] = maxi - mini;
return true;
}
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();
if (modelRes == nullptr) {
return false;
}
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)
boost::optional<AABB> EntityAbsoluteAABB(World* world, EntityID entity)
{
if (!world->HasComponent(entity, "AABB")) {
if (forceBoxFromModel) {
if (!attachAABBComponentFromModel(world, entity))
return false;
} else {
return false;
}
return boost::none;
}
ComponentWrapper& cBox = world->GetComponent(entity, "AABB");
return GetEntityBox(world, cBox, outBox);
ComponentWrapper& cAABB = world->GetComponent(entity, "AABB");
glm::vec3 absPosition = RenderQueueFactory::AbsolutePosition(world, entity);
glm::vec3 absScale = RenderQueueFactory::AbsoluteScale(world, entity);
glm::vec3 origin = absPosition + (glm::vec3)cAABB["Origin"];
glm::vec3 size = (glm::vec3)cAABB["Size"] * absScale;
return AABB::FromOriginSize(origin, size);
}
}
+15 -16
View File
@@ -2,31 +2,30 @@
#include "Collision/CollisionSystem.h"
#include "Core/AABB.h"
void CollisionSystem::UpdateComponent(World * world, ComponentWrapper & cAABB, double dt)
void CollisionSystem::UpdateComponent(World* world, ComponentWrapper& cAABB, double dt)
{
//Right now, cAABB is a component attached to any entity that should be collideable.
AABB thisBox;
if (!Collision::GetEntityBox(world, cAABB, thisBox)) {
EntityID entity = cAABB.EntityID;
boost::optional<AABB> boundingBox = Collision::EntityAbsoluteAABB(world, entity);
if (!boundingBox) {
return;
}
ComponentWrapper& cTransform = world->GetComponent(entity, "Transform");
AABB& boxA = *boundingBox;
//Press 'Z' to enable/disable collision.
if (zPress) {
return;
}
//Here, mover should be an object that moves, currently only players.
for (auto& mover : *world->GetComponents("Player")) {
if (cAABB.EntityID == mover.EntityID) {
std::vector<AABB> octreeResult;
m_Octree->BoxesInSameRegion(*boundingBox, octreeResult);
for (auto& boxB : octreeResult) {
glm::vec3 resolutionVector;
if (Collision::IsSameBoxProbably(boxA, boxB)) {
continue;
}
AABB otherBox;
if (!Collision::GetEntityBox(world, mover.EntityID, otherBox)) {
continue;
}
glm::vec3 resolveTranslation;
if (Collision::AABBVsAABB(otherBox, thisBox, resolveTranslation)) {
ComponentWrapper& trans = world->GetComponent(mover.EntityID, "Transform");
//TODO: Special treatment if both are movers.
trans["Position"] = (glm::vec3)trans["Position"] + resolveTranslation;
if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
(glm::vec3&)cTransform["Position"] += resolutionVector;
}
}
}
+10 -11
View File
@@ -3,27 +3,27 @@
#include "Core/AABB.h"
#include "Rendering/Model.h"
void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, double dt)
void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& cTrigger, double dt)
{
//Currently only players can trigger things.
auto players = world->GetComponents("Player");
if (players == nullptr) {
return;
}
EntityID tId = trigger.EntityID;
AABB triggerBox;
EntityID tId = cTrigger.EntityID;
boost::optional<AABB> triggerBox = Collision::EntityAbsoluteAABB(world, tId);
//The trigger *should* have a bounding box, or something, to test against so it can be triggered.
if (!Collision::GetEntityBox(world, tId, triggerBox, true)) {
if (!triggerBox) {
return;
}
for (auto& pc : *players) {
EntityID pId = pc.EntityID;
AABB playerBox;
boost::optional<AABB> playerBox = Collision::EntityAbsoluteAABB(world, pId);
//The player can't trigger anything without an AABB.
if (!Collision::GetEntityBox(world, pId, playerBox, true)) {
if (!playerBox) {
continue;
}
if (!Collision::AABBVsAABB(triggerBox, playerBox)) {
if (!Collision::AABBVsAABB(*triggerBox, *playerBox)) {
//Entity is not touching the trigger,
//Throw event if it was previously.
if (throwLeaveIfWasInTrigger(m_EntitiesTouchingTrigger[tId], pId, tId)) {
@@ -34,10 +34,9 @@ void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, dou
throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[tId], pId, tId);
} else {
//Entity is at least touching the trigger.
AABB completelyInsideBox;
completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - 2.0f * playerBox.Size());
if (Collision::AABBVsAABB(completelyInsideBox, playerBox) &&
glm::all(glm::greaterThan(triggerBox.Size(), playerBox.Size()))) {
AABB completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*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);
+5 -8
View File
@@ -4,7 +4,7 @@
AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
: m_MinCorner(minPos)
, m_MaxCorner(maxPos)
, m_Center(0.5f * (maxPos + minPos))
, m_Origin(0.5f * (maxPos + minPos))
, m_HalfSize(0.5f * (maxPos - minPos))
{
DEBUG_IF(glm::any(glm::lessThan(m_MaxCorner, m_MinCorner))) {
@@ -20,15 +20,12 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
AABB::AABB(const glm::vec4& minPos, const glm::vec4& maxPos)
: AABB(glm::vec3(minPos), glm::vec3(maxPos))
{}
{ }
void AABB::CreateFromCenter(const glm::vec3& center, const glm::vec3& size)
AABB AABB::FromOriginSize(const glm::vec3& origin, const glm::vec3& size)
{
m_Center = center;
m_HalfSize = 0.5f * size;
m_MinCorner = m_Center - m_HalfSize;
m_MaxCorner = m_Center + m_HalfSize;
return AABB(origin - (size/2.f), origin + (size/2.f));
}
AABB::~AABB()
{}
{ }
+4 -8
View File
@@ -21,14 +21,10 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
}
Octree::Octree()
: Octree(AABB(), 0)
{}
Octree::Octree(const AABB& octTreeBounds, int subDivisions)
: m_Root(new Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
, m_UpdatedOnce(false)
{}
{ }
Octree::~Octree()
{
@@ -107,7 +103,7 @@ Octree::Child::Child(const AABB& octTreeBounds,
glm::vec3 minPos, maxPos;
const glm::vec3& parentMin = m_Box.MinCorner();
const glm::vec3& parentMax = m_Box.MaxCorner();
const glm::vec3& parentCenter = m_Box.Center();
const glm::vec3& parentCenter = m_Box.Origin();
std::bitset<3> bits(i);
//If child is 4,5,6,7.
if (bits.test(2)) {
@@ -192,7 +188,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
std::vector<ChildInfo> childInfos;
childInfos.reserve(8);
for (int i = 0; i < 8; ++i) {
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Center()) });
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) });
}
std::sort(childInfos.begin(), childInfos.end(), isFirstLower);
//Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit.
@@ -329,7 +325,7 @@ void Octree::Child::ClearDynamicObjects()
// z : - + - + - + - +
int Octree::Child::childIndexContainingPoint(const glm::vec3& point) const
{
const glm::vec3& c = m_Box.Center();
const glm::vec3& c = m_Box.Origin();
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
}
+2 -1
View File
@@ -3,7 +3,8 @@
#include <imgui/imgui_internal.h>
EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
: ImpureSystem(eventBroker)
: System(eventBroker)
, ImpureSystem()
, m_Renderer(renderer)
{
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
+14 -6
View File
@@ -1,4 +1,5 @@
#include "Game.h"
#include "Collision/CollidableOctreeSystem.h"
#include "Collision/TriggerSystem.h"
#include "Collision/CollisionSystem.h"
#include "Game/HealthSystem.h"
@@ -56,20 +57,25 @@ Game::Game(int argc, char* argv[])
fp.MergeEntities(m_World);
}
// Create Octrees
m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4);
m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4);
// Create system pipeline
m_SystemPipeline = new SystemPipeline(m_EventBroker);
//All systems with orderlevel 0 will be updated first.
// All systems with orderlevel 0 will be updated first.
unsigned int updateOrderLevel = 0;
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
//Collision and TriggerSystem should update after player.
// Populate Octree with collidables
++updateOrderLevel;
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<CollidableOctreeSystem>(updateOrderLevel, m_OctreeCollision);
// Collision and TriggerSystem should update after player.
++updateOrderLevel;
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel, m_OctreeCollision);
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel, m_OctreeCollision);
// Invoke network
if (m_Config->Get<bool>("Networking.StartNetwork", false)) {
@@ -82,6 +88,8 @@ Game::Game(int argc, char* argv[])
Game::~Game()
{
delete m_SystemPipeline;
delete m_OctreeFrustrumCulling;
delete m_OctreeCollision;
delete m_World;
delete m_FrameStack;
delete m_InputProxy;
+2 -1
View File
@@ -2,7 +2,8 @@
#include <algorithm>
HealthSystem::HealthSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Health")
: System(eventBroker)
, PureSystem("Health")
{
//subscribe/listenTo playerdamage,healthpickup events (using the eventBroker)
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged);
+3 -3
View File
@@ -21,9 +21,9 @@ BOOST_AUTO_TEST_CASE(octSameRegionTest)
tree.BoxesInSameRegion(testBox, region);
BOOST_REQUIRE(region.size() == 1);
AABB& box = region[0];
BOOST_CHECK_CLOSE_FRACTION(box.Center().x, firstQuadrant.Center().x, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Center().y, firstQuadrant.Center().y, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Center().z, firstQuadrant.Center().z, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Origin().x, firstQuadrant.Origin().x, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Origin().y, firstQuadrant.Origin().y, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Origin().z, firstQuadrant.Origin().z, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().x, firstQuadrant.HalfSize().x, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().y, firstQuadrant.HalfSize().y, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().z, firstQuadrant.HalfSize().z, 0.00001f);
+2 -2
View File
@@ -91,7 +91,7 @@ void Game::Tick()
frameCounter = 0;
}
ComponentWrapper transform = m_World->GetComponent(m_World->anotherBoxTransformId, "Transform");
transform["Position"] = boxi.Center();
transform["Position"] = boxi.Origin();
//check all children again in the tree if they have a box in them or not, and colormark them if they do
//contentboxarna får man ut - inte childboxarna!
@@ -110,7 +110,7 @@ void Game::Tick()
//REQUIRED: childIndicesContainingBox must be public to test this!
for each (auto someBoxIndex in boxIndex)
{
glm::vec3 pos = m_World->someOctTree.m_Root->m_Children[someBoxIndex]->m_Box.Center();
glm::vec3 pos = m_World->someOctTree.m_Root->m_Children[someBoxIndex]->m_Box.Origin();
if (abs(pos.x - oneLinkedObject.posxyz.x) < 0.005f &&
abs(pos.y - oneLinkedObject.posxyz.y) < 0.005f &&
abs(pos.z - oneLinkedObject.posxyz.z) < 0.005f) {
+4 -4
View File
@@ -77,7 +77,7 @@ private:
auto someAABB = AABB(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f));
//draw main box first
AddBoxModel(someAABB.Center(), someAABB.HalfSize().x, someOctTree.m_Root, tempId);
AddBoxModel(someAABB.Origin(), someAABB.HalfSize().x, someOctTree.m_Root, tempId);
//add anotherbox in octTree
auto anotherBox = AABB(glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.2f, 0.2f, 0.2f));
@@ -85,19 +85,19 @@ private:
someOctTree.AddDynamicObject(anotherBox);
//draw anotherbox and save it in anotherBoxTransformId
AddBoxModel(anotherBox.Center(), anotherBox.HalfSize().x, someOctTree.m_Root, anotherBoxTransformId);
AddBoxModel(anotherBox.Origin(), anotherBox.HalfSize().x, someOctTree.m_Root, anotherBoxTransformId);
//draw the octTree
for (size_t j = 0; j < 8; j++)
{
AddBoxModel(someOctTree.m_Root->m_Children[j]->m_Box.Center(),
AddBoxModel(someOctTree.m_Root->m_Children[j]->m_Box.Origin(),
someOctTree.m_Root->m_Children[j]->m_Box.HalfSize().x, someOctTree.m_Root->m_Children[j], tempId);
auto someChild = someOctTree.m_Root->m_Children[j];
for (size_t i = 0; i < 8; i++)
{
AddBoxModel(someChild->m_Children[i]->m_Box.Center(),
AddBoxModel(someChild->m_Children[i]->m_Box.Origin(),
someChild->m_Children[i]->m_Box.HalfSize().x, someChild->m_Children[i], tempId);
}
}
+3 -3
View File
@@ -54,7 +54,7 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
glm::vec3 minPos, maxPos;
const glm::vec3& parentMin = m_Box.MinCorner();
const glm::vec3& parentMax = m_Box.MaxCorner();
const glm::vec3& parentCenter = m_Box.Center();
const glm::vec3& parentCenter = m_Box.Origin();
std::bitset<3> bits(i);
//If child is 4,5,6,7.
if (bits.test(2)) {
@@ -172,7 +172,7 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const
std::vector<ChildInfo> childInfos;
childInfos.reserve(8);
for (int i = 0; i < 8; ++i) {
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Center()) });
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) });
}
std::sort(childInfos.begin(), childInfos.end(), isFirstLower);
//Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit.
@@ -279,7 +279,7 @@ void OctTree::ClearDynamicObjects()
// z : - + - + - + - +
int OctTree::childIndexContainingPoint(const glm::vec3& point) const
{
const glm::vec3& c = m_Box.Center();
const glm::vec3& c = m_Box.Origin();
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
}