PlayerController and PickAndThrow #167

Merged
glencelow merged 21 commits from PlayerController into main 2022-11-02 17:40:51 +08:00
4 changed files with 265 additions and 286 deletions
Showing only changes of commit c572bb0f58 - Show all commits

View File

@ -173,93 +173,93 @@ namespace SHADE
SHASSERT(rp3dBody != nullptr, "ReactPhysics body does not exist!")
auto* rigidBody = reinterpret_cast<rp3d::RigidBody*>(rp3dBody);
// Sync velocities
rb->linearVelocity = rigidBody->getLinearVelocity();
rb->angularVelocity = rigidBody->getAngularVelocity();
if (rb->dirtyFlags == 0)
return;
const uint16_t RB_FLAGS = rb->dirtyFlags;
for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i)
if (rb->dirtyFlags != 0)
{
// Check if current dirty flag has been set to true
if (RB_FLAGS & 1U << i)
const uint16_t RB_FLAGS = rb->dirtyFlags;
for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i)
{
switch (i)
// Check if current dirty flag has been set to true
if (RB_FLAGS & 1U << i)
{
case 0: // Gravity
switch (i)
{
rigidBody->enableGravity(rb->IsGravityEnabled());
break;
}
case 1: // Sleeping
{
rigidBody->setIsAllowedToSleep(rb->IsAllowedToSleep());
break;
}
case 2: // Linear Constraints
{
const rp3d::Vector3 CONSTRAINTS
case 0: // Gravity
{
rb->flags & 1U << 2 ? 0.0f : 1.0f,
rb->flags & 1U << 3 ? 0.0f : 1.0f,
rb->flags & 1U << 4 ? 0.0f : 1.0f
};
rigidBody->setLinearLockAxisFactor(CONSTRAINTS);
break;
}
case 3: // Angular Constraints
{
const rp3d::Vector3 CONSTRAINTS
rigidBody->enableGravity(rb->IsGravityEnabled());
break;
}
case 1: // Sleeping
{
rb->flags & 1U << 5 ? 0.0f : 1.0f,
rb->flags & 1U << 6 ? 0.0f : 1.0f,
rb->flags & 1U << 7 ? 0.0f : 1.0f
};
rigidBody->setIsAllowedToSleep(rb->IsAllowedToSleep());
break;
}
case 2: // Linear Constraints
{
const rp3d::Vector3 CONSTRAINTS
{
rb->flags & 1U << 2 ? 0.0f : 1.0f,
rb->flags & 1U << 3 ? 0.0f : 1.0f,
rb->flags & 1U << 4 ? 0.0f : 1.0f
};
rigidBody->setAngularLockAxisFactor(CONSTRAINTS);
break;
rigidBody->setLinearLockAxisFactor(CONSTRAINTS);
break;
}
case 3: // Angular Constraints
{
const rp3d::Vector3 CONSTRAINTS
{
rb->flags & 1U << 5 ? 0.0f : 1.0f,
rb->flags & 1U << 6 ? 0.0f : 1.0f,
rb->flags & 1U << 7 ? 0.0f : 1.0f
};
rigidBody->setAngularLockAxisFactor(CONSTRAINTS);
break;
}
case 4: // Type
{
rigidBody->setType(static_cast<rp3d::BodyType>(rb->GetType()));
break;
}
case 5: // Mass
{
rigidBody->setMass(rb->GetMass());
break;
}
case 6: // Drag
{
rigidBody->setLinearDamping(rb->GetDrag());
break;
}
case 7: // Angular Drag
{
rigidBody->setAngularDamping(rb->GetAngularDrag());
break;
}
case 8: // Linear Velocity
{
rigidBody->setLinearVelocity(rb->GetLinearVelocity());
break;
}
case 9: // Angular Velocity
{
rigidBody->setAngularVelocity(rb->GetAngularVelocity());
break;
}
default: break;
}
case 4: // Type
{
rigidBody->setType(static_cast<rp3d::BodyType>(rb->GetType()));
break;
}
case 5: // Mass
{
rigidBody->setMass(rb->GetMass());
break;
}
case 6: // Drag
{
rigidBody->setLinearDamping(rb->GetDrag());
break;
}
case 7: // Angular Drag
{
rigidBody->setAngularDamping(rb->GetAngularDrag());
break;
}
case 8: // Linear Velocity
{
rigidBody->setLinearVelocity(rb->GetLinearVelocity());
break;
}
case 9: // Angular Velocity
{
rigidBody->setAngularVelocity(rb->GetAngularVelocity());
break;
}
default: break;
}
}
}
rb->dirtyFlags = 0;
rb->dirtyFlags = 0;
}
else
{
rb->linearVelocity = rigidBody->getLinearVelocity();
rb->angularVelocity = rigidBody->getAngularVelocity();
}
}
void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept

