Make shuttle brakes use thrusters and bandaid shuttle movement (#9826)

This commit is contained in:
metalgearsloth
2022-07-17 19:36:08 +10:00
committed by GitHub
parent cd7765e7d9
commit 0378a23790
7 changed files with 188 additions and 118 deletions

View File

@@ -13,7 +13,6 @@ namespace Content.Server.Physics.Controllers
public sealed class MoverController : SharedMoverController public sealed class MoverController : SharedMoverController
{ {
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly ShuttleSystem _shuttle = default!;
[Dependency] private readonly ThrusterSystem _thruster = default!; [Dependency] private readonly ThrusterSystem _thruster = default!;
private Dictionary<ShuttleComponent, List<(PilotComponent, InputMoverComponent, TransformComponent)>> _shuttlePilots = new(); private Dictionary<ShuttleComponent, List<(PilotComponent, InputMoverComponent, TransformComponent)>> _shuttlePilots = new();
@@ -233,49 +232,20 @@ namespace Content.Server.Physics.Controllers
{ {
if (Paused(shuttle.Owner) || FTLLocked(shuttle) || !TryComp(shuttle.Owner, out PhysicsComponent? body)) continue; if (Paused(shuttle.Owner) || FTLLocked(shuttle) || !TryComp(shuttle.Owner, out PhysicsComponent? body)) continue;
var shuttleNorthAngle = Transform(body.Owner).WorldRotation;
// Collate movement linear and angular inputs together // Collate movement linear and angular inputs together
var linearInput = Vector2.Zero; var linearInput = Vector2.Zero;
var brakeInput = 0f;
var angularInput = 0f; var angularInput = 0f;
foreach (var (pilot, _, consoleXform) in pilots) foreach (var (pilot, _, consoleXform) in pilots)
{ {
var pilotInput = GetPilotVelocityInput(pilot); var pilotInput = GetPilotVelocityInput(pilot);
// On the one hand we could just make it relay inputs to brake
// but uhh may be disorienting? n
if (pilotInput.Brakes > 0f) if (pilotInput.Brakes > 0f)
{ {
if (body.LinearVelocity.Length > 0f) brakeInput += pilotInput.Brakes;
{
var force = body.LinearVelocity.Normalized * pilotInput.Brakes / body.InvMass * 3f;
var impulse = force * body.InvMass * frameTime;
if (impulse.Length > body.LinearVelocity.Length)
{
body.LinearVelocity = Vector2.Zero;
}
else
{
body.ApplyLinearImpulse(-force * frameTime);
}
}
if (body.AngularVelocity != 0f)
{
var force = body.AngularVelocity * pilotInput.Brakes / body.InvI * 2f;
var impulse = force * body.InvI * frameTime;
if (MathF.Abs(impulse) > MathF.Abs(body.AngularVelocity))
{
body.AngularVelocity = 0f;
}
else
{
body.ApplyAngularImpulse(-force * frameTime);
}
}
continue;
} }
if (pilotInput.Strafe.Length > 0f) if (pilotInput.Strafe.Length > 0f)
@@ -293,12 +263,141 @@ namespace Content.Server.Physics.Controllers
var count = pilots.Count; var count = pilots.Count;
linearInput /= count; linearInput /= count;
angularInput /= count; angularInput /= count;
brakeInput /= count;
/*
* So essentially:
* 1. We do the same calcs for braking as we do for linear thrust so it's similar to a player pressing it
* but we also need to handle when they get close to 0 hence why it sets velocity directly.
*
* 2. We do a similar calculation to mob movement where the closer you are to your speed cap the slower you accelerate
*
* TODO: Could combine braking linear input and thrust more but my brain was just not working debugging
* TODO: Need to have variable speed caps based on thruster count or whatever
*/
// Handle shuttle movement // Handle shuttle movement
if (brakeInput > 0f)
{
if (body.LinearVelocity.Length > 0f)
{
// Get velocity relative to the shuttle so we know which thrusters to fire
var shuttleVelocity = (-shuttleNorthAngle).RotateVec(body.LinearVelocity);
var force = Vector2.Zero;
if (shuttleVelocity.X < 0f)
{
_thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.West);
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.East);
var index = (int) Math.Log2((int) DirectionFlag.East);
force.X += shuttle.LinearThrust[index];
}
else if (shuttleVelocity.X > 0f)
{
_thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.East);
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.West);
var index = (int) Math.Log2((int) DirectionFlag.West);
force.X -= shuttle.LinearThrust[index];
}
if (shuttleVelocity.Y < 0f)
{
_thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.South);
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.North);
var index = (int) Math.Log2((int) DirectionFlag.North);
force.Y += shuttle.LinearThrust[index];
}
else if (shuttleVelocity.Y > 0f)
{
_thruster.DisableLinearThrustDirection(shuttle, DirectionFlag.North);
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South);
var index = (int) Math.Log2((int) DirectionFlag.South);
force.Y -= shuttle.LinearThrust[index];
}
var impulse = force * brakeInput;
var wishDir = impulse.Normalized;
// TODO: Adjust max possible speed based on total thrust in particular direction.
var wishSpeed = 20f;
var currentSpeed = Vector2.Dot(shuttleVelocity, wishDir);
var addSpeed = wishSpeed - currentSpeed;
if (addSpeed > 0f)
{
var accelSpeed = impulse.Length * frameTime;
accelSpeed = MathF.Min(accelSpeed, addSpeed);
impulse = impulse.Normalized * accelSpeed * body.InvMass;
// Cap inputs
if (shuttleVelocity.X < 0f)
{
impulse.X = MathF.Min(impulse.X, -shuttleVelocity.X);
}
else if (shuttleVelocity.X > 0f)
{
impulse.X = MathF.Max(impulse.X, -shuttleVelocity.X);
}
if (shuttleVelocity.Y < 0f)
{
impulse.Y = MathF.Min(impulse.Y, -shuttleVelocity.Y);
}
else if (shuttleVelocity.Y > 0f)
{
impulse.Y = MathF.Max(impulse.Y, -shuttleVelocity.Y);
}
PhysicsSystem.SetLinearVelocity(body, body.LinearVelocity + shuttleNorthAngle.RotateVec(impulse));
}
}
else
{
_thruster.DisableLinearThrusters(shuttle);
}
if (body.AngularVelocity != 0f)
{
var impulse = shuttle.AngularThrust * brakeInput * (body.AngularVelocity > 0f ? -1f : 1f);
var wishSpeed = MathF.PI;
if (impulse < 0f)
wishSpeed *= -1f;
var currentSpeed = body.AngularVelocity;
var addSpeed = wishSpeed - currentSpeed;
if (!addSpeed.Equals(0f))
{
var accelSpeed = impulse * body.InvI * frameTime;
if (accelSpeed < 0f)
accelSpeed = MathF.Max(accelSpeed, addSpeed);
else
accelSpeed = MathF.Min(accelSpeed, addSpeed);
if (body.AngularVelocity < 0f && body.AngularVelocity + accelSpeed > 0f)
accelSpeed = -body.AngularVelocity;
else if (body.AngularVelocity > 0f && body.AngularVelocity + accelSpeed < 0f)
accelSpeed = -body.AngularVelocity;
PhysicsSystem.SetAngularVelocity(body, body.AngularVelocity + accelSpeed);
_thruster.SetAngularThrust(shuttle, true);
}
}
}
if (linearInput.Length.Equals(0f)) if (linearInput.Length.Equals(0f))
{ {
_thruster.DisableLinearThrusters(shuttle); body.SleepingAllowed = true;
body.LinearDamping = _shuttle.ShuttleIdleLinearDamping * body.InvMass;
if (brakeInput.Equals(0f))
_thruster.DisableLinearThrusters(shuttle);
if (body.LinearVelocity.Length < 0.08) if (body.LinearVelocity.Length < 0.08)
{ {
body.LinearVelocity = Vector2.Zero; body.LinearVelocity = Vector2.Zero;
@@ -306,11 +405,10 @@ namespace Content.Server.Physics.Controllers
} }
else else
{ {
body.LinearDamping = 0; body.SleepingAllowed = false;
var angle = linearInput.ToWorldAngle(); var angle = linearInput.ToWorldAngle();
var linearDir = angle.GetDir(); var linearDir = angle.GetDir();
var dockFlag = linearDir.AsFlag(); var dockFlag = linearDir.AsFlag();
var shuttleNorth = EntityManager.GetComponent<TransformComponent>(body.Owner).WorldRotation.ToWorldVec();
var totalForce = new Vector2(); var totalForce = new Vector2();
@@ -335,46 +433,52 @@ namespace Content.Server.Physics.Controllers
continue; continue;
} }
float length; var index = (int) Math.Log2((int) dir);
Angle thrustAngle; var thrust = shuttle.LinearThrust[index];
switch (dir) switch (dir)
{ {
case DirectionFlag.North: case DirectionFlag.North:
length = linearInput.Y; totalForce.Y += thrust;
thrustAngle = new Angle(MathF.PI);
break; break;
case DirectionFlag.South: case DirectionFlag.South:
length = -linearInput.Y; totalForce.Y -= thrust;
thrustAngle = new Angle(0f);
break; break;
case DirectionFlag.East: case DirectionFlag.East:
length = linearInput.X; totalForce.X += thrust;
thrustAngle = new Angle(MathF.PI / 2f);
break; break;
case DirectionFlag.West: case DirectionFlag.West:
length = -linearInput.X; totalForce.X -= thrust;
thrustAngle = new Angle(-MathF.PI / 2f);
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
_thruster.EnableLinearThrustDirection(shuttle, dir); _thruster.EnableLinearThrustDirection(shuttle, dir);
var index = (int) Math.Log2((int) dir);
var force = thrustAngle.RotateVec(shuttleNorth) * shuttle.LinearThrust[index] * length;
totalForce += force;
} }
body.ApplyLinearImpulse(totalForce * frameTime); // We don't want to touch damping if no inputs are given
// so we'll just add an artifical drag to the velocity input.
var shuttleVelocity = (-shuttleNorthAngle).RotateVec(body.LinearVelocity);
var wishDir = totalForce.Normalized;
// TODO: Adjust max possible speed based on total thrust in particular direction.
var wishSpeed = 20f;
var currentSpeed = Vector2.Dot(shuttleVelocity, wishDir);
var addSpeed = wishSpeed - currentSpeed;
if (addSpeed > 0f)
{
var accelSpeed = totalForce.Length * frameTime;
accelSpeed = MathF.Min(accelSpeed, addSpeed);
body.ApplyLinearImpulse(shuttleNorthAngle.RotateVec(totalForce.Normalized * accelSpeed));
}
} }
if (MathHelper.CloseTo(angularInput, 0f)) if (MathHelper.CloseTo(angularInput, 0f))
{ {
_thruster.SetAngularThrust(shuttle, false); _thruster.SetAngularThrust(shuttle, false);
body.AngularDamping = _shuttle.ShuttleIdleAngularDamping * body.InvI;
body.SleepingAllowed = true; body.SleepingAllowed = true;
if (Math.Abs(body.AngularVelocity) < 0.01f) if (Math.Abs(body.AngularVelocity) < 0.01f)
@@ -384,18 +488,28 @@ namespace Content.Server.Physics.Controllers
} }
else else
{ {
body.AngularDamping = 0;
body.SleepingAllowed = false; body.SleepingAllowed = false;
var impulse = shuttle.AngularThrust * -angularInput;
var wishSpeed = MathF.PI;
var maxSpeed = Math.Min(_shuttle.ShuttleMaxAngularMomentum * body.InvI, _shuttle.ShuttleMaxAngularSpeed); if (impulse < 0f)
var maxTorque = body.Inertia * _shuttle.ShuttleMaxAngularAcc; wishSpeed *= -1f;
var torque = Math.Min(shuttle.AngularThrust, maxTorque); var currentSpeed = body.AngularVelocity;
var dragTorque = body.AngularVelocity * (torque / maxSpeed); var addSpeed = wishSpeed - currentSpeed;
body.ApplyAngularImpulse((-angularInput * torque - dragTorque) * frameTime); if (!addSpeed.Equals(0f))
{
var accelSpeed = impulse * body.InvI * frameTime;
_thruster.SetAngularThrust(shuttle, true); if (accelSpeed < 0f)
accelSpeed = MathF.Max(accelSpeed, addSpeed);
else
accelSpeed = MathF.Min(accelSpeed, addSpeed);
PhysicsSystem.SetAngularVelocity(body, body.AngularVelocity + accelSpeed);
_thruster.SetAngularThrust(shuttle, true);
}
} }
} }
} }

