Initial work on CGroundMovement

This commit is contained in:
Jack Andersen 2017-06-18 21:00:50 -10:00
parent c854a45dfe
commit d4a97861dc
15 changed files with 993 additions and 53 deletions

View File

@ -1499,27 +1499,27 @@ bool CStateManager::TestRayDamage(const zeus::CVector3f& pos, const CActor& dama
return CGameCollision::RayDynamicIntersectionBool(*this, pos, dir, filter, nearList, &damagee, depth * origMag);
}
bool CStateManager::RayCollideWorld(const zeus::CVector3f& pos, const zeus::CVector3f& damageeCenter,
bool CStateManager::RayCollideWorld(const zeus::CVector3f& start, const zeus::CVector3f& end,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
const CMaterialFilter& filter, const CActor& damagee)
{
return RayCollideWorldInternal(pos, damageeCenter, filter, nearList, &damagee);
return RayCollideWorldInternal(start, end, filter, nearList, &damagee);
}
bool CStateManager::RayCollideWorldInternal(const zeus::CVector3f& pos, const zeus::CVector3f& damageeCenter,
bool CStateManager::RayCollideWorldInternal(const zeus::CVector3f& start, const zeus::CVector3f& end,
const CMaterialFilter& filter,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
const CActor* damagee)
{
zeus::CVector3f vecToDamagee = damageeCenter - pos;
if (!vecToDamagee.canBeNormalized())
zeus::CVector3f delta = end - start;
if (!delta.canBeNormalized())
return true;
float mag = vecToDamagee.magnitude();
zeus::CVector3f dir = vecToDamagee * (1.f / mag);
if (!CGameCollision::RayStaticIntersectionBool(*this, pos, dir, mag, filter))
float mag = delta.magnitude();
zeus::CVector3f dir = delta * (1.f / mag);
if (!CGameCollision::RayStaticIntersectionBool(*this, start, dir, mag, filter))
return false;
return CGameCollision::RayDynamicIntersectionBool(*this, pos, dir, filter, nearList, damagee, mag);
return CGameCollision::RayDynamicIntersectionBool(*this, start, dir, filter, nearList, damagee, mag);
}
bool CStateManager::MultiRayCollideWorld(const zeus::CMRay& ray, const CMaterialFilter& filter)

View File

@ -332,10 +332,10 @@ public:
const CDamageInfo& info);
bool TestRayDamage(const zeus::CVector3f& pos, const CActor& damagee,
const rstl::reserved_vector<TUniqueId, 1024>& nearList);
bool RayCollideWorld(const zeus::CVector3f& pos, const zeus::CVector3f& damageeCenter,
bool RayCollideWorld(const zeus::CVector3f& start, const zeus::CVector3f& end,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
const CMaterialFilter& filter, const CActor& damagee);
bool RayCollideWorldInternal(const zeus::CVector3f& pos, const zeus::CVector3f& damageeCenter,
bool RayCollideWorldInternal(const zeus::CVector3f& start, const zeus::CVector3f& end,
const CMaterialFilter& filter,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
const CActor* damagee);

View File

@ -0,0 +1,619 @@
#include "CGroundMovement.hpp"
#include "World/CPhysicsActor.hpp"
#include "Collision/CGameCollision.hpp"
#include "Collision/CCollisionInfoList.hpp"
#include "Collision/CollisionUtil.hpp"
#include "Collision/CAABoxFilter.hpp"
#include "CStateManager.hpp"
#include "TCastTo.hpp"
#include "World/CScriptPlatform.hpp"
#include "World/CWorld.hpp"
#include "World/CPlayer.hpp"
namespace urde
{
void CGroundMovement::CheckFalling(CPhysicsActor& actor, CStateManager& mgr, float)
{
bool oob = true;
for (const CGameArea& area : *mgr.GetWorld())
{
if (area.GetAABB().intersects(*actor.GetTouchBounds()))
{
oob = false;
break;
}
}
if (!oob)
{
mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::Falling);
}
else
{
mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::OnFloor);
actor.SetAngularVelocityWR(actor.GetAngularVelocityWR() * 0.98f);
zeus::CVector3f vel = actor.GetTransform().transposeRotate(actor.GetVelocity());
vel.z = 0.f;
actor.SetVelocityOR(vel);
actor.SetMomentumWR(zeus::CVector3f::skZero);
}
}
void CGroundMovement::MoveGroundCollider(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* nearList)
{
CMotionState oldState = actor.GetMotionState();
CMotionState newState = actor.PredictMotion_Internal(dt);
float deltaMag = newState.x0_translation.magnitude();
TUniqueId idDetect = kInvalidUniqueId;
CCollisionInfoList collisionList;
zeus::CAABox motionVol = actor.GetMotionVolume(dt);
rstl::reserved_vector<TUniqueId, 1024> useColliderList;
if (nearList)
useColliderList = *nearList;
mgr.BuildColliderList(useColliderList, actor, motionVol);
CAreaCollisionCache cache(motionVol);
float collideDt = dt;
if (actor.GetCollisionPrimitive()->GetPrimType() == FOURCC('OBTG'))
{
CGameCollision::BuildAreaCollisionCache(mgr, cache);
if (deltaMag > 0.5f * CGameCollision::GetMinExtentForCollisionPrimitive(*actor.GetCollisionPrimitive()))
{
zeus::CVector3f point =
actor.GetCollisionPrimitive()->CalculateAABox(actor.GetPrimitiveTransform()).center();
TUniqueId intersectId = kInvalidUniqueId;
CMaterialFilter filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid});
CRayCastResult result =
mgr.RayWorldIntersection(intersectId, point, newState.x0_translation.normalized(), deltaMag,
filter, useColliderList);
if (result.IsValid())
{
collideDt = dt * (result.GetT() / deltaMag);
newState = actor.PredictMotion_Internal(collideDt);
}
actor.MoveCollisionPrimitive(newState.x0_translation);
if (CGameCollision::DetectCollision_Cached(mgr, cache, *actor.GetCollisionPrimitive(),
actor.GetPrimitiveTransform(), actor.GetMaterialFilter(),
useColliderList, idDetect, collisionList))
{
actor.AddMotionState(newState);
float resolved = 0.f;
if (ResolveUpDown(cache, mgr, actor, actor.GetMaterialFilter(), useColliderList,
actor.GetStepUpHeight(), 0.f, resolved, collisionList))
{
actor.SetMotionState(oldState);
MoveGroundColliderXY(cache, mgr, actor, actor.GetMaterialFilter(), useColliderList, collideDt);
}
}
else
{
actor.AddMotionState(newState);
}
float stepDown = actor.GetStepDownHeight();
float resolved = 0.f;
collisionList.Clear();
TUniqueId stepZId = kInvalidUniqueId;
if (stepDown >= 0.f)
{
if (MoveGroundColliderZ(cache, mgr, actor, actor.GetMaterialFilter(), useColliderList,
-stepDown, resolved, collisionList, stepZId))
{
if (collisionList.GetCount() > 0)
{
CCollisionInfoList filteredList;
CollisionUtil::FilterByClosestNormal(zeus::CVector3f{0.f, 0.f, 1.f}, collisionList, filteredList);
if (filteredList.GetCount() > 0)
{
if (CGameCollision::IsFloor(filteredList.Front().GetMaterialLeft(),
filteredList.Front().GetNormalLeft()))
{
if (TCastToPtr<CScriptPlatform> plat = mgr.ObjectById(stepZId))
mgr.SendScriptMsg(plat.GetPtr(), actor.GetUniqueId(),
EScriptObjectMessage::AddPlatformRider);
CGameCollision::SendMaterialMessage(mgr, filteredList.Front().GetMaterialLeft(), actor);
mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::OnFloor);
}
else
{
CheckFalling(actor, mgr, dt);
}
}
}
}
}
else
{
CheckFalling(actor, mgr, dt);
}
actor.ClearForcesAndTorques();
actor.MoveCollisionPrimitive(zeus::CVector3f::skZero);
if (actor.GetMaterialList().HasMaterial(EMaterialTypes::Player))
{
CGameCollision::CollisionFailsafe(mgr, cache, actor, *actor.GetCollisionPrimitive(),
useColliderList, 0.f, 1);
}
}
}
}
bool CGroundMovement::ResolveUpDown(CAreaCollisionCache& cache, CStateManager& mgr, CPhysicsActor& actor,
const CMaterialFilter& filter, rstl::reserved_vector<TUniqueId, 1024>& nearList,
float stepUp, float stepDown, float& fOut, CCollisionInfoList& list)
{
float zextent = stepDown;
if (list.GetCount() <= 0)
return true;
zeus::CAABox aabb = zeus::CAABox::skInvertedBox;
zeus::CVector3f normAccum = zeus::CVector3f::skZero;
for (CCollisionInfo& info : list)
{
if (CGameCollision::IsFloor(info.GetMaterialLeft(), info.GetNormalLeft()))
{
aabb.accumulateBounds(info.GetPoint());
aabb.accumulateBounds(info.GetExtreme());
normAccum += info.GetNormalLeft();
}
}
if (normAccum.canBeNormalized())
normAccum.normalize();
else
return true;
zeus::CAABox actorAABB = actor.GetBoundingBox();
if (normAccum.z >= 0.f)
{
zextent = aabb.max.z - actorAABB.min.z + 0.02f;
if (zextent > stepUp)
return true;
}
else
{
zextent = aabb.min.z - actorAABB.max.z - 0.02f;
if (zextent < -stepDown)
return true;
}
actor.MoveCollisionPrimitive({0.f, 0.f, zextent});
if (!CGameCollision::DetectCollisionBoolean_Cached(mgr, cache, *actor.GetCollisionPrimitive(),
actor.GetPrimitiveTransform(), filter, nearList))
{
fOut = zextent;
actor.SetTranslation(actor.GetTranslation() + zeus::CVector3f(0.f, 0.f, zextent));
actor.MoveCollisionPrimitive(zeus::CVector3f::skZero);
bool floor = false;
for (CCollisionInfo& info : list)
{
if (CGameCollision::IsFloor(info.GetMaterialLeft(), info.GetNormalLeft()))
{
floor = true;
break;
}
}
if (!floor)
mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::LandOnNotFloor);
return false;
}
return true;
}
bool CGroundMovement::MoveGroundColliderZ(CAreaCollisionCache& cache, CStateManager& mgr, CPhysicsActor& actor,
const CMaterialFilter& filter, rstl::reserved_vector<TUniqueId, 1024>& nearList,
float amt, float&, CCollisionInfoList& list, TUniqueId& idOut)
{
actor.MoveCollisionPrimitive({0.f, 0.f, amt});
zeus::CAABox aabb = zeus::CAABox::skInvertedBox;
if (CGameCollision::DetectCollision_Cached(mgr, cache, *actor.GetCollisionPrimitive(),
actor.GetPrimitiveTransform(), filter, nearList, idOut, list))
{
for (CCollisionInfo& info : list)
{
aabb.accumulateBounds(info.GetPoint());
aabb.accumulateBounds(info.GetExtreme());
}
zeus::CAABox actorAABB = actor.GetBoundingBox();
float zextent;
if (amt > 0.f)
zextent = aabb.min.z - actorAABB.max.z - 0.02f + amt;
else
zextent = aabb.max.z - actorAABB.min.z + 0.02f + amt;
actor.MoveCollisionPrimitive({0.f, 0.f, zextent});
if (!CGameCollision::DetectCollisionBoolean_Cached(mgr, cache, *actor.GetCollisionPrimitive(),
actor.GetPrimitiveTransform(), filter, nearList))
{
actor.SetTranslation(actor.GetTranslation() + zeus::CVector3f(0.f, 0.f, zextent));
actor.MoveCollisionPrimitive(zeus::CVector3f::skZero);
}
bool floor = false;
for (CCollisionInfo& info : list)
{
if (CGameCollision::IsFloor(info.GetMaterialLeft(), info.GetNormalLeft()))
{
floor = true;
break;
}
}
if (!floor)
mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::LandOnNotFloor);
CCollisionInfoList filteredList;
if (amt > 0.f)
CollisionUtil::FilterByClosestNormal({0.f, 0.f, -1.f}, list, filteredList);
else
CollisionUtil::FilterByClosestNormal({0.f, 0.f, 1.f}, list, filteredList);
if (filteredList.GetCount() > 0)
CGameCollision::MakeCollisionCallbacks(mgr, actor, idOut, filteredList);
return true;
}
return false;
}
void CGroundMovement::MoveGroundColliderXY(CAreaCollisionCache& cache, CStateManager& mgr, CPhysicsActor& actor,
const CMaterialFilter& filter, rstl::reserved_vector<TUniqueId, 1024>& nearList,
float dt)
{
bool didCollide = false;
bool isPlayer = actor.GetMaterialList().HasMaterial(EMaterialTypes::Player);
float remDt = dt;
float originalDt = dt;
TCastToPtr<CPhysicsActor> otherActor;
CCollisionInfoList collisionList;
CMotionState newMState = actor.PredictMotion_Internal(dt);
float transMag = newMState.x0_translation.magnitude();
float divMag;
if (isPlayer)
divMag = std::max(transMag / 5.f, 0.005f);
else
divMag = std::max(transMag / 3.f, 0.02f);
float minExtent = 0.5f * CGameCollision::GetMinExtentForCollisionPrimitive(*actor.GetCollisionPrimitive());
if (transMag > minExtent)
{
dt = minExtent * (dt / transMag);
originalDt = dt;
newMState = actor.PredictMotion_Internal(dt);
divMag = std::min(divMag, minExtent);
}
float nonCollideDt = dt;
do
{
actor.MoveCollisionPrimitive(newMState.x0_translation);
collisionList.Clear();
TUniqueId otherId = kInvalidUniqueId;
bool collided = CGameCollision::DetectCollision_Cached(mgr, cache, *actor.GetCollisionPrimitive(),
actor.GetPrimitiveTransform(), filter, nearList,
otherId, collisionList);
if (collided)
otherActor = mgr.ObjectById(otherId);
actor.MoveCollisionPrimitive(zeus::CVector3f::skZero);
if (collided)
{
didCollide = true;
if (newMState.x0_translation.magnitude() < divMag)
{
CCollisionInfoList backfaceFilteredList, floorFilteredList;
zeus::CVector3f deltaVel = actor.GetVelocity();
if (otherActor)
deltaVel -= otherActor->GetVelocity();
CollisionUtil::FilterOutBackfaces(deltaVel, collisionList, backfaceFilteredList);
CAABoxFilter::FilterBoxFloorCollisions(backfaceFilteredList, floorFilteredList);
CGameCollision::MakeCollisionCallbacks(mgr, actor, otherId, floorFilteredList);
if (floorFilteredList.GetCount() == 0 && isPlayer)
{
CMotionState lastNonCollideState = actor.GetLastNonCollidingState();
lastNonCollideState.x1c_velocity *= 0.5f;
lastNonCollideState.x28_angularMomentum *= 0.5f;
actor.SetMotionState(lastNonCollideState);
}
for (const CCollisionInfo& info : floorFilteredList)
{
CCollisionInfo infoCopy = info;
float restitution = CGameCollision::GetCoefficientOfRestitution(infoCopy) +
actor.GetCoefficientOfRestitutionModifier();
if (otherActor)
CGameCollision::CollideWithDynamicBodyNoRot(actor, *otherActor, infoCopy, restitution, true);
else
CGameCollision::CollideWithStaticBodyNoRot(actor, infoCopy.GetMaterialLeft(), infoCopy.GetMaterialRight(),
infoCopy.GetNormalLeft(), restitution, true);
}
remDt -= dt;
nonCollideDt = std::min(originalDt, remDt);
dt = nonCollideDt;
}
else
{
nonCollideDt *= 0.5f;
dt *= 0.5f;
}
}
else
{
actor.AddMotionState(newMState);
remDt -= dt;
dt = nonCollideDt;
actor.MoveCollisionPrimitive(zeus::CVector3f::skZero);
}
newMState = actor.PredictMotion_Internal(dt);
} while (remDt > 0.f);
if (!didCollide && !actor.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider))
mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::Falling);
actor.MoveCollisionPrimitive(zeus::CVector3f::skZero);
}
void CGroundMovement::CollisionDamping(const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&,
float, float)
{
}
void CGroundMovement::MoveGroundCollider_New(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* nearList)
{
zeus::CAABox motionVol = actor.GetMotionVolume(dt);
rstl::reserved_vector<TUniqueId, 1024> useNearList;
if (nearList)
useNearList = *nearList;
else
mgr.BuildColliderList(useNearList, actor, motionVol);
CAreaCollisionCache cache(motionVol);
CGameCollision::BuildAreaCollisionCache(mgr, cache);
CPlayer& player = static_cast<CPlayer&>(actor);
player.x9c5_28_slidingOnWall = false;
bool startingJump = player.x258_movementState == CPlayer::EPlayerMovementState::StartingJump;
bool dampUnderwater = false;
if (player.x9c4_31_dampUnderwaterMotion)
{
if (!mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::GravitySuit))
dampUnderwater = true;
}
bool noJump = (player.x258_movementState != CPlayer::EPlayerMovementState::StartingJump &&
player.x258_movementState != CPlayer::EPlayerMovementState::Jump);
float stepDown = player.GetStepDownHeight();
float stepUp = player.GetStepUpHeight();
bool x108 = true;
CMaterialList material(EMaterialTypes::Unknown);
SMoveObjectResult result;
if (!startingJump)
{
SMovementOptions opts;
opts.x0_ = false;
opts.x4_ = 0.f;
opts.x8_ = 0.f;
opts.xc_ = 0.37f;
opts.x10_ = 0.25f;
opts.x14_ = 0.f;
opts.x18_ = true;
opts.x19_ = false;
opts.x1a_ = noJump;
opts.x1c_ = 4;
opts.x20_ = 0.002f;
opts.x24_ = 0.f;
opts.x28_ = 1.f;
opts.x2c_ = 0.f;
opts.x30_ = 0.02f;
opts.x3c_ = player.GetLastFloorPlaneNormal();
opts.x34_ = 0.2f;
opts.x38_ = player.GetMaximumPlayerPositiveVerticalVelocity(mgr);
if (noJump)
{
zeus::CVector3f vel = player.GetVelocity();
vel.z = 0.f;
actor.SetVelocityWR(vel);
actor.x15c_force.z = 0.f;
actor.x150_momentum.z = 0.f;
actor.x168_impulse.z = 0.f;
}
CPhysicsState physStatePre = actor.GetPhysicsState();
CMaterialList material = MoveObjectAnalytical(mgr, actor, dt, useNearList, cache, opts, result);
CPhysicsState physStatePost = actor.GetPhysicsState();
if (material.XOR({EMaterialTypes::Unknown}))
{
SMovementOptions optsCopy = opts;
zeus::CVector3f postToPre = physStatePre.GetTranslation() - physStatePost.GetTranslation();
float f27 = postToPre.magSquared();
optsCopy.x19_ = noJump;
float quarterStepUp = 0.25f * stepUp;
rstl::reserved_vector<CPhysicsState, 2> physStateList;
rstl::reserved_vector<float, 2> floatList;
rstl::reserved_vector<CCollisionInfo, 2> collisionInfoList;
rstl::reserved_vector<TUniqueId, 2> uniqueIdList;
rstl::reserved_vector<CMaterialList, 2> materialListList;
bool done = false;
for (int i=0 ; i < 2 && !done ; ++i)
{
double useStepUp = (i == 0) ? quarterStepUp : stepUp;
actor.SetPhysicsState(physStatePre);
CCollisionInfo collisionInfo;
TUniqueId id = kInvalidUniqueId;
CGameCollision::DetectCollision_Cached_Moving(mgr, cache, *actor.GetCollisionPrimitive(),
actor.GetTransform(), actor.GetMaterialFilter(),
useNearList, {0.f, 0.f, 1.f}, id, collisionInfo,
useStepUp);
if (collisionInfo.IsValid())
{
useStepUp = std::max(0.0, useStepUp - optsCopy.x20_);
done = true;
}
if (useStepUp > 0.0005)
{
actor.SetTranslation(actor.GetTranslation() + zeus::CVector3f(0.f, 0.f, useStepUp));
SMoveObjectResult result;
CMaterialList material = MoveObjectAnalytical(mgr, actor, dt, useNearList, cache, optsCopy, result);
CCollisionInfo collisionInfo;
double useStepDown = useStepUp + stepDown;
TUniqueId id = kInvalidUniqueId;
if (useStepDown > 0.0)
{
CGameCollision::DetectCollision_Cached_Moving(mgr, cache, *actor.GetCollisionPrimitive(),
actor.GetTransform(), actor.GetMaterialFilter(),
useNearList, {0.f, 0.f, -1.f}, id, collisionInfo,
useStepDown);
}
else
{
useStepDown = 0.0;
}
float minStep = std::min(useStepUp, useStepDown);
zeus::CVector3f offsetStep = actor.GetTranslation() - zeus::CVector3f(0.f, 0.f, minStep);
bool canBlock = (collisionInfo.IsValid() &&
CGameCollision::CanBlock(collisionInfo.GetMaterialLeft(), collisionInfo.GetNormalLeft()));
zeus::CVector3f postToPre = physStatePre.GetTranslation() - offsetStep;
float f26 = postToPre.magSquared();
if (canBlock && f27 < f26)
{
useStepDown = std::max(0.0, useStepDown - 0.0005);
actor.SetTranslation(actor.GetTranslation() - zeus::CVector3f(0.f, 0.f, useStepDown));
physStateList.push_back(actor.GetPhysicsState());
floatList.push_back(f26);
collisionInfoList.push_back(collisionInfo);
uniqueIdList.push_back(id);
materialListList.push_back(material);
}
}
}
if (physStateList.size() == 0)
{
actor.SetPhysicsState(physStatePost);
}
else
{
float maxFloat = -1.0e10f;
int maxIdx = -1;
for (int i=0 ; i<physStateList.size() ; ++i)
{
if (maxFloat < floatList[i])
{
maxFloat = floatList[i];
maxIdx = i;
}
}
actor.SetPhysicsState(physStateList[maxIdx]);
mgr.SendScriptMsg(&actor, kInvalidUniqueId, EScriptObjectMessage::OnFloor);
if (CEntity* ent = mgr.ObjectById(uniqueIdList[maxIdx]))
{
result.x0_id.emplace(uniqueIdList[maxIdx]);
result.x8_collision.emplace(collisionInfoList[maxIdx]);
if (TCastToPtr<CScriptPlatform> plat = ent)
mgr.SendScriptMsg(ent, actor.GetUniqueId(), EScriptObjectMessage::AddPlatformRider);
}
CCollisionInfo& cInfo = collisionInfoList[maxIdx];
CGameCollision::SendMaterialMessage(mgr, cInfo.GetMaterialLeft(), actor);
x108 = false;
actor.SetLastFloorPlaneNormal({cInfo.GetNormalLeft()});
}
}
}
else
{
SMovementOptions opts;
opts.x0_ = true;
opts.x4_ = dampUnderwater ? 35.f : 1.f;
opts.x8_ = dampUnderwater ? 5.f : 0.f;
opts.xc_ = dampUnderwater ? 0.05f : 0.37f;
opts.x10_ = dampUnderwater ? 0.01f : 0.25f;
opts.x14_ = dampUnderwater ? 0.2f : 0.f;
opts.x18_ = false;
opts.x19_ = false;
opts.x1a_ = false;
opts.x1c_ = 4;
opts.x20_ = 0.002f;
opts.x24_ = 0.f;
opts.x28_ = 1.f;
opts.x2c_ = 0.1f;
opts.x30_ = dampUnderwater ? 0.2f : 0.2f;
opts.x3c_ = player.GetLastFloorPlaneNormal();
opts.x38_ = player.GetMaximumPlayerPositiveVerticalVelocity(mgr);
material = MoveObjectAnalytical(mgr, actor, dt, useNearList, cache, opts, result);
}
if (x108)
{
// TODO: Finish
}
actor.ClearForcesAndTorques();
if (material.HasMaterial(EMaterialTypes::Wall))
player.SetPlayerHitWallDuringMove();
if (result.x0_id)
{
CCollisionInfoList list;
list.Add(*result.x8_collision, false);
CGameCollision::MakeCollisionCallbacks(mgr, actor, *result.x0_id, list);
}
CMotionState mState = actor.GetMotionState();
mState.x0_translation = actor.GetLastNonCollidingState().x0_translation;
mState.x1c_velocity = actor.GetLastNonCollidingState().x1c_velocity;
actor.SetLastNonCollidingState(mState);
const CCollisionPrimitive* prim = actor.GetCollisionPrimitive();
if (prim->GetPrimType() == FOURCC('AABX'))
{
// TODO: Finish
}
else if (prim->GetPrimType() == FOURCC('SPHR'))
{
// TODO: Finish
}
CGameCollision::CollisionFailsafe(mgr, cache, actor, *prim, useNearList, 0.f, 1);
}
void CGroundMovement::RemoveNormalComponent(const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&, float&)
{
}
void CGroundMovement::RemoveNormalComponent(const zeus::CVector3f&, const zeus::CVector3f&)
{
}
CMaterialList CGroundMovement::MoveObjectAnalytical(CStateManager& mgr, CPhysicsActor& actor, float,
rstl::reserved_vector<TUniqueId, 1024>& nearList,
CAreaCollisionCache& cache, const SMovementOptions& opts,
SMoveObjectResult& result)
{
return {};
}
}