View File

@ -257,7 +257,10 @@ namespace SHADE
if (physicsObject.rp3dBody == nullptr)
continue;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (transformComponent && transformComponent->HasChanged())
{
const auto WORLD_POS = transformComponent->GetWorldPosition();
@ -266,46 +269,57 @@ namespace SHADE
physicsObject.SetPosition(WORLD_POS);
physicsObject.SetOrientation(WORLD_ROT);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
// Sync physics component transforms
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
// Clear all forces and velocities if editor is stopped
if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP)
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
const bool COMPONENT_ACTIVE = rigidBodyComponent->isActive;
system->SyncActiveStates(&physicsObject, COMPONENT_ACTIVE);
if (!COMPONENT_ACTIVE)
continue;
physicsObject.SyncRigidBody(rigidBodyComponent);
}
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
const bool COMPONENT_ACTIVE = colliderComponent->isActive;
system->SyncActiveStates(&physicsObject, COMPONENT_ACTIVE);
if (!COMPONENT_ACTIVE)
continue;
physicsObject.SyncColliders(colliderComponent);
}
}
// Sync rigid bodies
if (rigidBodyComponent)
{
// Clear all forces and velocities if editor is stopped
if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP)
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
// Sync active states
const bool COMPONENT_ACTIVE = rigidBodyComponent->isActive;
SyncActiveStates(physicsObject, COMPONENT_ACTIVE);
if (!COMPONENT_ACTIVE)
continue;
physicsObject.SyncRigidBody(rigidBodyComponent);
}
// Sync colliders
if (colliderComponent)
{
const bool COMPONENT_ACTIVE = colliderComponent->isActive;
SyncActiveStates(physicsObject, colliderComponent->isActive);
if (!COMPONENT_ACTIVE)
continue;
physicsObject.SyncColliders(colliderComponent);
}
}
}
@ -349,26 +363,10 @@ namespace SHADE
{
for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i)
{
auto contactPair = callbackData.getContactPair(i);
SHCollisionEvent newCollisionEvent = GenerateCollisionEvent(contactPair);
const auto CONTACT_PAIR = callbackData.getContactPair(i);
const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(CONTACT_PAIR);
// Find contact pair in container
auto existingEvent = std::ranges::find_if(collisionInfo.begin(), collisionInfo.end(), [&](const SHCollisionEvent& e)
{
const bool ENTITY_MATCH = e.value[0] == newCollisionEvent.value[0];
const bool COLLIDERS_MATCH = e.value[1] == newCollisionEvent.value[1];
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (existingEvent == collisionInfo.end())
{
// Add new event
collisionInfo.emplace_back(newCollisionEvent);
}
else
{
existingEvent->collisionState = newCollisionEvent.collisionState;
}
UpdateEventContainers(NEW_EVENT, collisionInfo);
}
}
@ -376,26 +374,10 @@ namespace SHADE
{
for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i)
{
auto contactPair = callbackData.getOverlappingPair(i);
SHCollisionEvent newTriggerEvent = GenerateCollisionEvent(contactPair);
const auto& OVERLAP_PAIR = callbackData.getOverlappingPair(i);
const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(OVERLAP_PAIR);
// Find contact pair in container
auto existingEvent = std::ranges::find_if(collisionInfo.begin(), collisionInfo.end(), [&](const SHCollisionEvent& e)
{
const bool ENTITY_MATCH = e.value[0] == newTriggerEvent.value[0];
const bool COLLIDERS_MATCH = e.value[1] == newTriggerEvent.value[1];
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (existingEvent == collisionInfo.end())
{
// Add new event
triggerInfo.emplace_back(newTriggerEvent);
}
else
{
existingEvent->collisionState = newTriggerEvent.collisionState;
}
UpdateEventContainers(NEW_EVENT, triggerInfo);
}
}
@ -432,11 +414,11 @@ namespace SHADE
map.erase(entityID);
}
void SHPhysicsSystem::SyncActiveStates(SHPhysicsObject* physicsObject, bool componentActive) noexcept
void SHPhysicsSystem::SyncActiveStates(SHPhysicsObject& physicsObject, bool componentActive) noexcept
{
const bool RP3D_ACTIVE = physicsObject->rp3dBody->isActive();
const bool RP3D_ACTIVE = physicsObject.rp3dBody->isActive();
if (RP3D_ACTIVE != componentActive)
physicsObject->rp3dBody->setIsActive(componentActive);
physicsObject.rp3dBody->setIsActive(componentActive);
}
void SHPhysicsSystem::SyncTransforms() noexcept
@ -491,155 +473,54 @@ namespace SHADE
}
// Convert RP3D Transform to SHADE
auto* transformComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
transformComponent->SetWorldPosition(rp3dPos);
transformComponent->SetWorldOrientation(rp3dRot);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent != nullptr)
{
transformComponent->SetWorldPosition(rp3dPos);
transformComponent->SetWorldOrientation(rp3dRot);
}
// Cache transforms
physicsObject.prevTransform = CURRENT_TF;
}
}
void SHPhysicsSystem::UpdateEventContainers(const SHCollisionEvent& collisionEvent, CollisionEvents& container) noexcept
{
const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionEvent& e)
{
const bool ENTITY_MATCH = e.value[0] == collisionEvent.value[0];
const bool COLLIDERS_MATCH = e.value[1] == collisionEvent.value[1];
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (IT == container.end())
container.emplace_back(collisionEvent);
else
IT->collisionState = collisionEvent.collisionState;
}
void SHPhysicsSystem::ClearInvalidCollisions() noexcept
{
for (auto collisionInfoIter = collisionInfo.begin(); collisionInfoIter != collisionInfo.end();)
static const auto CLEAR = [](CollisionEvents& container)
{
if (collisionInfoIter->GetCollisionState() == SHCollisionEvent::State::EXIT
|| collisionInfoIter->GetCollisionState() == SHCollisionEvent::State::INVALID)
for (auto eventIter = container.begin(); eventIter != container.end();)
{
collisionInfoIter = collisionInfo.erase(collisionInfoIter);
}
else
{
++collisionInfoIter;
}
}
const bool CLEAR_EVENT = eventIter->GetCollisionState() == SHCollisionEvent::State::EXIT
|| eventIter->GetCollisionState() == SHCollisionEvent::State::INVALID;
for (auto triggerInfoIter = triggerInfo.begin(); triggerInfoIter != triggerInfo.end();)
{
if (triggerInfoIter->GetCollisionState() == SHCollisionEvent::State::EXIT
|| triggerInfoIter->GetCollisionState() == SHCollisionEvent::State::INVALID)
{
triggerInfoIter = triggerInfo.erase(triggerInfoIter);
if (CLEAR_EVENT)
eventIter = container.erase(eventIter);
else
++eventIter;
}
else
{
++triggerInfoIter;
}
}
}
SHCollisionEvent SHPhysicsSystem::GenerateCollisionEvent(const rp3d::CollisionCallback::ContactPair& cp) noexcept
{
static const auto MATCH_COLLIDER = [](const SHPhysicsObject& physicsObject, const rp3d::Entity colliderID)->uint32_t
{
for (uint32_t i = 0; i < physicsObject.rp3dBody->getNbColliders(); ++i)
{
const auto* collider = physicsObject.rp3dBody->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
};
SHCollisionEvent cInfo;
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : map)
{
// Match body 1
if (matched[SHCollisionEvent::ENTITY_A] == false && physicsObject.rp3dBody->getEntity() == body1)
{
cInfo.ids[SHCollisionEvent::ENTITY_A] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_A] = MATCH_COLLIDER(physicsObject, collider1);
matched[SHCollisionEvent::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionEvent::ENTITY_B] == false && physicsObject.rp3dBody->getEntity() == body2)
{
cInfo.ids[SHCollisionEvent::ENTITY_B] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_B] = MATCH_COLLIDER(physicsObject, collider2);
matched[SHCollisionEvent::ENTITY_B] = true;
}
if (matched[SHCollisionEvent::ENTITY_A] == true && matched[SHCollisionEvent::ENTITY_B] == true)
return cInfo;
}
return cInfo;
CLEAR(collisionInfo);
CLEAR(triggerInfo);
}
SHCollisionEvent SHPhysicsSystem::GenerateCollisionEvent(const rp3d::OverlapCallback::OverlapPair& cp) noexcept
{
static const auto MATCH_COLLIDER = [](const SHPhysicsObject& physicsObject, const rp3d::Entity colliderID)->uint32_t
{
for (uint32_t i = 0; i < physicsObject.rp3dBody->getNbColliders(); ++i)
{
const auto* collider = physicsObject.rp3dBody->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
};
SHCollisionEvent cInfo;
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : map)
{
// Match body 1
if (matched[SHCollisionEvent::ENTITY_A] == false && physicsObject.rp3dBody->getEntity() == body1)
{
cInfo.ids[SHCollisionEvent::ENTITY_A] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_A] = MATCH_COLLIDER(physicsObject, collider1);
matched[SHCollisionEvent::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionEvent::ENTITY_B] == false && physicsObject.rp3dBody->getEntity() == body2)
{
cInfo.ids[SHCollisionEvent::ENTITY_B] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_B] = MATCH_COLLIDER(physicsObject, collider2);
matched[SHCollisionEvent::ENTITY_B] = true;
}
if (matched[SHCollisionEvent::ENTITY_A] == true && matched[SHCollisionEvent::ENTITY_B] == true)
return cInfo;
}
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
return cInfo;
}
SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
@ -728,6 +609,9 @@ namespace SHADE
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = GetPhysicsObject(ENTITY_ID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
if (REMOVED_ID == RIGID_BODY_ID)
@ -735,7 +619,6 @@ namespace SHADE
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
physicsObject->rp3dBody = nullptr;
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (colliderComponent != nullptr)
{
// Preserve colliders as a collision body
@ -766,6 +649,10 @@ namespace SHADE
auto* collider = physicsObject->rp3dBody->getCollider(i);
physicsObject->rp3dBody->removeCollider(collider);
}
// Check for a rigidbody component
if (rigidBodyComponent == nullptr)
physicsObject->rp3dBody = nullptr;
}
if (physicsObject->rp3dBody == nullptr)

