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.
This commit is contained in:
@@ -15,11 +15,11 @@ class CollisionSystem : public PureSystem
|
|||||||
public:
|
public:
|
||||||
CollisionSystem(SystemParams params, Octree<EntityAABB>* octree)
|
CollisionSystem(SystemParams params, Octree<EntityAABB>* octree)
|
||||||
: System(params)
|
: System(params)
|
||||||
, PureSystem("Collidable")
|
, PureSystem("Physics")
|
||||||
, m_Octree(octree)
|
, m_Octree(octree)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override;
|
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPhysics, double dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Octree<EntityAABB>* m_Octree;
|
Octree<EntityAABB>* m_Octree;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<Physics xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Physics.xsd">
|
<Physics xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Physics.xsd">
|
||||||
<Velocity X="0" Y="0" Z="0"/>
|
<Velocity X="0" Y="0" Z="0"/>
|
||||||
<Gravity>true</Gravity>
|
<Gravity>true</Gravity>
|
||||||
|
<PrevOrigin X="-9876.5" Y="-9876.5" Z="-9876.5"/>
|
||||||
<IsOnGround>false</IsOnGround>
|
<IsOnGround>false</IsOnGround>
|
||||||
<VerticalStepHeight>0.33</VerticalStepHeight>
|
<VerticalStepHeight>0.33</VerticalStepHeight>
|
||||||
</Physics>
|
</Physics>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<xs:annotation><xs:documentation>m/s^2</xs:documentation></xs:annotation>
|
<xs:annotation><xs:documentation>m/s^2</xs:documentation></xs:annotation>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="Gravity" type="t:bool" minOccurs="0"/>
|
<xs:element name="Gravity" type="t:bool" minOccurs="0"/>
|
||||||
|
<xs:element name="PrevOrigin" type="t:Vector" minOccurs="0"/>
|
||||||
<xs:element name="IsOnGround" type="t:bool" minOccurs="0"/>
|
<xs:element name="IsOnGround" type="t:bool" minOccurs="0"/>
|
||||||
<xs:element name="VerticalStepHeight" type="t:double" minOccurs="0">
|
<xs:element name="VerticalStepHeight" type="t:double" minOccurs="0">
|
||||||
<xs:annotation><xs:documentation>The largest height of a "stair-step" that can be walked over</xs:documentation></xs:annotation>
|
<xs:annotation><xs:documentation>The largest height of a "stair-step" that can be walked over</xs:documentation></xs:annotation>
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ bool RayVsModel(const Ray& ray,
|
|||||||
glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
|
glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
|
||||||
glm::vec3 v1 = 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);
|
glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
|
||||||
float dist = INFINITY;
|
float dist = outDistance;
|
||||||
float u;
|
float u;
|
||||||
float v;
|
float v;
|
||||||
if (RayVsTriangle(ray, v0, v1, v2, dist, u, v)) {
|
if (RayVsTriangle(ray, v0, v1, v2, dist, u, v)) {
|
||||||
|
|||||||
@@ -3,24 +3,71 @@
|
|||||||
#include "Core/AABB.h"
|
#include "Core/AABB.h"
|
||||||
#include "Rendering/Model.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;
|
return;
|
||||||
}
|
}
|
||||||
ComponentWrapper& cPhysics = entity["Physics"];
|
|
||||||
|
|
||||||
boost::optional<EntityAABB> boundingBox = Collision::EntityAbsoluteAABB(entity);
|
boost::optional<EntityAABB> boundingBox = Collision::EntityAbsoluteAABB(entity);
|
||||||
if (!boundingBox) {
|
if (!boundingBox) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ComponentWrapper& cTransform = entity["Transform"];
|
ComponentWrapper& cTransform = entity["Transform"];
|
||||||
EntityAABB& boxA = *boundingBox;
|
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<RawModel, true>(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
|
// Collide against octree items
|
||||||
m_OctreeResult.clear();
|
m_OctreeResult.clear();
|
||||||
m_Octree->ObjectsInSameRegion(*boundingBox, m_OctreeResult);
|
m_Octree->ObjectsInSameRegion(*boundingBox, m_OctreeResult);
|
||||||
bool everHitTheGround = false;
|
|
||||||
for (auto& boxB : m_OctreeResult) {
|
for (auto& boxB : m_OctreeResult) {
|
||||||
glm::vec3 resolutionVector;
|
glm::vec3 resolutionVector;
|
||||||
if (boxA.Entity == boxB.Entity) {
|
if (boxA.Entity == boxB.Entity) {
|
||||||
@@ -64,4 +111,6 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
|
|||||||
if (!everHitTheGround) {
|
if (!everHitTheGround) {
|
||||||
(bool)cPhysics["IsOnGround"] = false;
|
(bool)cPhysics["IsOnGround"] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(glm::vec3&)cPhysics["PrevOrigin"] = boxA.Origin();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user