View File

@ -0,0 +1,74 @@
#ifndef __URDE_CGROUNDMOVEMENT_HPP__
#define __URDE_CGROUNDMOVEMENT_HPP__
#include "RetroTypes.hpp"
#include "Collision/CCollisionInfo.hpp"
namespace urde
{
class CPhysicsActor;
class CStateManager;
class CAreaCollisionCache;
class CMaterialFilter;
class CCollisionInfoList;
class CGroundMovement
{
public:
struct SMovementOptions
{
bool x0_;
float x4_;
float x8_;
float xc_;
float x10_;
float x14_;
bool x18_;
bool x19_;
bool x1a_;
u32 x1c_;
float x20_;
float x24_;
float x28_;
float x2c_;
float x30_;
float x34_;
float x38_;
std::experimental::optional<zeus::CVector3f> x3c_;
};
struct SMoveObjectResult
{
std::experimental::optional<TUniqueId> x0_id;
std::experimental::optional<CCollisionInfo> x8_collision;
u32 x6c_;
float x70_;
};
static void CheckFalling(CPhysicsActor& actor, CStateManager& mgr, float);
static void MoveGroundCollider(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* nearList);
static bool ResolveUpDown(CAreaCollisionCache& cache, CStateManager& mgr, CPhysicsActor& actor,
const CMaterialFilter& filter, rstl::reserved_vector<TUniqueId, 1024>& nearList,
float, float, float&, CCollisionInfoList& list);
static bool MoveGroundColliderZ(CAreaCollisionCache& cache, CStateManager& mgr, CPhysicsActor& actor,
const CMaterialFilter& filter, rstl::reserved_vector<TUniqueId, 1024>& nearList,
float, float&, CCollisionInfoList& list, TUniqueId& idOut);
static void MoveGroundColliderXY(CAreaCollisionCache& cache, CStateManager& mgr, CPhysicsActor& actor,
const CMaterialFilter& filter, rstl::reserved_vector<TUniqueId, 1024>& nearList,
float);
static void CollisionDamping(const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&,
float, float);
static void MoveGroundCollider_New(CStateManager& mgr, CPhysicsActor& actor, float,
const rstl::reserved_vector<TUniqueId, 1024>* nearList);
static void RemoveNormalComponent(const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&, float&);
static void RemoveNormalComponent(const zeus::CVector3f&, const zeus::CVector3f&);
static CMaterialList MoveObjectAnalytical(CStateManager& mgr, CPhysicsActor& actor, float,
rstl::reserved_vector<TUniqueId, 1024>& nearList,
CAreaCollisionCache& cache, const SMovementOptions& opts,
SMoveObjectResult& result);
};
}
#endif // __URDE_CGROUNDMOVEMENT_HPP__

