Move Eye Lerping to content and fix/improve it a bunch. (#5900)
This commit is contained in:
committed by
GitHub
parent
b0bdc0336e
commit
525c38b794
123
Content.Client/Eye/EyeLerpingSystem.cs
Normal file
123
Content.Client/Eye/EyeLerpingSystem.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Physics;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Client.Eye;
|
||||||
|
|
||||||
|
public class EyeLerpingSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
|
private Angle? _lastGridAngle;
|
||||||
|
private Angle? _lerpTo;
|
||||||
|
private Angle _lerpStartRotation;
|
||||||
|
private float _accumulator;
|
||||||
|
|
||||||
|
// How fast the camera rotates in radians / s
|
||||||
|
private const float CameraRotateSpeed = MathF.PI;
|
||||||
|
|
||||||
|
// Safety override
|
||||||
|
private const float LerpTimeMax = 1.5f;
|
||||||
|
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
UpdatesAfter.Add(typeof(TransformSystem));
|
||||||
|
UpdatesAfter.Add(typeof(PhysicsSystem));
|
||||||
|
UpdatesBefore.Add(typeof(EyeUpdateSystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FrameUpdate(float frameTime)
|
||||||
|
{
|
||||||
|
if (!_gameTiming.IsFirstTimePredicted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var currentEye = _eyeManager.CurrentEye;
|
||||||
|
|
||||||
|
if (_playerManager.LocalPlayer?.ControlledEntity is not {} mob || Deleted(mob))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We can't lerp if the mob can't move!
|
||||||
|
if (!TryComp(mob, out IMoverComponent? mover))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var moverLastGridAngle = mover.LastGridAngle;
|
||||||
|
|
||||||
|
// Let's not turn the camera into a washing machine when the game starts.
|
||||||
|
if (_lastGridAngle == null)
|
||||||
|
{
|
||||||
|
_lastGridAngle = moverLastGridAngle;
|
||||||
|
currentEye.Rotation = -moverLastGridAngle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the last lerp grid angle we have is not the same as the last mover grid angle...
|
||||||
|
if (!_lastGridAngle.Value.EqualsApprox(moverLastGridAngle))
|
||||||
|
{
|
||||||
|
// And now, we start lerping.
|
||||||
|
_lerpTo = moverLastGridAngle;
|
||||||
|
_lastGridAngle = moverLastGridAngle;
|
||||||
|
_lerpStartRotation = currentEye.Rotation;
|
||||||
|
_accumulator = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lerpTo != null)
|
||||||
|
{
|
||||||
|
_accumulator += frameTime;
|
||||||
|
|
||||||
|
var lerpRot = -_lerpTo.Value.FlipPositive().Reduced();
|
||||||
|
var startRot = _lerpStartRotation.FlipPositive().Reduced();
|
||||||
|
|
||||||
|
var changeNeeded = Angle.ShortestDistance(startRot, lerpRot);
|
||||||
|
|
||||||
|
if (changeNeeded.EqualsApprox(Angle.Zero))
|
||||||
|
{
|
||||||
|
// Nothing to do here!
|
||||||
|
CleanupLerp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get how much the camera should have moved by now. Make it faster depending on the change needed.
|
||||||
|
var changeRot = (CameraRotateSpeed * Math.Max(1f, Math.Abs(changeNeeded) * 0.75f)) * _accumulator * Math.Sign(changeNeeded);
|
||||||
|
|
||||||
|
// How close is this from reaching the end?
|
||||||
|
var percentage = (float)Math.Abs(changeRot / changeNeeded);
|
||||||
|
|
||||||
|
currentEye.Rotation = Angle.Lerp(startRot, lerpRot, percentage);
|
||||||
|
|
||||||
|
// Either we have overshot, or we have taken way too long on this, emergency reset time
|
||||||
|
if (percentage >= 1.0f || _accumulator >= LerpTimeMax)
|
||||||
|
{
|
||||||
|
CleanupLerp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CleanupLerp()
|
||||||
|
{
|
||||||
|
currentEye.Rotation = -_lerpTo.Value;
|
||||||
|
_lerpStartRotation = currentEye.Rotation;
|
||||||
|
_lerpTo = null;
|
||||||
|
_accumulator = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This makes it so rotating the camera manually is impossible...
|
||||||
|
// However, it is needed. Why? Because of a funny (hilarious, even) race condition involving
|
||||||
|
// ghosting, this system listening for attached mob changes, and the eye rotation being reset after our
|
||||||
|
// changes back to zero because of an EyeComponent state coming from the server being applied.
|
||||||
|
// At some point we'll need to come up with a solution for that. But for now, I just want to fix this.
|
||||||
|
currentEye.Rotation = -moverLastGridAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ using Content.Shared.Pulling.Components;
|
|||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
|
|
||||||
namespace Content.Client.Physics.Controllers
|
namespace Content.Client.Physics.Controllers
|
||||||
@@ -19,11 +20,15 @@ namespace Content.Client.Physics.Controllers
|
|||||||
|
|
||||||
if (_playerManager.LocalPlayer?.ControlledEntity is not {Valid: true} player ||
|
if (_playerManager.LocalPlayer?.ControlledEntity is not {Valid: true} player ||
|
||||||
!EntityManager.TryGetComponent(player, out IMoverComponent? mover) ||
|
!EntityManager.TryGetComponent(player, out IMoverComponent? mover) ||
|
||||||
!EntityManager.TryGetComponent(player, out PhysicsComponent? body))
|
!EntityManager.TryGetComponent(player, out PhysicsComponent? body) ||
|
||||||
|
!EntityManager.TryGetComponent(player, out TransformComponent? xform))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xform.GridID != GridId.Invalid)
|
||||||
|
mover.LastGridAngle = GetParentGridAngle(xform, mover);
|
||||||
|
|
||||||
// Essentially we only want to set our mob to predicted so every other entity we just interpolate
|
// Essentially we only want to set our mob to predicted so every other entity we just interpolate
|
||||||
// (i.e. only see what the server has sent us).
|
// (i.e. only see what the server has sent us).
|
||||||
// The exception to this is joints.
|
// The exception to this is joints.
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace Content.Shared.Movement.Components
|
|||||||
|
|
||||||
private MoveButtons _heldMoveButtons = MoveButtons.None;
|
private MoveButtons _heldMoveButtons = MoveButtons.None;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
public Angle LastGridAngle { get; set; } = new(0);
|
public Angle LastGridAngle { get; set; } = new(0);
|
||||||
|
|
||||||
public float CurrentWalkSpeed => _movementSpeed?.CurrentWalkSpeed ?? MovementSpeedModifierComponent.DefaultBaseWalkSpeed;
|
public float CurrentWalkSpeed => _movementSpeed?.CurrentWalkSpeed ?? MovementSpeedModifierComponent.DefaultBaseWalkSpeed;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Shared.Friction;
|
|||||||
using Content.Shared.MobState.Components;
|
using Content.Shared.MobState.Components;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Pulling.Components;
|
using Content.Shared.Pulling.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -60,6 +61,14 @@ namespace Content.Shared.Movement
|
|||||||
UsedMobMovement.Clear();
|
UsedMobMovement.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Angle GetParentGridAngle(TransformComponent xform, IMoverComponent mover)
|
||||||
|
{
|
||||||
|
if (xform.GridID == GridId.Invalid || !_mapManager.TryGetGrid(xform.GridID, out var grid))
|
||||||
|
return mover.LastGridAngle;
|
||||||
|
|
||||||
|
return grid.WorldRotation;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A generic kinematic mover for entities.
|
/// A generic kinematic mover for entities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -68,7 +77,7 @@ namespace Content.Shared.Movement
|
|||||||
var (walkDir, sprintDir) = mover.VelocityDir;
|
var (walkDir, sprintDir) = mover.VelocityDir;
|
||||||
|
|
||||||
var transform = EntityManager.GetComponent<TransformComponent>(mover.Owner);
|
var transform = EntityManager.GetComponent<TransformComponent>(mover.Owner);
|
||||||
var parentRotation = transform.Parent!.WorldRotation;
|
var parentRotation = GetParentGridAngle(transform, mover);
|
||||||
|
|
||||||
// Regular movement.
|
// Regular movement.
|
||||||
// Target velocity.
|
// Target velocity.
|
||||||
@@ -118,7 +127,7 @@ namespace Content.Shared.Movement
|
|||||||
if (!touching)
|
if (!touching)
|
||||||
{
|
{
|
||||||
if (transform.GridID != GridId.Invalid)
|
if (transform.GridID != GridId.Invalid)
|
||||||
mover.LastGridAngle = transform.Parent!.WorldRotation;
|
mover.LastGridAngle = GetParentGridAngle(transform, mover);
|
||||||
|
|
||||||
transform.WorldRotation = physicsComponent.LinearVelocity.GetDir().ToAngle();
|
transform.WorldRotation = physicsComponent.LinearVelocity.GetDir().ToAngle();
|
||||||
return;
|
return;
|
||||||
@@ -130,7 +139,7 @@ namespace Content.Shared.Movement
|
|||||||
// This is relative to the map / grid we're on.
|
// This is relative to the map / grid we're on.
|
||||||
var total = walkDir * mover.CurrentWalkSpeed + sprintDir * mover.CurrentSprintSpeed;
|
var total = walkDir * mover.CurrentWalkSpeed + sprintDir * mover.CurrentSprintSpeed;
|
||||||
|
|
||||||
var parentRotation = transform.Parent!.WorldRotation;
|
var parentRotation = GetParentGridAngle(transform, mover);
|
||||||
|
|
||||||
var worldTotal = _relativeMovement ? parentRotation.RotateVec(total) : total;
|
var worldTotal = _relativeMovement ? parentRotation.RotateVec(total) : total;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user