From 22664848dc44ab481a3dbe601c70132202262edf Mon Sep 17 00:00:00 2001 From: William Moberg Date: Fri, 19 Feb 2016 14:16:22 +0100 Subject: [PATCH] You should not be able to fall through ground or dash thru walls. Very thin objects may still be possible to go through, e.g. the grid border walls in GameMap.xml. --- include/Engine/Collision/CollisionSystem.h | 4 +- resources/Schema/Components/Physics.xml | 1 + resources/Schema/Components/Physics.xsd | 1 + src/Engine/Collision/Collision.cpp | 2 +- src/Engine/Collision/CollisionSystem.cpp | 59 ++++++++++++++++++++-- 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index c963e6b8..9cd2fe63 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -15,11 +15,11 @@ class CollisionSystem : public PureSystem public: CollisionSystem(SystemParams params, Octree* octree) : System(params) - , PureSystem("Collidable") + , PureSystem("Physics") , m_Octree(octree) { } - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPhysics, double dt) override; private: Octree* m_Octree; diff --git a/resources/Schema/Components/Physics.xml b/resources/Schema/Components/Physics.xml index 6cb73c75..84b6aba3 100644 --- a/resources/Schema/Components/Physics.xml +++ b/resources/Schema/Components/Physics.xml @@ -2,6 +2,7 @@ true + false 0.33 diff --git a/resources/Schema/Components/Physics.xsd b/resources/Schema/Components/Physics.xsd index 7fed1fb5..206e2a23 100644 --- a/resources/Schema/Components/Physics.xsd +++ b/resources/Schema/Components/Physics.xsd @@ -13,6 +13,7 @@ m/s^2 + The largest height of a "stair-step" that can be walked over diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index ab2098b7..3aadf9fe 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -207,7 +207,7 @@ bool RayVsModel(const Ray& ray, glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); glm::vec3 v1 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); - float dist = INFINITY; + float dist = outDistance; float u; float v; if (RayVsTriangle(ray, v0, v1, v2, dist, u, v)) { diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index afd09022..fcc3665f 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -3,24 +3,71 @@ #include "Core/AABB.h" #include "Rendering/Model.h" -void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) +void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPhysics, double dt) { - if (!entity.HasComponent("Physics")) { + if (!entity.HasComponent("Collidable")) { return; } - ComponentWrapper& cPhysics = entity["Physics"]; - boost::optional boundingBox = Collision::EntityAbsoluteAABB(entity); if (!boundingBox) { return; } ComponentWrapper& cTransform = entity["Transform"]; EntityAABB& boxA = *boundingBox; + bool everHitTheGround = false; + + glm::vec3 size = boxA.Size(); + float diameter = std::min(size.x, size.z); + glm::vec3 prevOrigin = (glm::vec3)cPhysics["PrevOrigin"]; + glm::vec3 toCurrentPos = boxA.Origin() - prevOrigin; + float rayLength = glm::length(toCurrentPos) + 0.5f*diameter; + //If the entity has moved farther than the size of its box, we need to handle it specially. + bool traceCollision = rayLength > diameter; + //hack solution: If prevOrigin is less than -9000 in all dimensions, + //then it means it is not set, i.e. this is the first collision check for the entity. + if (traceCollision && glm::any(glm::greaterThan((glm::vec3)cPhysics["PrevOrigin"], glm::vec3(-9000.f)))) { + Ray ray(prevOrigin, toCurrentPos); + m_OctreeResult.clear(); + m_Octree->ObjectsPossiblyHitByRay(ray, m_OctreeResult); + for (auto& boxB : m_OctreeResult) { + if (boxA.Entity == boxB.Entity) { + continue; + } + bool hit; + float dist; + if (boxB.Entity.HasComponent("Model")) { + RawModel* model; + std::string res = (std::string)boxB.Entity["Model"]["Resource"]; + try { + model = ResourceManager::Load(res); + } catch (const std::exception&) { + continue; + } + float u, v; + hit = Collision::RayVsModel(ray, model->Vertices(), model->m_Indices, Transform::ModelMatrix(boxB.Entity), dist, u, v); + } else { + hit = Collision::RayVsAABB(ray, boxB, dist); + } + if (hit && dist < rayLength) { + //Set the entity to where it was colliding, minus the maximum box size. + //TODO: Perhaps this should be done slightly more properly. + glm::vec3 newOriginPos = ray.Origin() + (dist - 0.707107f*diameter) * ray.Direction(); + glm::vec3 resolve = newOriginPos - boxA.Origin(); + (glm::vec3&)cTransform["Position"] += resolve; + boxA = *Collision::EntityAbsoluteAABB(entity); + if (resolve.y > 0) { + everHitTheGround = true; + (bool)cPhysics["IsOnGround"] = true; + ((glm::vec3&)cPhysics["Velocity"]).y = 0.f; + } + break; + } + } + } // Collide against octree items m_OctreeResult.clear(); m_Octree->ObjectsInSameRegion(*boundingBox, m_OctreeResult); - bool everHitTheGround = false; for (auto& boxB : m_OctreeResult) { glm::vec3 resolutionVector; if (boxA.Entity == boxB.Entity) { @@ -64,4 +111,6 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c if (!everHitTheGround) { (bool)cPhysics["IsOnGround"] = false; } + + (glm::vec3&)cPhysics["PrevOrigin"] = boxA.Origin(); }