View File

@ -88,6 +88,7 @@ set(CHARACTER_SOURCES
CAnimSysContext.hpp
CBodyState.hpp CBodyState.cpp
CBodyStateCmdMgr.hpp CBodyStateCmdMgr.cpp
CBodyController.hpp CBodyController.cpp)
CBodyController.hpp CBodyController.cpp
CGroundMovement.hpp CGroundMovement.cpp)
runtime_add_list(Character CHARACTER_SOURCES)

View File

@ -28,6 +28,8 @@ public:
x0_list.push_back(info.GetSwapped());
}
void Clear() { x0_list.clear(); }
const CCollisionInfo& Front() const { return x0_list.front(); }
const CCollisionInfo& GetItem(int i) const { return x0_list[i]; }
rstl::reserved_vector<CCollisionInfo, 32>::iterator end() { return x0_list.end(); }
rstl::reserved_vector<CCollisionInfo, 32>::const_iterator end() const { return x0_list.end(); }
rstl::reserved_vector<CCollisionInfo, 32>::iterator begin() { return x0_list.begin(); }

View File

@ -12,6 +12,7 @@
#include "CollisionUtil.hpp"
#include "World/CScriptPlatform.hpp"
#include "CCollidableSphere.hpp"
#include "Character/CGroundMovement.hpp"
namespace urde
{
@ -21,9 +22,9 @@ static float CollisionImpulseFiniteVsInfinite(float mass, float velNormDot, floa
return mass * ((1.f / restitution) * velNormDot);
}
static float CollisionImpulseFiniteVsFinite(float mass, float velNormDot, float restitution, float f4)
static float CollisionImpulseFiniteVsFinite(float mass0, float mass1, float velNormDot, float restitution)
{
return (-(1.f + f4) * restitution) / ((1.f / mass) + (1.f / velNormDot));
return (-(1.f + restitution) * velNormDot) / ((1.f / mass0) + (1.f / mass1));
}
void CGameCollision::InitCollision()
@ -68,36 +69,13 @@ void CGameCollision::MovePlayer(CStateManager& mgr, CPhysicsActor& actor, float
else
{
if (actor.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider))
MoveGroundCollider_New(mgr, actor, dt, colliderList);
CGroundMovement::MoveGroundCollider_New(mgr, actor, dt, colliderList);
else
MoveAndCollide(mgr, actor, dt, CBallFilter(actor), colliderList);
}
actor.SetAngularEnabled(false);
}
void CGameCollision::MoveGroundCollider(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* colliderList)
{
CMotionState oldState = actor.GetMotionState();
CMotionState newState = actor.PredictMotion_Internal(dt);
newState.x0_translation.magnitude();
actor.GetMaterialFilter();
zeus::CAABox motionVol = actor.GetMotionVolume(dt);
rstl::reserved_vector<TUniqueId, 1024> augmentedColliderList;
if (colliderList)
augmentedColliderList = *colliderList;
mgr.BuildColliderList(augmentedColliderList, actor, motionVol);
CAreaCollisionCache cache(motionVol);
actor.GetCollisionPrimitive()->GetPrimType();
// TODO: finish
}
void CGameCollision::MoveGroundCollider_New(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* colliderList)
{
// TODO: finish
}
void CGameCollision::MoveAndCollide(CStateManager& mgr, CPhysicsActor& actor, float dt, const ICollisionFilter& filter,
const rstl::reserved_vector<TUniqueId, 1024>* colliderList)
{
@ -246,7 +224,7 @@ void CGameCollision::Move(CStateManager& mgr, CPhysicsActor& actor, float dt,
if (actor.GetMaterialList().HasMaterial(EMaterialTypes::Player))
MovePlayer(mgr, actor, dt, colliderList);
else if (actor.GetMaterialList().HasMaterial(EMaterialTypes::GroundCollider))
MoveGroundCollider(mgr, actor, dt, colliderList);
CGroundMovement::MoveGroundCollider(mgr, actor, dt, colliderList);
else
MoveAndCollide(mgr, actor, dt, CAABoxFilter(actor), colliderList);
}
@ -587,6 +565,17 @@ bool CGameCollision::DetectCollision_Cached(CStateManager& mgr, CAreaCollisionCa
return ret;
}
bool CGameCollision::DetectCollision_Cached_Moving(CStateManager& mgr, CAreaCollisionCache& cache,
const CCollisionPrimitive& prim, const zeus::CTransform& xf,
const CMaterialFilter& filter,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
const zeus::CVector3f& vec,
TUniqueId& idOut, CCollisionInfo& infoOut, double&)
{
// TODO: Finish
return false;
}
bool CGameCollision::DetectStaticCollision(CStateManager& mgr, const CCollisionPrimitive& prim,
const zeus::CTransform& xf, const CMaterialFilter& filter,
CCollisionInfoList& list)
@ -777,16 +766,80 @@ void CGameCollision::ResolveCollisions(CPhysicsActor& a0, CPhysicsActor* a1, con
}
void CGameCollision::CollideWithDynamicBodyNoRot(CPhysicsActor& a0, CPhysicsActor& a1,
const CCollisionInfo& info, float restitution, bool)
const CCollisionInfo& info, float restitution, bool zeroZ)
{
/* TODO: Finish */
zeus::CVector3f normal = info.GetNormalLeft();
if (zeroZ)
normal.z = 0.f;
zeus::CVector3f relVel = GetActorRelativeVelocities(a0, &a1);
float velNormDot = relVel.dot(normal);
float a0MaxCollisionVel = std::max(a0.GetVelocity().magnitude(), a0.GetMaximumCollisionVelocity());
float a1MaxCollisionVel = std::max(a1.GetVelocity().magnitude(), a1.GetMaximumCollisionVelocity());
bool a0Move = !a0.GetMaterialList().HasMaterial(EMaterialTypes::Immovable) && a0.GetMass() != 0.f;
bool a1Move = !a1.GetMaterialList().HasMaterial(EMaterialTypes::Immovable) && a1.GetMass() != 0.f;
if (velNormDot < -0.0001f)
{
if (a0Move)
{
if (a1Move)
{
float impulse = CollisionImpulseFiniteVsFinite(a0.GetMass(), a1.GetMass(), velNormDot, restitution);
a0.ApplyImpulseWR(normal * impulse, zeus::CAxisAngle::sIdentity);
a1.ApplyImpulseWR(normal * -impulse, zeus::CAxisAngle::sIdentity);
}
else
{
float impulse = CollisionImpulseFiniteVsInfinite(a0.GetMass(), velNormDot, restitution);
a0.ApplyImpulseWR(normal * impulse, zeus::CAxisAngle::sIdentity);
}
}
else
{
if (a1Move)
{
float impulse = CollisionImpulseFiniteVsInfinite(a1.GetMass(), velNormDot, restitution);
a1.ApplyImpulseWR(normal * -impulse, zeus::CAxisAngle::sIdentity);
}
else
{
a0.SetVelocityWR(zeus::CVector3f::skZero);
a1.SetVelocityWR(zeus::CVector3f::skZero);
}
}
a0.UseCollisionImpulses();
a1.UseCollisionImpulses();
}
else if (velNormDot < 0.1f)
{
if (a0Move)
{
float impulse = 0.05f * a0.GetMass();
a0.ApplyImpulseWR(normal * impulse, zeus::CAxisAngle::sIdentity);
a0.UseCollisionImpulses();
}
if (a1Move)
{
float impulse = -0.05f * a1.GetMass();
a1.ApplyImpulseWR(normal * impulse, zeus::CAxisAngle::sIdentity);
a1.UseCollisionImpulses();
}
}
if (a0.GetVelocity().magnitude() > a0MaxCollisionVel)
a0.SetVelocityWR(a0.GetVelocity().normalized() * a0MaxCollisionVel);
if (a1.GetVelocity().magnitude() > a1MaxCollisionVel)
a1.SetVelocityWR(a1.GetVelocity().normalized() * a1MaxCollisionVel);
}
void CGameCollision::CollideWithStaticBodyNoRot(CPhysicsActor& a0, const CMaterialList& m0, const CMaterialList& m1,
const zeus::CUnitVector3f& normal, float restitution, bool b)
const zeus::CUnitVector3f& normal, float restitution, bool zeroZ)
{
zeus::CUnitVector3f useNorm = normal;
if (b && m0.HasMaterial(EMaterialTypes::Player) && !m1.HasMaterial(EMaterialTypes::Floor))
if (zeroZ && m0.HasMaterial(EMaterialTypes::Player) && !m1.HasMaterial(EMaterialTypes::Floor))
useNorm.z = 0.f;
if (useNorm.canBeNormalized())
@ -825,7 +878,37 @@ void CGameCollision::CollisionFailsafe(CStateManager& mgr, CAreaCollisionCache&
actor.SetNumTicksStuck(actor.GetNumTicksStuck() + 1);
if (actor.GetNumTicksStuck() < failsafeTicks)
return;
/* TODO: Finish */
CMotionState oldMState = actor.GetMotionState();
CMotionState lastNonCollide = actor.GetLastNonCollidingState();
actor.SetMotionState(lastNonCollide);
if (!DetectCollisionBoolean_Cached(mgr, cache, prim, actor.GetPrimitiveTransform(),
actor.GetMaterialFilter(), nearList))
{
lastNonCollide.x1c_velocity *= 0.5f;
lastNonCollide.x28_angularMomentum *= 0.5f;
actor.SetLastNonCollidingState(lastNonCollide);
//++gDebugPrintCount;
actor.SetNumTicksStuck(0);
}
else
{
actor.SetMotionState(oldMState);
if (auto nonIntersectVec = FindNonIntersectingVector(mgr, cache, actor, prim, nearList))
{
oldMState.x0_translation += *nonIntersectVec;
actor.SetMotionState(oldMState);
actor.SetLastNonCollidingState(actor.GetMotionState());
//++gDebugPrintCount;
}
else
{
//++gDebugPrintCount;
lastNonCollide.x1c_velocity *= 0.5f;
lastNonCollide.x28_angularMomentum *= 0.5f;
actor.SetLastNonCollidingState(lastNonCollide);
}
}
}
else
{
@ -833,4 +916,117 @@ void CGameCollision::CollisionFailsafe(CStateManager& mgr, CAreaCollisionCache&
actor.SetNumTicksStuck(0);
}
}
std::experimental::optional<zeus::CVector3f>
CGameCollision::FindNonIntersectingVector(CStateManager& mgr, CAreaCollisionCache& cache,
CPhysicsActor& actor, const CCollisionPrimitive& prim,
const rstl::reserved_vector<TUniqueId, 1024>& nearList)
{
zeus::CTransform xf = actor.GetPrimitiveTransform();
zeus::CVector3f center = prim.CalculateAABox(xf).center();
for (int i=2 ; i<1000 ; i+=(i/2))
{
float pos = i * 0.005f;
float neg = -pos;
for (int j=0 ; j<26 ; ++j)
{
zeus::CVector3f vec;
switch (j)
{
case 0:
vec = {0.f, pos, 0.f};
break;
case 1:
vec = {0.f, neg, 0.f};
break;
case 2:
vec = {pos, 0.f, 0.f};
break;
case 3:
vec = {neg, 0.f, 0.f};
break;
case 4:
vec = {0.f, 0.f, pos};
break;
case 5:
vec = {0.f, 0.f, neg};
break;
case 6:
vec = {0.f, pos, pos};
break;
case 7:
vec = {0.f, neg, neg};
break;
case 8:
vec = {0.f, neg, pos};
break;
case 9:
vec = {0.f, pos, neg};
break;
case 10:
vec = {pos, 0.f, pos};
break;
case 11:
vec = {neg, 0.f, neg};
break;
case 12:
vec = {neg, 0.f, pos};
break;
case 13:
vec = {pos, 0.f, neg};
break;
case 14:
vec = {pos, pos, 0.f};
break;
case 15:
vec = {neg, neg, 0.f};
break;
case 16:
vec = {neg, pos, 0.f};
break;
case 17:
vec = {pos, neg, 0.f};
break;
case 18:
vec = {pos, pos, pos};
break;
case 19:
vec = {neg, pos, pos};
break;
case 20:
vec = {pos, neg, pos};
break;
case 21:
vec = {neg, neg, pos};
break;
case 22:
vec = {pos, pos, neg};
break;
case 23:
vec = {neg, pos, neg};
break;
case 24:
vec = {pos, neg, neg};
break;
case 25:
vec = {neg, neg, neg};
break;
default: break;
}
zeus::CVector3f worldPoint = vec + xf.origin;
if (mgr.GetWorld()->GetAreaAlways(mgr.GetNextAreaId())->GetAABB().pointInside(worldPoint))
{
if (mgr.RayCollideWorld(center, center + vec, nearList,
CMaterialFilter::skPassEverything, actor))
{
if (!DetectCollisionBoolean_Cached(mgr, cache, prim, xf, actor.GetMaterialFilter(), nearList))
return {vec};
}
}
}
}
return {};
}
}

