Fixed bug where collision & trigger state were called more than once

This commit is contained in:
Diren D Bharwani 2023-03-03 23:47:39 +08:00
parent 446db133d2
commit 6200e3f533
8 changed files with 77 additions and 84 deletions

View File

@ -38,10 +38,6 @@
Rotation Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true IsActive: true
Scripts: Scripts:
- Type: PhysicsTestObj
Enabled: true
forceAmount: 50
torqueAmount: 500
- Type: CollisionTest - Type: CollisionTest
Enabled: true Enabled: true
- EID: 1 - EID: 1
@ -176,46 +172,6 @@
Rotation Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 7
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0, z: 3}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
RigidBody Component:
Type: Dynamic
Auto Mass: false
Mass: 1
Drag: 0.00999999978
Angular Drag: 0.100000001
Use Gravity: true
Gravity Scale: 1
Interpolate: true
Sleeping Enabled: true
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: false
Freeze Rotation Y: false
Freeze Rotation Z: false
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~
- EID: 8 - EID: 8
Name: Target Name: Target
IsActive: true IsActive: true

View File

@ -76,8 +76,6 @@ namespace SHADE
continue; continue;
const auto* SHAPE_A = manifold.shapeA; const auto* SHAPE_A = manifold.shapeA;
const auto* SHAPE_B = manifold.shapeB;
const SHCollisionUtils::ShapeTransform TF_A = { SHAPE_A->GetWorldCentroid(), SHAPE_A->GetWorldOrientation() }; const SHCollisionUtils::ShapeTransform TF_A = { SHAPE_A->GetWorldCentroid(), SHAPE_A->GetWorldOrientation() };
for (uint32_t i = 0; i < manifold.numContacts; ++i) for (uint32_t i = 0; i < manifold.numContacts; ++i)
@ -138,22 +136,41 @@ namespace SHADE
removeInvalidObject(manifolds, eid, shapeIndex); removeInvalidObject(manifolds, eid, shapeIndex);
} }
void SHContactManager::RemoveExpiredContacts() noexcept
{
// Manifolds
for (auto manifoldsIter = manifolds.begin(); manifoldsIter != manifolds.end();)
{
const auto STATE = manifoldsIter->second.state;
if (STATE == SHCollisionState::INVALID || STATE == SHCollisionState::EXIT)
manifoldsIter = manifolds.erase(manifoldsIter);
else
++manifoldsIter;
}
// Triggers
for (auto triggersIter = triggers.begin(); triggersIter != triggers.end();)
{
const auto STATE = triggersIter->second.state;
if (STATE == SHCollisionState::INVALID || STATE == SHCollisionState::EXIT)
triggersIter = triggers.erase(triggersIter);
else
++triggersIter;
}
}
void SHContactManager::Update() noexcept void SHContactManager::Update() noexcept
{ {
// Clear expired or invalid collisions. If not, test collision.
for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();) for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();)
{ {
// Test collision of every manifold. SHManifold& manifold = manifoldPair->second;
SHManifold& manifold = manifoldPair->second;
SHManifold oldManifold = manifold; SHManifold oldManifold = manifold;
const bool IS_COLLIDING = SHCollisionDispatcher::Collide(manifold, *manifold.shapeA, *manifold.shapeB); const bool IS_COLLIDING = SHCollisionDispatcher::Collide(manifold, *manifold.shapeA, *manifold.shapeB);
updateCollisionState(IS_COLLIDING, manifold.state);
auto& collisionState = manifold.state; // For any false positives
updateCollisionState(IS_COLLIDING, collisionState); if (manifold.state == SHCollisionState::INVALID)
const bool IS_INVALID = collisionState == SHCollisionState::INVALID;
if (IS_INVALID)
{ {
manifoldPair = manifolds.erase(manifoldPair); manifoldPair = manifolds.erase(manifoldPair);
continue; continue;
@ -163,19 +180,16 @@ namespace SHADE
++manifoldPair; ++manifoldPair;
} }
// Clear expired or invalid triggers, If not, test collision.
for (auto triggerPair = triggers.begin(); triggerPair != triggers.end();) for (auto triggerPair = triggers.begin(); triggerPair != triggers.end();)
{ {
// Test collision of every trigger. // Test collision of every trigger.
Trigger& trigger = triggerPair->second; Trigger& trigger = triggerPair->second;
const bool IS_COLLIDING = SHCollisionDispatcher::Collide(*trigger.A, *trigger.B); const bool IS_COLLIDING = SHCollisionDispatcher::Collide(*trigger.A, *trigger.B);
updateCollisionState(IS_COLLIDING, trigger.state);
auto& collisionState = trigger.state; // For any false positives
updateCollisionState(IS_COLLIDING, collisionState); if (trigger.state == SHCollisionState::INVALID)
const bool IS_INVALID = collisionState == SHCollisionState::INVALID;
if (IS_INVALID)
triggerPair = triggers.erase(triggerPair); triggerPair = triggers.erase(triggerPair);
else else
++triggerPair; ++triggerPair;
@ -238,7 +252,11 @@ namespace SHADE
{ {
// New states start at invalid. In the first frame of collision, move to enter. // New states start at invalid. In the first frame of collision, move to enter.
// If it already in enter, move to stay // If it already in enter, move to stay
state = state == SHCollisionState::INVALID ? SHCollisionState::ENTER : SHCollisionState::STAY; if (state == SHCollisionState::ENTER)
state = SHCollisionState::STAY;
if (state == SHCollisionState::INVALID)
state = SHCollisionState::ENTER;
} }
else else
{ {

View File

@ -79,6 +79,12 @@ namespace SHADE
void RemoveInvalidatedManifold (EntityID eid) noexcept; void RemoveInvalidatedManifold (EntityID eid) noexcept;
void RemoveInvalidatedManifold (EntityID eid, uint32_t shapeIndex) noexcept; void RemoveInvalidatedManifold (EntityID eid, uint32_t shapeIndex) noexcept;
/**
* @brief
* Removes any contact manifold or triggers that are in the exit or invalid state.
*/
void RemoveExpiredContacts () noexcept;
/** /**
* @brief * @brief
* Removes any invalidated contacts and triggers, then performs narrowphase collision * Removes any invalidated contacts and triggers, then performs narrowphase collision

View File

@ -86,13 +86,19 @@ namespace SHADE
void SHPhysicsWorld::Step(float dt) void SHPhysicsWorld::Step(float dt)
{ {
/* /*
* Detect Collisions * Detect Collisions
*/ */
contactManager.RemoveExpiredContacts();
if (collisionSpace) if (collisionSpace)
collisionSpace->DetectCollisions(); collisionSpace->DetectCollisions();
// TODO: Build Islands
/* /*
* Integrate Forces * Integrate Forces
*/ */
@ -106,7 +112,6 @@ namespace SHADE
integrateForces(*rigidBody, dt); integrateForces(*rigidBody, dt);
} }
/* /*
* Resolve Contacts * Resolve Contacts
*/ */

View File

@ -15,6 +15,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Physics/System/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
@ -36,7 +37,6 @@ namespace SHADE
void SHPhysicsDebugDrawSystem::PhysicsDebugDraw::Execute(double) noexcept void SHPhysicsDebugDrawSystem::PhysicsDebugDraw::Execute(double) noexcept
{ {
#ifdef SHEDITOR
auto* physicsDebugDrawSystem = reinterpret_cast<SHPhysicsDebugDrawSystem*>(GetSystem()); auto* physicsDebugDrawSystem = reinterpret_cast<SHPhysicsDebugDrawSystem*>(GetSystem());
if (!physicsDebugDrawSystem->IsDebugDrawActive()) if (!physicsDebugDrawSystem->IsDebugDrawActive())
@ -86,17 +86,22 @@ namespace SHADE
} }
} }
if (DRAW_RAYCASTS) #ifdef SHEDITOR
{ if (DRAW_RAYCASTS)
const SHColour& RAY_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)]; {
const SHColour& RAY_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)];
const auto& RAYS = physicsSystem->raycastHits; auto& rays = physicsSystem->raycastHits;
for (const auto& hit : RAYS) for (const auto& hit : rays)
debugDrawSystem->DrawLine(hit.start, hit.end, RAY_COLOUR, true); debugDrawSystem->DrawLine(hit.start, hit.end, RAY_COLOUR, true);
// Clear rays for the physics system // Clear the raycast hit container only in play mode.
physicsSystem->raycastHits.clear(); // No other raycasts are assumed to be done in pause or stop mode.
} const auto EDITOR_STATE = SHSystemManager::GetSystem<SHEditor>()->editorState;
if (EDITOR_STATE == SHEditor::State::PLAY)
rays.clear();
}
#endif
if (DRAW_BROADPHASE) if (DRAW_BROADPHASE)
{ {
@ -110,7 +115,6 @@ namespace SHADE
debugDrawSystem->DrawWireCube(TRS, AABB_COLOUR); debugDrawSystem->DrawWireCube(TRS, AABB_COLOUR);
} }
} }
#endif
} }
} // namespace SHADE } // namespace SHADE

