Sim speed: one SimClock steps the zone; presenters draw ahead by Lead

SimClock (engine-free) turns real frame seconds into whole fixed steps; ActionGameManager.Update feeds it outside the pause gate and Zone.Update(Time.deltaTime) is gone, with IntroCutscene (dead, Unity-driven pose writes). Entity.TurnRate is the sum of the rotation actuators' applied turn per sim second, zeroed each Update; DrawAhead reads it so EntityInstance and ShipInstance draw the latest sim state ahead by Lead. Unverified at this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-08 18:26:02 +02:00
commit c4bd6e153e
11 changed files with 393 additions and 40 deletions

View file

@ -177,8 +177,6 @@ public class ActionGameManager : MonoBehaviour
public Sprite ShieldIcon;
public Sprite NoShieldIcon;
public float IntroDuration;
//public PlayerInput Input;
// private CinemachineFramingTransposer _transposer;
@ -231,6 +229,7 @@ public class ActionGameManager : MonoBehaviour
public ItemManager ItemManager { get; private set; }
public Zone Zone { get; private set; }
public static SimClock Clock { get; private set; }
private readonly (float2 direction, string name)[] _directions = {
(float2(0, 1), "Front"),
@ -728,6 +727,7 @@ public class ActionGameManager : MonoBehaviour
galaxyZone.Contents = new Zone(ItemManager, Settings.PlanetSettings, galaxyZone.PackedContents, galaxyZone, CurrentGalaxy);
}
Zone = galaxyZone.Contents;
Clock = new SimClock(1f / 60f);
PlayMusic(MusicType.Overworld);
Zone.Log = s => Debug.Log($"Zone: {s}");
@ -818,7 +818,6 @@ public class ActionGameManager : MonoBehaviour
}
else
{
//StartCoroutine(IntroCutscene(targetEntity as Ship));
BindToEntity(targetEntity);
}
@ -866,35 +865,6 @@ public class ActionGameManager : MonoBehaviour
BindToEntity(staged.Player);
}
private IEnumerator IntroCutscene(Ship ship)
{
ZoneRenderer.PerspectiveEntity = ship;
var entityPosition = ship.Position.xz;
var followOrbit = Zone.Orbits.Keys.MinBy(o => lengthsq(Zone.GetOrbitPosition(o) - entityPosition));
var followPlanet = ZoneRenderer.Planets[Zone.Planets.FirstOrDefault(p => p.Value.Orbit.Key.Equals(followOrbit)).Key];
DockCamera.Follow = followPlanet.Body.transform;
var rootOrbit = followOrbit;
while (Zone.Orbits[rootOrbit].Data.Parent.IsSet())
rootOrbit = Zone.Orbits[rootOrbit].Data.Parent.Key;
var rootPlanet = ZoneRenderer.Planets[Zone.Planets.FirstOrDefault(p => p.Value.Orbit.Key.Equals(rootOrbit)).Key];
DockCamera.LookAt = rootPlanet.Body.transform;
var shipVelocity = ship.GetBehavior<VelocityLimit>().Limit;
var followOrbitPosition = Zone.GetOrbitPosition(followOrbit);
var shipDirection = normalize(Zone.GetOrbitPosition(rootOrbit) - followOrbitPosition);
ship.Position.xz = followOrbitPosition - shipDirection * shipVelocity * IntroDuration;
var startTime = Time.time;
while (Time.time - startTime < IntroDuration)
{
ship.Direction = shipDirection;
ship.Velocity = shipDirection * shipVelocity;
yield return null;
}
BindToEntity(ship);
}
public void Dock()
{
if (CurrentEntity.Parent != null) return;
@ -1356,8 +1326,9 @@ public class ActionGameManager : MonoBehaviour
CurrentEntity.TractorPower =
saturate(CurrentEntity.TractorPower + sign(tractorPower - CurrentEntity.TractorPower) * Time.deltaTime * 2);
}
Zone.Update(Time.deltaTime);
}
// One clock steps the zone, paused or not: a paused frame feeds it no real time.
Clock.Advance(_paused ? 0f : Time.deltaTime, Zone.Update);
}
private static string ResultLabel(ShotResult result) => result switch

View file

@ -416,9 +416,10 @@ public class EntityInstance : MonoBehaviour
var direction = FireControl.Solution(weapon, Entity, Entity.Target.Value).Direction;
group.Value.position = barrel + new Vector3(direction.x, 0, direction.y) * aimDistance;
}
LocalSpace.localPosition = transform.position = Entity.Position.ToUnity();
var drawn = DrawAhead.Position(Entity, ActionGameManager.Clock.Lead);
LocalSpace.localPosition = transform.position = drawn.ToUnity();
if (_influenceInstance)
_influenceInstance.position = new Vector3(Entity.Position.x, 0, Entity.Position.z);
_influenceInstance.position = new Vector3(drawn.x, 0, drawn.z);
}
public virtual void OnDestroy()

View file

@ -138,6 +138,6 @@ public class ShipInstance : EntityInstance
emissionModule.rateOverTimeMultiplier = thrusterInstance.BaseEmission * thrusterInstance.Thruster.Axis * thrusterInstance.Thruster.Condition;
}
transform.rotation = Ship.Rotation.ToUnity();
transform.rotation = DrawAhead.Rotation(Ship, ActionGameManager.Clock.Lead).ToUnity();
}
}