View File

@ -25,10 +25,6 @@ class CGameCollision
{
static void MovePlayer(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* colliderList);
static void MoveGroundCollider(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* colliderList);
static void MoveGroundCollider_New(CStateManager& mgr, CPhysicsActor& actor, float dt,
const rstl::reserved_vector<TUniqueId, 1024>* colliderList);
static void MoveAndCollide(CStateManager& mgr, CPhysicsActor& actor, float dt, const ICollisionFilter& filter,
const rstl::reserved_vector<TUniqueId, 1024>* colliderList);
static zeus::CVector3f GetActorRelativeVelocities(const CPhysicsActor& act0, const CPhysicsActor* act1);
@ -84,6 +80,12 @@ public:
const CMaterialFilter& filter,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
TUniqueId& idOut, CCollisionInfoList& infoList);
static bool DetectCollision_Cached_Moving(CStateManager& mgr, CAreaCollisionCache& cache,
const CCollisionPrimitive& prim, const zeus::CTransform& xf,
const CMaterialFilter& filter,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
const zeus::CVector3f& vec,
TUniqueId& idOut, CCollisionInfo& infoOut, double&);
static bool DetectStaticCollision(CStateManager& mgr, const CCollisionPrimitive& prim,
const zeus::CTransform& xf, const CMaterialFilter& filter,
CCollisionInfoList& list);
@ -105,6 +107,10 @@ public:
CPhysicsActor& actor, const CCollisionPrimitive& prim,
const rstl::reserved_vector<TUniqueId, 1024>& nearList,
float, u32 failsafeTicks);
static std::experimental::optional<zeus::CVector3f>
FindNonIntersectingVector(CStateManager& mgr, CAreaCollisionCache& cache,
CPhysicsActor& actor, const CCollisionPrimitive& prim,
const rstl::reserved_vector<TUniqueId, 1024>& nearList);
};
}