View File

@ -35,7 +35,7 @@ namespace SHADE
void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept
{ {
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem()); auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>(); auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr) if (scriptingSystem == nullptr)
@ -93,10 +93,6 @@ namespace SHADE
*/ */
} }
} }
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
} }
} // namespace SHADE } // namespace SHADE

View File

@ -35,10 +35,10 @@ namespace SHADE
{ {
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem()); auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptEngine = SHSystemManager::GetSystem<SHScriptEngine>(); auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (!scriptEngine) if (!scriptingSystem)
{ {
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing ScriptEngine!") SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!")
} }
const double FIXED_DT = physicsSystem->fixedDT; const double FIXED_DT = physicsSystem->fixedDT;
@ -47,12 +47,15 @@ namespace SHADE
int count = 0; int count = 0;
while (accumulatedTime > FIXED_DT) while (accumulatedTime > FIXED_DT)
{ {
if (scriptEngine) if (scriptingSystem)
scriptEngine->ExecuteFixedUpdates(); scriptingSystem->ExecuteFixedUpdates();
if (physicsSystem->physicsWorld) if (physicsSystem->physicsWorld)
physicsSystem->physicsWorld->Step(static_cast<float>(FIXED_DT)); physicsSystem->physicsWorld->Step(static_cast<float>(FIXED_DT));
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
accumulatedTime -= FIXED_DT; accumulatedTime -= FIXED_DT;
++count; ++count;
} }

View File

@ -287,6 +287,11 @@ namespace SHADE
collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider); collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider);
} }
#ifdef SHEDITOR
// HACK: Editor stop always goes into scene exit
raycastHits.clear();
#endif
delete collisionSpace; delete collisionSpace;
collisionSpace = nullptr; collisionSpace = nullptr;