View File

@@ -22,7 +22,7 @@ namespace Content.Server.Shuttles.Components
/// <summary> /// <summary>
/// The thrusters contributing to the angular impulse of the shuttle. /// The thrusters contributing to the angular impulse of the shuttle.
/// </summary> /// </summary>
public readonly List<ThrusterComponent> AngularThrusters = new List<ThrusterComponent>(); public readonly List<ThrusterComponent> AngularThrusters = new();
[ViewVariables] [ViewVariables]
public float AngularThrust = 0f; public float AngularThrust = 0f;

View File

@@ -261,8 +261,8 @@ public sealed partial class ShuttleSystem
{ {
body.LinearVelocity = Vector2.Zero; body.LinearVelocity = Vector2.Zero;
body.AngularVelocity = 0f; body.AngularVelocity = 0f;
body.LinearDamping = ShuttleIdleLinearDamping; body.LinearDamping = ShuttleLinearDamping;
body.AngularDamping = ShuttleIdleAngularDamping; body.AngularDamping = ShuttleAngularDamping;
} }
TryComp(comp.Owner, out shuttle); TryComp(comp.Owner, out shuttle);

View File

@@ -21,14 +21,8 @@ namespace Content.Server.Shuttles.Systems
public const float TileMassMultiplier = 0.5f; public const float TileMassMultiplier = 0.5f;
public float ShuttleMaxLinearSpeed; public const float ShuttleLinearDamping = 0.05f;
public const float ShuttleAngularDamping = 0.05f;
public float ShuttleMaxAngularMomentum;
public float ShuttleMaxAngularAcc;
public float ShuttleMaxAngularSpeed;
public float ShuttleIdleLinearDamping;
public float ShuttleIdleAngularDamping;
public override void Initialize() public override void Initialize()
{ {
@@ -47,14 +41,6 @@ namespace Content.Server.Shuttles.Systems
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit); SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
SubscribeLocalEvent<GridFixtureChangeEvent>(OnGridFixtureChange); SubscribeLocalEvent<GridFixtureChangeEvent>(OnGridFixtureChange);
var configManager = IoCManager.Resolve<IConfigurationManager>();
configManager.OnValueChanged(CCVars.ShuttleMaxLinearSpeed, SetShuttleMaxLinearSpeed, true);
configManager.OnValueChanged(CCVars.ShuttleMaxAngularSpeed, SetShuttleMaxAngularSpeed, true);
configManager.OnValueChanged(CCVars.ShuttleIdleLinearDamping, SetShuttleIdleLinearDamping, true);
configManager.OnValueChanged(CCVars.ShuttleIdleAngularDamping, SetShuttleIdleAngularDamping, true);
configManager.OnValueChanged(CCVars.ShuttleMaxAngularAcc, SetShuttleMaxAngularAcc, true);
configManager.OnValueChanged(CCVars.ShuttleMaxAngularMomentum, SetShuttleMaxAngularMomentum, true);
} }
public override void Update(float frameTime) public override void Update(float frameTime)
@@ -71,23 +57,11 @@ namespace Content.Server.Shuttles.Systems
CleanupHyperspace(); CleanupHyperspace();
} }
private void SetShuttleMaxLinearSpeed(float value) => ShuttleMaxLinearSpeed = value;
private void SetShuttleMaxAngularSpeed(float value) => ShuttleMaxAngularSpeed = value;
private void SetShuttleMaxAngularAcc(float value) => ShuttleMaxAngularAcc = value;
private void SetShuttleMaxAngularMomentum(float value) => ShuttleMaxAngularMomentum = value;
private void SetShuttleIdleLinearDamping(float value) => ShuttleIdleLinearDamping = value;
private void SetShuttleIdleAngularDamping(float value) => ShuttleIdleAngularDamping = value;
public override void Shutdown() public override void Shutdown()
{ {
base.Shutdown(); base.Shutdown();
ShutdownEscape(); ShutdownEscape();
ShutdownEmergencyConsole(); ShutdownEmergencyConsole();
_configManager.UnsubValueChanged(CCVars.ShuttleMaxLinearSpeed, SetShuttleMaxLinearSpeed);
_configManager.UnsubValueChanged(CCVars.ShuttleMaxAngularSpeed, SetShuttleMaxAngularSpeed);
_configManager.UnsubValueChanged(CCVars.ShuttleIdleLinearDamping, SetShuttleIdleLinearDamping);
_configManager.UnsubValueChanged(CCVars.ShuttleIdleAngularDamping, SetShuttleIdleAngularDamping);
_configManager.UnsubValueChanged(CCVars.ShuttleMaxAngularMomentum, SetShuttleMaxAngularMomentum);
} }
private void OnShuttleAdd(EntityUid uid, ShuttleComponent component, ComponentAdd args) private void OnShuttleAdd(EntityUid uid, ShuttleComponent component, ComponentAdd args)
@@ -159,8 +133,8 @@ namespace Content.Server.Shuttles.Systems
component.BodyType = BodyType.Dynamic; component.BodyType = BodyType.Dynamic;
component.BodyStatus = BodyStatus.InAir; component.BodyStatus = BodyStatus.InAir;
component.FixedRotation = false; component.FixedRotation = false;
component.LinearDamping = ShuttleIdleLinearDamping; component.LinearDamping = ShuttleLinearDamping;
component.AngularDamping = ShuttleIdleAngularDamping; component.AngularDamping = ShuttleAngularDamping;
} }
private void Disable(PhysicsComponent component) private void Disable(PhysicsComponent component)

View File

@@ -869,23 +869,6 @@ namespace Content.Shared.CCVar
/* /*
* Shuttles * Shuttles
*/ */
public static readonly CVarDef<float> ShuttleMaxLinearSpeed =
CVarDef.Create("shuttle.max_linear_speed", 13f, CVar.SERVERONLY);
public static readonly CVarDef<float> ShuttleMaxAngularSpeed =
CVarDef.Create("shuttle.max_angular_speed", 1.4f, CVar.SERVERONLY);
public static readonly CVarDef<float> ShuttleMaxAngularAcc =
CVarDef.Create("shuttle.max_angular_acc", 2f, CVar.SERVERONLY);
public static readonly CVarDef<float> ShuttleMaxAngularMomentum =
CVarDef.Create("shuttle.max_angular_momentum", 60000f, CVar.SERVERONLY);
public static readonly CVarDef<float> ShuttleIdleLinearDamping =
CVarDef.Create("shuttle.idle_linear_damping", 50f, CVar.SERVERONLY);
public static readonly CVarDef<float> ShuttleIdleAngularDamping =
CVarDef.Create("shuttle.idle_angular_damping", 100f, CVar.SERVERONLY);
/// <summary> /// <summary>
/// Whether cargo shuttles are enabled. /// Whether cargo shuttles are enabled.