View File

@ -147,6 +147,11 @@ public:
{
return other.x0_list & x0_list;
}
u64 XOR(const CMaterialList& other) const
{
return x0_list ^ other.x0_list;
}
};
}

View File

@ -63,6 +63,26 @@ void FilterOutBackfaces(const zeus::CVector3f& vec, const CCollisionInfoList& in
}
}
void FilterByClosestNormal(const zeus::CVector3f& norm, const CCollisionInfoList& in, CCollisionInfoList& out)
{
float maxDot = -1.1f;
int idx = -1;
int i=0;
for (const CCollisionInfo& info : in)
{
float dot = info.GetNormalLeft().dot(norm);
if (dot > maxDot)
{
maxDot = dot;
idx = i;
}
++i;
}
if (idx != -1)
out.Add(in.GetItem(i), false);
}
static const zeus::CVector3f AABBNormalTable[] =
{
{-1.f, 0.f, 0.f},

View File

@ -16,6 +16,7 @@ u32 RaySphereIntersection_Double(const zeus::CSphere&, const zeus::CVector3f&, c
bool RaySphereIntersection(const zeus::CSphere& sphere, const zeus::CVector3f& pos, const zeus::CVector3f& dir,
float mag, float& T, zeus::CVector3f& point);
void FilterOutBackfaces(const zeus::CVector3f& vec, const CCollisionInfoList& in, CCollisionInfoList& out);
void FilterByClosestNormal(const zeus::CVector3f& norm, const CCollisionInfoList& in, CCollisionInfoList& out);
bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const CMaterialList& list0,
const zeus::CAABox& aabb1, const CMaterialList& list1,
CCollisionInfoList& infoList);

View File

@ -114,6 +114,7 @@ class TCastToPtr : public IVisitor
protected:
T* ptr = nullptr;
public:
TCastToPtr() = default;
TCastToPtr(CEntity* p);
TCastToPtr(CEntity& p);
@ -134,6 +135,7 @@ template <class T>
class TCastToConstPtr : TCastToPtr<T>
{
public:
TCastToConstPtr() = default;
TCastToConstPtr(const CEntity* p) : TCastToPtr<T>(const_cast<CEntity*>(p)) {}
TCastToConstPtr(const CEntity& p) : TCastToPtr<T>(const_cast<CEntity&>(p)) {}
const T* GetPtr() const { return TCastToPtr<T>::ptr; }

View File

@ -78,6 +78,7 @@ public:
class CPhysicsActor : public CActor
{
friend class CGroundMovement;
protected:
float xe8_mass;
float xec_massRecip;
@ -108,7 +109,7 @@ protected:
CCollidableAABox x1c0_collisionPrimitive;
zeus::CVector3f x1e8_primitiveOffset;
CMotionState x1f4_lastNonCollidingState;
bool x234_ = false;
std::experimental::optional<zeus::CVector3f> x228_lastFloorPlaneNormal;
float x238_maximumCollisionVelocity = 1000000.0f;
float x23c_stepUpHeight;
float x240_stepDownHeight;
@ -138,7 +139,7 @@ public:
zeus::CVector3f GetPrimitiveOffset();
void MoveCollisionPrimitive(const zeus::CVector3f& offset);
void SetBoundingBox(const zeus::CAABox& box);
zeus::CAABox GetMotionVolume(float f31) const;
zeus::CAABox GetMotionVolume(float dt) const;
zeus::CVector3f CalculateNewVelocityWR_UsingImpulses() const;
zeus::CAABox GetBoundingBox() const;
const zeus::CAABox& GetBaseBoundingBox() const;
@ -153,9 +154,12 @@ public:
void SetMass(float mass);
void SetAngularVelocityOR(const zeus::CAxisAngle& angVel);
zeus::CAxisAngle GetAngularVelocityOR() const;
const zeus::CAxisAngle& GetAngularVelocityWR() const { return x144_angularVelocity; }
void SetAngularVelocityWR(const zeus::CAxisAngle& angVel);
void SetVelocityWR(const zeus::CVector3f& vel);
void SetVelocityOR(const zeus::CVector3f& vel);
void SetMomentumWR(const zeus::CVector3f& m) { x150_momentum = m; }
const zeus::CVector3f& GetMomentum() const { return x150_momentum; }
const zeus::CVector3f& GetVelocity() const { return x138_velocity; }
zeus::CVector3f GetTotalForcesWR() const;
void RotateInOneFrameOR(const zeus::CQuaternion& q, float d);
@ -186,6 +190,8 @@ public:
void SetNumTicksPartialUpdate(u32 t) { x250_numTicksPartialUpdate = t; }
u32 GetNumTicksStuck() const { return x24c_numTicksStuck; }
void SetNumTicksStuck(u32 t) { x24c_numTicksStuck = t; }
const std::experimental::optional<zeus::CVector3f>& GetLastFloorPlaneNormal() const { return x228_lastFloorPlaneNormal; }
void SetLastFloorPlaneNormal(const std::experimental::optional<zeus::CVector3f>& n) { x228_lastFloorPlaneNormal = n; }
CMotionState PredictMotion_Internal(float) const;
CMotionState PredictMotion(float dt) const;

View File

@ -947,6 +947,12 @@ bool CPlayer::ObjectInScanningRange(TUniqueId id, const CStateManager& mgr) cons
return false;
}
void CPlayer::SetPlayerHitWallDuringMove()
{
x9c5_29_hitWall = true;
x2d0_ = 1;
}
void CPlayer::Touch() {}
void CPlayer::CVisorSteam::SetSteam(float a, float b, float c, ResId d, bool e)

View File

@ -27,6 +27,7 @@ class CPlayer : public CPhysicsActor
friend class CFirstPersonCamera;
friend class CPlayerCameraBob;
friend class CMorphBall;
friend class CGroundMovement;
public:
enum class EPlayerScanState
@ -318,13 +319,13 @@ private:
bool x9c4_28_ : 1;
bool x9c4_29_ : 1;
bool x9c4_30_ : 1;
bool x9c4_31_ : 1;
bool x9c4_31_dampUnderwaterMotion : 1;
bool x9c5_24_ : 1;
bool x9c5_25_splashUpdated : 1;
bool x9c5_26_ : 1;
bool x9c5_27_ : 1;
bool x9c5_28_ : 1;
bool x9c5_29_ : 1;
bool x9c5_28_slidingOnWall : 1;
bool x9c5_29_hitWall : 1;
bool x9c5_30_ : 1;
bool x9c5_31_ : 1;
bool x9c6_24_ : 1;
@ -543,6 +544,7 @@ public:
const std::vector<TUniqueId>& GetNearbyOrbitObjects() const { return x344_nearbyOrbitObjects; }
const std::vector<TUniqueId>& GetOnScreenOrbitObjects() const { return x354_onScreenOrbitObjects; }
const std::vector<TUniqueId>& GetOffScreenOrbitObjects() const { return x364_offScreenOrbitObjects; }
void SetPlayerHitWallDuringMove();
void Touch();