mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 07:47:57 +03:00
Dynamic bridge collision (#1137)
* Initial commit * Don't update bridge offset if not necessary * Don't stick to bridge when in air * Update Changes.txt * Minor simplification * Simplify * Update collide_room.h * Update collide_room.h * Use real floor height to determine bridge collision * Detect bridges first to avoid potential issues with item init * Remove incorrect forward declaration * Move pickups on dynamic bridges * Push player away from moving bridges * Update Changes.txt * Use actual pickup bounds for collision detection * Stabilize collision by using both abs Y and bb Y ref points * Update collide_item.cpp * Swap function parameters * Update collide_room.cpp * Increase movement tolerance --------- Co-authored-by: Sezz <sezzary@outlook.com> Co-authored-by: Jakub <80340234+Kubsy@users.noreply.github.com>
This commit is contained in:
parent
ba368be4b7
commit
35304ce84a
20 changed files with 223 additions and 77 deletions
|
@ -14,6 +14,8 @@ Version 1.1.0
|
|||
* Add multiple doppelgangers by using the same OCB for the origin nullmesh and doppelganger.
|
||||
* Pause all sounds when entering inventory or pause menu.
|
||||
* Improve deflection against slopes.
|
||||
* Move and rotate Lara together with dynamic bridge objects.
|
||||
* Move and rotate activated pickups together with dynamic bridge objects.
|
||||
* Add TR1 skateboard kid.
|
||||
* Add TR1 Kold.
|
||||
|
||||
|
|
|
@ -48,6 +48,10 @@ bool LaraDeflectEdge(ItemInfo* item, CollisionInfo* coll)
|
|||
ShiftItem(item, coll);
|
||||
item->Pose.Orientation.y -= ANGLE(coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
|
||||
}
|
||||
else if (coll->LastBridgeItemNumber != NO_ITEM)
|
||||
{
|
||||
ShiftItem(item, coll);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -202,8 +206,8 @@ bool LaraDeflectEdgeCrawl(ItemInfo* item, CollisionInfo* coll)
|
|||
bool LaraDeflectEdgeMonkey(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
// HACK
|
||||
if (coll->Shift.y >= 0 && coll->Shift.y <= CLICK(1.25f))
|
||||
coll->Shift.y = 0;
|
||||
if (coll->Shift.Position.y >= 0 && coll->Shift.Position.y <= CLICK(1.25f))
|
||||
coll->Shift.Position.y = 0;
|
||||
|
||||
if (coll->CollisionType == CT_FRONT || coll->CollisionType == CT_TOP_FRONT ||
|
||||
coll->HitTallObject)
|
||||
|
|
|
@ -140,8 +140,8 @@ void lara_col_monkey_idle(ItemInfo* item, CollisionInfo* coll)
|
|||
GetCollisionInfo(coll, item);
|
||||
|
||||
// HACK: Prevent ShiftItem() from causing an instantaneous snap, thereby interfering with DoLaraMonkeyStep(), when going down a step. @Sezz 2022.01.28
|
||||
if (coll->Shift.y >= 0 && coll->Shift.y <= CLICK(1.25f))
|
||||
coll->Shift.y = 0;
|
||||
if (coll->Shift.Position.y >= 0 && coll->Shift.Position.y <= CLICK(1.25f))
|
||||
coll->Shift.Position.y = 0;
|
||||
ShiftItem(item, coll);
|
||||
|
||||
if (TestLaraMonkeyFall(item, coll))
|
||||
|
|
|
@ -250,9 +250,9 @@ bool TestLaraHang(ItemInfo* item, CollisionInfo* coll)
|
|||
else // Death, incorrect ledge or ACTION release
|
||||
{
|
||||
SetAnimation(item, LA_JUMP_UP, 9);
|
||||
item->Pose.Position.x += coll->Shift.x;
|
||||
item->Pose.Position.x += coll->Shift.Position.x;
|
||||
item->Pose.Position.y += GameBoundingBox(item).Y2 * 1.8f;
|
||||
item->Pose.Position.z += coll->Shift.z;
|
||||
item->Pose.Position.z += coll->Shift.Position.z;
|
||||
item->Animation.IsAirborne = true;
|
||||
item->Animation.Velocity.z = 2;
|
||||
item->Animation.Velocity.y = 1;
|
||||
|
@ -472,12 +472,12 @@ bool TestLaraHangOnClimbableWall(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
item->Pose.Position.z += coll2.Shift.z;
|
||||
item->Pose.Position.z += coll2.Shift.Position.z;
|
||||
break;
|
||||
|
||||
case EAST:
|
||||
case WEST:
|
||||
item->Pose.Position.x += coll2.Shift.x;
|
||||
item->Pose.Position.x += coll2.Shift.Position.x;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -753,6 +753,54 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool ena
|
|||
return true;
|
||||
}
|
||||
|
||||
// Simplified version of ItemPushItem for basic pushes.
|
||||
bool ItemPushItem(ItemInfo* item, ItemInfo* item2)
|
||||
{
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
float cosY = phd_cos(item->Pose.Orientation.y);
|
||||
|
||||
// Get direction vector from item to player.
|
||||
auto direction = item2->Pose.Position - item->Pose.Position;
|
||||
|
||||
// Rotate Lara vector into item frame.
|
||||
int rx = (direction.x * cosY) - (direction.z * sinY);
|
||||
int rz = (direction.z * cosY) + (direction.x * sinY);
|
||||
|
||||
const auto& bounds = GetBestFrame(*item).BoundingBox;
|
||||
|
||||
int minX = bounds.X1;
|
||||
int maxX = bounds.X2;
|
||||
int minZ = bounds.Z1;
|
||||
int maxZ = bounds.Z2;
|
||||
|
||||
// Big enemies
|
||||
if (abs(direction.x) > BLOCK(4.5f) || abs(direction.z) > BLOCK(4.5f) ||
|
||||
rx <= minX || rx >= maxX ||
|
||||
rz <= minZ || rz >= maxZ)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int left = rx - minX;
|
||||
int top = maxZ - rz;
|
||||
int bottom = rz - minZ;
|
||||
int right = maxX - rx;
|
||||
|
||||
if (right <= left && right <= top && right <= bottom)
|
||||
rx += right;
|
||||
else if (left <= right && left <= top && left <= bottom)
|
||||
rx -= left;
|
||||
else if (top <= left && top <= right && top <= bottom)
|
||||
rz += top;
|
||||
else
|
||||
rz -= bottom;
|
||||
|
||||
item2->Pose.Position.x = item->Pose.Position.x + (rx * cosY) + (rz * sinY);
|
||||
item2->Pose.Position.z = item->Pose.Position.z + (rz * cosY) - (rx * sinY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Previously ItemPushLaraStatic().
|
||||
bool ItemPushStatic(ItemInfo* item, const MESH_INFO& mesh, CollisionInfo* coll)
|
||||
{
|
||||
|
@ -828,6 +876,62 @@ bool ItemPushStatic(ItemInfo* item, const MESH_INFO& mesh, CollisionInfo* coll)
|
|||
return true;
|
||||
}
|
||||
|
||||
void ItemPushBridge(ItemInfo& item, CollisionInfo& coll)
|
||||
{
|
||||
coll.Setup.ForwardAngle = item.Pose.Orientation.y;
|
||||
coll.Setup.OldPosition = item.Pose.Position;
|
||||
GetCollisionInfo(&coll, &item);
|
||||
ShiftItem(&item, &coll);
|
||||
}
|
||||
|
||||
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResult& collResult)
|
||||
{
|
||||
// Store an offset for a bridge item into shifts, if exists.
|
||||
if (coll.LastBridgeItemNumber == collResult.Position.Bridge && coll.LastBridgeItemNumber != NO_ITEM)
|
||||
{
|
||||
auto& bridgeItem = g_Level.Items[collResult.Position.Bridge];
|
||||
|
||||
auto deltaPos = bridgeItem.Pose.Position - coll.LastBridgeItemPose.Position;
|
||||
auto deltaOrient = bridgeItem.Pose.Orientation - coll.LastBridgeItemPose.Orientation;
|
||||
auto deltaPose = Pose(deltaPos, deltaOrient);
|
||||
|
||||
int absDeltaHeight = item.Pose.Position.y - collResult.Position.Floor;
|
||||
int relDeltaHeight = absDeltaHeight + GameBoundingBox(&item).Y2;
|
||||
|
||||
if (deltaPose != Pose::Zero &&
|
||||
(abs(absDeltaHeight) <= CLICK(1 / 8.0f) || abs(relDeltaHeight) <= CLICK(1 / 8.0f)))
|
||||
{
|
||||
const auto& bridgePos = bridgeItem.Pose.Position;
|
||||
|
||||
// Calculate offset.
|
||||
auto relOffset = (item.Pose.Position - bridgePos).ToVector3();
|
||||
auto rotMatrix = deltaPose.Orientation.ToRotationMatrix();
|
||||
auto offset = bridgePos.ToVector3() + Vector3::Transform(relOffset, rotMatrix);
|
||||
|
||||
deltaPose.Position -= item.Pose.Position - Vector3i(offset);
|
||||
|
||||
// Don't update shifts if difference is too big (possibly bridge was teleported or just entered bridge).
|
||||
if (deltaPose.Position.ToVector3().Length() <= coll.Setup.Radius * 2)
|
||||
coll.Shift = deltaPose;
|
||||
}
|
||||
else if (deltaPos.ToVector3().Length() <= coll.Setup.Radius && relDeltaHeight > 0 &&
|
||||
(deltaPos != Vector3i::Zero || deltaOrient != EulerAngles::Zero))
|
||||
{
|
||||
// Push item away if not directly above bridge, and bridge position was changed.
|
||||
ItemPushItem(&bridgeItem, &item);
|
||||
}
|
||||
|
||||
coll.LastBridgeItemPose = bridgeItem.Pose;
|
||||
}
|
||||
else
|
||||
{
|
||||
coll.LastBridgeItemPose = Pose::Zero;
|
||||
coll.LastBridgeItemNumber = NO_ITEM;
|
||||
}
|
||||
|
||||
coll.LastBridgeItemNumber = collResult.Position.Bridge;
|
||||
}
|
||||
|
||||
void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
coll->HitTallObject = false;
|
||||
|
@ -1057,20 +1161,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
case NORTH:
|
||||
if (rawShift.x > coll->Setup.Radius || rawShift.x < -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.z = rawShift.z;
|
||||
coll->Shift.x = ox - x;
|
||||
coll->Shift.Position.z = rawShift.z;
|
||||
coll->Shift.Position.x = ox - x;
|
||||
coll->CollisionType = CT_FRONT;
|
||||
}
|
||||
else if (rawShift.x > 0 && rawShift.x <= coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.x = rawShift.x;
|
||||
coll->Shift.z = 0;
|
||||
coll->Shift.Position.x = rawShift.x;
|
||||
coll->Shift.Position.z = 0;
|
||||
coll->CollisionType = CT_LEFT;
|
||||
}
|
||||
else if (rawShift.x < 0 && rawShift.x >= -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.x = rawShift.x;
|
||||
coll->Shift.z = 0;
|
||||
coll->Shift.Position.x = rawShift.x;
|
||||
coll->Shift.Position.z = 0;
|
||||
coll->CollisionType = CT_RIGHT;
|
||||
}
|
||||
|
||||
|
@ -1079,20 +1183,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
case SOUTH:
|
||||
if (rawShift.x > coll->Setup.Radius || rawShift.x < -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.z = rawShift.z;
|
||||
coll->Shift.x = ox - x;
|
||||
coll->Shift.Position.z = rawShift.z;
|
||||
coll->Shift.Position.x = ox - x;
|
||||
coll->CollisionType = CT_FRONT;
|
||||
}
|
||||
else if (rawShift.x > 0 && rawShift.x <= coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.x = rawShift.x;
|
||||
coll->Shift.z = 0;
|
||||
coll->Shift.Position.x = rawShift.x;
|
||||
coll->Shift.Position.z = 0;
|
||||
coll->CollisionType = CT_RIGHT;
|
||||
}
|
||||
else if (rawShift.x < 0 && rawShift.x >= -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.x = rawShift.x;
|
||||
coll->Shift.z = 0;
|
||||
coll->Shift.Position.x = rawShift.x;
|
||||
coll->Shift.Position.z = 0;
|
||||
coll->CollisionType = CT_LEFT;
|
||||
}
|
||||
|
||||
|
@ -1101,20 +1205,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
case EAST:
|
||||
if (rawShift.z > coll->Setup.Radius || rawShift.z < -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.x = rawShift.x;
|
||||
coll->Shift.z = oz - z;
|
||||
coll->Shift.Position.x = rawShift.x;
|
||||
coll->Shift.Position.z = oz - z;
|
||||
coll->CollisionType = CT_FRONT;
|
||||
}
|
||||
else if (rawShift.z > 0 && rawShift.z <= coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.z = rawShift.z;
|
||||
coll->Shift.x = 0;
|
||||
coll->Shift.Position.z = rawShift.z;
|
||||
coll->Shift.Position.x = 0;
|
||||
coll->CollisionType = CT_RIGHT;
|
||||
}
|
||||
else if (rawShift.z < 0 && rawShift.z >= -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.z = rawShift.z;
|
||||
coll->Shift.x = 0;
|
||||
coll->Shift.Position.z = rawShift.z;
|
||||
coll->Shift.Position.x = 0;
|
||||
coll->CollisionType = CT_LEFT;
|
||||
}
|
||||
|
||||
|
@ -1123,20 +1227,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
case WEST:
|
||||
if (rawShift.z > coll->Setup.Radius || rawShift.z < -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.x = rawShift.x;
|
||||
coll->Shift.z = oz - z;
|
||||
coll->Shift.Position.x = rawShift.x;
|
||||
coll->Shift.Position.z = oz - z;
|
||||
coll->CollisionType = CT_FRONT;
|
||||
}
|
||||
else if (rawShift.z > 0 && rawShift.z <= coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.z = rawShift.z;
|
||||
coll->Shift.x = 0;
|
||||
coll->Shift.Position.z = rawShift.z;
|
||||
coll->Shift.Position.x = 0;
|
||||
coll->CollisionType = CT_LEFT;
|
||||
}
|
||||
else if (rawShift.z < 0 && rawShift.z >= -coll->Setup.Radius)
|
||||
{
|
||||
coll->Shift.z = rawShift.z;
|
||||
coll->Shift.x = 0;
|
||||
coll->Shift.Position.z = rawShift.z;
|
||||
coll->Shift.Position.x = 0;
|
||||
coll->CollisionType = CT_RIGHT;
|
||||
}
|
||||
|
||||
|
@ -1144,15 +1248,15 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
}
|
||||
|
||||
// Determine final shifts orientation/distance.
|
||||
distance = Vector3(x + coll->Shift.x, y, z + coll->Shift.z) - pose.Position.ToVector3();
|
||||
distance = Vector3(x + coll->Shift.Position.x, y, z + coll->Shift.Position.z) - pose.Position.ToVector3();
|
||||
sinY = phd_sin(-pose.Orientation.y);
|
||||
cosY = phd_cos(-pose.Orientation.y);
|
||||
|
||||
// Calculate final shifts orientation/distance.
|
||||
coll->Shift.x = (round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x) - item->Pose.Position.x;
|
||||
coll->Shift.z = (round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z) - item->Pose.Position.z;
|
||||
coll->Shift.Position.x = (round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x) - item->Pose.Position.x;
|
||||
coll->Shift.Position.z = (round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z) - item->Pose.Position.z;
|
||||
|
||||
if (coll->Shift.x == 0 && coll->Shift.z == 0)
|
||||
if (coll->Shift.Position.x == 0 && coll->Shift.Position.z == 0)
|
||||
coll->CollisionType = CT_NONE; // Paranoid.
|
||||
|
||||
// Set splat state flag if item is Lara and bounds are taller than Lara's headroom.
|
||||
|
@ -1838,7 +1942,7 @@ void ObjectCollision(const short itemNumber, ItemInfo* laraItem, CollisionInfo*
|
|||
if (TestCollision(item, laraItem))
|
||||
{
|
||||
if (coll->Setup.EnableObjectPush)
|
||||
ItemPushItem(item, laraItem, coll, false, true);
|
||||
ItemPushItem(item, laraItem, coll, false, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#pragma once
|
||||
#include "Math/Math.h"
|
||||
|
||||
using std::pair;
|
||||
|
||||
class FloorInfo;
|
||||
struct CollisionInfo;
|
||||
struct CollisionResult;
|
||||
struct ItemInfo;
|
||||
struct MESH_INFO;
|
||||
|
||||
|
@ -19,8 +18,8 @@ extern MESH_INFO* CollidedMeshes[MAX_COLLIDED_OBJECTS];
|
|||
|
||||
struct ObjectCollisionBounds
|
||||
{
|
||||
GameBoundingBox BoundingBox = GameBoundingBox::Zero;
|
||||
pair<EulerAngles, EulerAngles> OrientConstraint = {};
|
||||
GameBoundingBox BoundingBox = GameBoundingBox::Zero;
|
||||
std::pair<EulerAngles, EulerAngles> OrientConstraint = {};
|
||||
};
|
||||
|
||||
void GenericSphereBoxCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
|
@ -40,10 +39,13 @@ bool Move3DPosTo3DPos(ItemInfo* item, Pose& fromPose, const Pose& toPose, int ve
|
|||
bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius);
|
||||
bool TestBoundsCollideStatic(ItemInfo* item, const MESH_INFO& mesh, int radius);
|
||||
bool ItemPushItem(ItemInfo* item, ItemInfo* laraItem, CollisionInfo* coll, bool enableSpasm, char bigPush);
|
||||
bool ItemPushItem(ItemInfo* item, ItemInfo* item2);
|
||||
bool ItemPushStatic(ItemInfo* laraItem, const MESH_INFO& mesh, CollisionInfo* coll);
|
||||
void ItemPushBridge(ItemInfo& item, CollisionInfo& coll);
|
||||
|
||||
bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose& pose, CollisionInfo* coll);
|
||||
void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll);
|
||||
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResult& collResult);
|
||||
|
||||
void AIPickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
void ObjectCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
|
|
|
@ -18,7 +18,8 @@ using namespace TEN::Renderer;
|
|||
|
||||
void ShiftItem(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
item->Pose.Position += coll->Shift;
|
||||
item->Pose.Position += coll->Shift.Position;
|
||||
item->Pose.Orientation += coll->Shift.Orientation;
|
||||
coll->Shift = Vector3i::Zero;
|
||||
}
|
||||
|
||||
|
@ -227,7 +228,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
|
||||
// Reset collision parameters.
|
||||
coll->CollisionType = CollisionType::CT_NONE;
|
||||
coll->Shift = Vector3i::Zero;
|
||||
coll->Shift = Pose::Zero;
|
||||
|
||||
// Offset base probe position by provided offset, if any.
|
||||
auto entityPos = item->Pose.Position + offset;
|
||||
|
@ -348,6 +349,9 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
coll->Middle.Floor = height;
|
||||
coll->Middle.Ceiling = ceiling;
|
||||
|
||||
// Additionally calculate bridge shifts, if present.
|
||||
CollideBridgeItems(*item, *coll, collResult);
|
||||
|
||||
// TEST 3: FRONTAL PROBE
|
||||
|
||||
probePos.x = entityPos.x + xFront;
|
||||
|
@ -698,21 +702,21 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
|
||||
if (coll->Middle.Floor == NO_HEIGHT)
|
||||
{
|
||||
coll->Shift = coll->Setup.OldPosition - entityPos;
|
||||
coll->Shift.Position += coll->Setup.OldPosition - entityPos;
|
||||
coll->CollisionType = CT_FRONT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (coll->Middle.Floor - coll->Middle.Ceiling <= 0)
|
||||
{
|
||||
coll->Shift = coll->Setup.OldPosition - entityPos;
|
||||
coll->Shift.Position += coll->Setup.OldPosition - entityPos;
|
||||
coll->CollisionType = CT_CLAMP;
|
||||
return;
|
||||
}
|
||||
|
||||
if (coll->Middle.Ceiling >= 0)
|
||||
{
|
||||
coll->Shift.y = coll->Middle.Ceiling;
|
||||
coll->Shift.Position.y += coll->Middle.Ceiling;
|
||||
coll->CollisionType = CT_TOP;
|
||||
}
|
||||
|
||||
|
@ -724,8 +728,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
{
|
||||
if (coll->Front.HasDiagonalSplit())
|
||||
{
|
||||
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
|
||||
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -733,14 +737,14 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
{
|
||||
case 0:
|
||||
case 2:
|
||||
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.z = FindGridShift(entityPos.z + zFront, entityPos.z);
|
||||
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.Position.z += FindGridShift(entityPos.z + zFront, entityPos.z);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
coll->Shift.x = FindGridShift(entityPos.x + xFront, entityPos.x);
|
||||
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
|
||||
coll->Shift.Position.x += FindGridShift(entityPos.x + xFront, entityPos.x);
|
||||
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -752,7 +756,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
if (coll->Front.Ceiling > coll->Setup.LowerCeilingBound ||
|
||||
coll->Front.Ceiling < coll->Setup.UpperCeilingBound)
|
||||
{
|
||||
coll->Shift = coll->Setup.OldPosition - entityPos;
|
||||
coll->Shift.Position += coll->Setup.OldPosition - entityPos;
|
||||
coll->CollisionType = CT_TOP_FRONT;
|
||||
return;
|
||||
}
|
||||
|
@ -768,8 +772,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
// HACK: Force slight push-out to the left side to avoid stucking
|
||||
TranslateItem(item, coll->Setup.ForwardAngle + ANGLE(8.0f), item->Animation.Velocity.z);
|
||||
|
||||
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
|
||||
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -777,12 +781,12 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
{
|
||||
case 0:
|
||||
case 2:
|
||||
coll->Shift.x = FindGridShift(entityPos.x + xLeft, entityPos.x + xFront);
|
||||
coll->Shift.Position.x += FindGridShift(entityPos.x + xLeft, entityPos.x + xFront);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
coll->Shift.z = FindGridShift(entityPos.z + zLeft, entityPos.z + zFront);
|
||||
coll->Shift.Position.z += FindGridShift(entityPos.z + zLeft, entityPos.z + zFront);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -822,8 +826,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
// HACK: Force slight push out to the right side to avoid getting stuck.
|
||||
TranslateItem(item, coll->Setup.ForwardAngle - ANGLE(8.0f), item->Animation.Velocity.z);
|
||||
|
||||
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
|
||||
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
|
||||
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -831,12 +835,12 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
|
|||
{
|
||||
case 0:
|
||||
case 2:
|
||||
coll->Shift.x = FindGridShift(entityPos.x + xRight, entityPos.x + xFront);
|
||||
coll->Shift.Position.x += FindGridShift(entityPos.x + xRight, entityPos.x + xFront);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
coll->Shift.z = FindGridShift(entityPos.z + zRight, entityPos.z + zFront);
|
||||
coll->Shift.Position.z += FindGridShift(entityPos.z + zRight, entityPos.z + zFront);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "Math/Math.h"
|
||||
#include "Objects/game_object_ids.h"
|
||||
|
||||
struct ItemInfo;
|
||||
struct CollisionInfo;
|
||||
class FloorInfo;
|
||||
struct ROOM_INFO;
|
||||
struct MESH_INFO;
|
||||
|
@ -105,13 +105,16 @@ struct CollisionInfo
|
|||
CollisionPosition FrontLeft;
|
||||
CollisionPosition FrontRight;
|
||||
|
||||
Vector3i Shift;
|
||||
Pose Shift = Pose::Zero;
|
||||
CollisionType CollisionType;
|
||||
Vector2 FloorTilt; // x = x, y = z
|
||||
Vector2 CeilingTilt; // x = x, y = z
|
||||
short NearestLedgeAngle;
|
||||
float NearestLedgeDistance;
|
||||
|
||||
int LastBridgeItemNumber;
|
||||
Pose LastBridgeItemPose;
|
||||
|
||||
bool HitStatic;
|
||||
bool HitTallObject;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdexcept>
|
||||
#include <variant>
|
||||
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/itemdata/creature_info.h"
|
||||
#include "Game/itemdata/door_data.h"
|
||||
#include "Game/Lara/lara_struct.h"
|
||||
|
@ -56,6 +57,7 @@ class ItemData
|
|||
PushableInfo,
|
||||
ItemInfo*,
|
||||
LaraInfo*,
|
||||
CollisionInfo,
|
||||
CreatureInfo,
|
||||
WraithInfo,
|
||||
GuardianInfo,
|
||||
|
|
|
@ -958,6 +958,8 @@ void DropPickups(ItemInfo* item)
|
|||
void PickupControl(short itemNumber)
|
||||
{
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
|
||||
ItemPushBridge(*item, *(CollisionInfo*)item->Data);
|
||||
|
||||
short roomNumber;
|
||||
short triggerFlags = item->TriggerFlags & 0x3F;
|
||||
|
@ -1056,9 +1058,13 @@ const GameBoundingBox* FindPlinth(ItemInfo* item)
|
|||
void InitializePickup(short itemNumber)
|
||||
{
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
|
||||
auto bounds = GameBoundingBox(item);
|
||||
|
||||
item->Data = CollisionInfo();
|
||||
auto* coll = (CollisionInfo*)item->Data;
|
||||
coll->Setup.Radius = std::max(bounds.GetWidth(), bounds.GetDepth());
|
||||
coll->Setup.Height = bounds.GetHeight();
|
||||
|
||||
short triggerFlags = item->TriggerFlags & 0x3F;
|
||||
if (triggerFlags == 5)
|
||||
{
|
||||
|
|
|
@ -253,7 +253,7 @@ namespace TEN::Entities::Doors
|
|||
if (!(doorItem->ObjectNumber >= ID_LIFT_DOORS1 &&
|
||||
doorItem->ObjectNumber <= ID_LIFT_DOORS2) || doorItem->ItemFlags[0])
|
||||
{
|
||||
ItemPushItem(doorItem, laraItem, coll, FALSE, TRUE);
|
||||
ItemPushItem(doorItem, laraItem, coll, false, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace TEN::Entities::Traps::TR1
|
|||
return;
|
||||
|
||||
if (coll->Setup.EnableObjectPush)
|
||||
ItemPushItem(&item, laraItem, coll, false, true);
|
||||
ItemPushItem(&item, laraItem, coll, false, 1);
|
||||
|
||||
if (item.Animation.IsAirborne)
|
||||
{
|
||||
|
|
|
@ -184,7 +184,7 @@ namespace TEN::Entities::Vehicles
|
|||
{
|
||||
// HACK: Collision in water behaves differently? @Sezz 2022.06.28
|
||||
if (TestBoundsCollide(UPVItem, laraItem, coll->Setup.Radius) && TestCollision(UPVItem, laraItem))
|
||||
ItemPushItem(UPVItem, laraItem, coll, false, false);
|
||||
ItemPushItem(UPVItem, laraItem, coll, false, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -152,7 +152,7 @@ namespace TEN::Entities::TR4
|
|||
if (TestCollision(item, laraItem))
|
||||
{
|
||||
if (coll->Setup.EnableObjectPush)
|
||||
ItemPushItem(item, laraItem, coll, 0, 0);
|
||||
ItemPushItem(item, laraItem, coll, false, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,17 +106,17 @@ void ScalesCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
|||
GlobalCollisionBounds.Z1 = -256;
|
||||
GlobalCollisionBounds.Z2 = 384;
|
||||
|
||||
ItemPushItem(item, laraItem, coll, 0, 2);
|
||||
ItemPushItem(item, laraItem, coll, false, 2);
|
||||
|
||||
GlobalCollisionBounds.X1 = -256;
|
||||
GlobalCollisionBounds.X2 = 256;
|
||||
|
||||
ItemPushItem(item, laraItem, coll, 0, 2);
|
||||
ItemPushItem(item, laraItem, coll, false, 2);
|
||||
|
||||
GlobalCollisionBounds.X1 = -1280;
|
||||
GlobalCollisionBounds.X2 = -640;
|
||||
|
||||
ItemPushItem(item, laraItem, coll, 0, 2);
|
||||
ItemPushItem(item, laraItem, coll, false, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace TEN::Entities::TR4
|
|||
int dy = 0;
|
||||
int dz = 0;
|
||||
|
||||
if (ItemPushItem(bladeItem, laraItem, coll, 1, 1))
|
||||
if (ItemPushItem(bladeItem, laraItem, coll, true, 1))
|
||||
{
|
||||
DoDamage(laraItem, bladeItem->ItemFlags[3]);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace TEN::Entities::TR4
|
|||
DoDamage(laraItem, 10);
|
||||
}
|
||||
else if (coll->Setup.EnableObjectPush)
|
||||
ItemPushItem(cogItem, laraItem, coll, 0, 0);
|
||||
ItemPushItem(cogItem, laraItem, coll, false, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace TEN::Entities::Traps
|
|||
GlobalCollisionBounds.Z1 = bounds.z;
|
||||
|
||||
if (TestWithGlobalCollisionBounds(item, laraItem, coll))
|
||||
ItemPushItem(item, laraItem, coll, 0, 2);
|
||||
ItemPushItem(item, laraItem, coll, false, 2);
|
||||
}*/
|
||||
|
||||
if (!TestBoundsCollide(item, laraItem, coll->Setup.Radius))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "framework.h"
|
||||
|
||||
#include "Game/items.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/control/lot.h"
|
||||
#include "Game/effects/debris.h"
|
||||
#include "Game/effects/item_fx.h"
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include "Scripting/Internal/TEN/Rotation/Rotation.h"
|
||||
#include "Scripting/Internal/TEN/Vec3/Vec3.h"
|
||||
|
||||
using namespace TEN::Collision::Floordata;
|
||||
using namespace TEN::Effects::Items;
|
||||
|
||||
/***
|
||||
|
@ -576,6 +578,10 @@ void Moveable::SetPos(Vec3 const& pos, sol::optional<bool> updateRoom)
|
|||
SetRoomNumber(potentialNewRoom);
|
||||
}
|
||||
}
|
||||
|
||||
const auto& object = Objects[m_item->ObjectNumber];
|
||||
if (object.floor != nullptr || object.ceiling != nullptr)
|
||||
UpdateBridgeItem((int)m_item->Index);
|
||||
}
|
||||
|
||||
Vec3 Moveable::GetJointPos(int jointIndex) const
|
||||
|
@ -598,11 +604,15 @@ Rotation Moveable::GetRot() const
|
|||
};
|
||||
}
|
||||
|
||||
void Moveable::SetRot(Rotation const& rot)
|
||||
void Moveable::SetRot(const Rotation& rot)
|
||||
{
|
||||
m_item->Pose.Orientation.x = ANGLE(rot.x);
|
||||
m_item->Pose.Orientation.y = ANGLE(rot.y);
|
||||
m_item->Pose.Orientation.z = ANGLE(rot.z);
|
||||
|
||||
const auto& object = Objects[m_item->ObjectNumber];
|
||||
if (object.floor != nullptr || object.ceiling != nullptr)
|
||||
UpdateBridgeItem(m_item->Index);
|
||||
}
|
||||
|
||||
/// Get current HP (hit points/health points)
|
||||
|
|
|
@ -187,8 +187,17 @@ void LoadItems()
|
|||
memcpy(&item->StartPose, &item->Pose, sizeof(Pose));
|
||||
}
|
||||
|
||||
for (int i = 0; i < g_Level.NumItems; i++)
|
||||
InitializeItem(i);
|
||||
// Initialize all bridges first.
|
||||
// It is needed because some other items need final floor height to init properly.
|
||||
|
||||
for (int isFloor = 0; isFloor <= 1; isFloor++)
|
||||
{
|
||||
for (int i = 0; i < g_Level.NumItems; i++)
|
||||
{
|
||||
if ((Objects[g_Level.Items[i].ObjectNumber].floor == nullptr) == (bool)isFloor)
|
||||
InitializeItem(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue