Rework the way held items scatter when holder is knocked down (#36232)
* Redo drop held items math * Don't assume the holder has a PhysicsComponent * Assume infinite mass for held items with no PhysicsComponent * Switch to EntityQuery for PhysicsComponent * The micro-est of optimizations * use NextAngle * Might as well do that outside the loop
This commit is contained in:
@@ -39,6 +39,15 @@ namespace Content.Server.Hands.Systems
|
||||
[Dependency] private readonly PullingSystem _pullingSystem = default!;
|
||||
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
|
||||
/// <summary>
|
||||
/// Items dropped when the holder falls down will be launched in
|
||||
/// a direction offset by up to this many degrees from the holder's
|
||||
/// movement direction.
|
||||
/// </summary>
|
||||
private const float DropHeldItemsSpread = 45;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -60,6 +69,8 @@ namespace Content.Server.Hands.Systems
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.ThrowItemInHand, new PointerInputCmdHandler(HandleThrowItem))
|
||||
.Register<HandsSystem>();
|
||||
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
@@ -234,13 +245,13 @@ namespace Content.Server.Hands.Systems
|
||||
|
||||
private void OnDropHandItems(Entity<HandsComponent> entity, ref DropHandItemsEvent args)
|
||||
{
|
||||
var direction = EntityManager.TryGetComponent(entity, out PhysicsComponent? comp) ? comp.LinearVelocity / 50 : Vector2.Zero;
|
||||
var dropAngle = _random.NextFloat(0.8f, 1.2f);
|
||||
// If the holder doesn't have a physics component, they ain't moving
|
||||
var holderVelocity = _physicsQuery.TryComp(entity, out var physics) ? physics.LinearVelocity : Vector2.Zero;
|
||||
var spreadMaxAngle = Angle.FromDegrees(DropHeldItemsSpread);
|
||||
|
||||
var fellEvent = new FellDownEvent(entity);
|
||||
RaiseLocalEvent(entity, fellEvent, false);
|
||||
|
||||
var worldRotation = TransformSystem.GetWorldRotation(entity).ToVec();
|
||||
foreach (var hand in entity.Comp.Hands.Values)
|
||||
{
|
||||
if (hand.HeldEntity is not EntityUid held)
|
||||
@@ -255,10 +266,26 @@ namespace Content.Server.Hands.Systems
|
||||
if (!TryDrop(entity, hand, null, checkActionBlocker: false, handsComp: entity.Comp))
|
||||
continue;
|
||||
|
||||
// Rotate the item's throw vector a bit for each item
|
||||
var angleOffset = _random.NextAngle(-spreadMaxAngle, spreadMaxAngle);
|
||||
// Rotate the holder's velocity vector by the angle offset to get the item's velocity vector
|
||||
var itemVelocity = angleOffset.RotateVec(holderVelocity);
|
||||
// Decrease the distance of the throw by a random amount
|
||||
itemVelocity *= _random.NextFloat(1f);
|
||||
// Heavier objects don't get thrown as far
|
||||
// If the item doesn't have a physics component, it isn't going to get thrown anyway, but we'll assume infinite mass
|
||||
itemVelocity *= _physicsQuery.TryComp(held, out var heldPhysics) ? heldPhysics.InvMass : 0;
|
||||
// Throw at half the holder's intentional throw speed and
|
||||
// vary the speed a little to make it look more interesting
|
||||
var throwSpeed = entity.Comp.BaseThrowspeed * _random.NextFloat(0.45f, 0.55f);
|
||||
|
||||
_throwingSystem.TryThrow(held,
|
||||
_random.NextAngle().RotateVec(direction / dropAngle + worldRotation / 50),
|
||||
0.5f * dropAngle * _random.NextFloat(-0.9f, 1.1f),
|
||||
entity, 0);
|
||||
itemVelocity,
|
||||
throwSpeed,
|
||||
entity,
|
||||
pushbackRatio: 0,
|
||||
compensateFriction: false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user