View File

@ -28,6 +28,12 @@
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Concepts */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
@ -176,22 +182,24 @@ namespace SHADE
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
void DestroyPhysicsObject (EntityID entityID) noexcept;
void SyncActiveStates (SHPhysicsObject* physicsObject, bool componentActive) noexcept;
static void SyncActiveStates (SHPhysicsObject& physicsObject, bool componentActive) noexcept;
void SyncTransforms () noexcept;
void ClearInvalidCollisions () noexcept;
SHCollisionEvent GenerateCollisionEvent (const rp3d::CollisionCallback::ContactPair& cp) noexcept;
SHCollisionEvent GenerateCollisionEvent (const rp3d::OverlapCallback::OverlapPair& cp) noexcept;
static void UpdateEventContainers (const SHCollisionEvent& collisionEvent, CollisionEvents& container) noexcept;
void ClearInvalidCollisions () noexcept;
SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent);
SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent);
template <typename RP3DCollisionPair, typename = std::enable_if_t
<std::is_same_v<RP3DCollisionPair, rp3d::CollisionCallback::ContactPair>
|| std::is_same_v<RP3DCollisionPair, rp3d::OverlapCallback::OverlapPair>>>
SHCollisionEvent GenerateCollisionEvent (const RP3DCollisionPair& cp) noexcept;
};
} // namespace SHADE
#include "SHPhysicsSystem.hpp"

View File

@ -0,0 +1,84 @@
/****************************************************************************************
* \file SHPhysicsSystem.hpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for templated functions the Physics System
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <type_traits>
// Primary Header
#include "SHPhysicsSystem.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
template <typename RP3DCollisionPair, typename Condition>
SHCollisionEvent SHPhysicsSystem::GenerateCollisionEvent(const RP3DCollisionPair& cp) noexcept
{
static const auto MATCH_COLLIDER = []
(
const SHPhysicsObject& physicsObject
, const rp3d::Entity colliderID
)->uint32_t
{
for (uint32_t i = 0; i < physicsObject.rp3dBody->getNbColliders(); ++i)
{
const auto* collider = physicsObject.rp3dBody->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
};
SHCollisionEvent cInfo;
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : map)
{
// Match body 1
if (matched[SHCollisionEvent::ENTITY_A] == false && physicsObject.rp3dBody->getEntity() == body1)
{
cInfo.ids[SHCollisionEvent::ENTITY_A] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_A] = MATCH_COLLIDER(physicsObject, collider1);
matched[SHCollisionEvent::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionEvent::ENTITY_B] == false && physicsObject.rp3dBody->getEntity() == body2)
{
cInfo.ids[SHCollisionEvent::ENTITY_B] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_B] = MATCH_COLLIDER(physicsObject, collider2);
matched[SHCollisionEvent::ENTITY_B] = true;
}
if (matched[SHCollisionEvent::ENTITY_A] == true && matched[SHCollisionEvent::ENTITY_B] == true)
return cInfo;
}
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
return cInfo;
}
} // namespace SHADE