View File

@@ -22,18 +22,18 @@ public abstract partial class SharedMoverController
if (_pushingEnabled) if (_pushingEnabled)
{ {
_physics.KinematicControllerCollision += OnMobCollision; PhysicsSystem.KinematicControllerCollision += OnMobCollision;
} }
else else
{ {
_physics.KinematicControllerCollision -= OnMobCollision; PhysicsSystem.KinematicControllerCollision -= OnMobCollision;
} }
} }
private void ShutdownPushing() private void ShutdownPushing()
{ {
if (_pushingEnabled) if (_pushingEnabled)
_physics.KinematicControllerCollision -= OnMobCollision; PhysicsSystem.KinematicControllerCollision -= OnMobCollision;
_configManager.UnsubValueChanged(CCVars.MobPushing, SetPushing); _configManager.UnsubValueChanged(CCVars.MobPushing, SetPushing);
} }

View File

@@ -35,7 +35,6 @@ namespace Content.Shared.Movement.Systems
[Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedMobStateSystem _mobState = default!; [Dependency] private readonly SharedMobStateSystem _mobState = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly TagSystem _tags = default!; [Dependency] private readonly TagSystem _tags = default!;
private const float StepSoundMoveDistanceRunning = 2; private const float StepSoundMoveDistanceRunning = 2;
@@ -131,7 +130,7 @@ namespace Content.Shared.Movement.Systems
touching = ev.CanMove; touching = ev.CanMove;
if (!touching && TryComp<MobMoverComponent>(xform.Owner, out var mobMover)) if (!touching && TryComp<MobMoverComponent>(xform.Owner, out var mobMover))
touching |= IsAroundCollider(_physics, xform, mobMover, physicsComponent); touching |= IsAroundCollider(PhysicsSystem, xform, mobMover, physicsComponent);
} }
if (!touching) if (!touching)
@@ -227,7 +226,7 @@ namespace Content.Shared.Movement.Systems
if (!weightless || touching) if (!weightless || touching)
Accelerate(ref velocity, in worldTotal, accel, frameTime); Accelerate(ref velocity, in worldTotal, accel, frameTime);
_physics.SetLinearVelocity(physicsComponent, velocity); PhysicsSystem.SetLinearVelocity(physicsComponent, velocity);
} }
private void Friction(float minimumFrictionSpeed, float frameTime, float friction, ref Vector2 velocity) private void Friction(float minimumFrictionSpeed, float frameTime, float friction, ref Vector2 velocity)