A camera behaviour used before a race starts. It cycles through available CameraMarker entities while the game mode is WaitingForPlayers and returns interpolated CameraPose with configurable cycle duration and field of view.
using Machines.GameModes;
namespace Machines.Components;
/// <summary>
/// Pre-race camera that cycles through all CameraMarkers in the scene while waiting for players to join.
/// </summary>
public sealed class PreRaceCamera : CameraBehaviour
{
/// <summary>
/// Seconds to dwell on each marker before cycling to the next.
/// </summary>
[Property, Group( "Cycling" )]
public float CycleDuration { get; set; } = 3f;
[Property, Group( "Framing" )]
public float FieldOfView { get; set; } = 60f;
public override int Priority => 10;
public override bool WantsControl =>
BaseGameMode.Current.IsValid()
&& BaseGameMode.Current.State == GameModeState.WaitingForPlayers
&& CameraMarker.All.Count > 0;
private int _currentIndex = -1;
private TimeSince _timeSinceCycle;
private CameraMarker _currentMarker;
public override void OnActivated( CameraPose from )
{
_currentIndex = -1;
_timeSinceCycle = CycleDuration; // force an immediate pick
CycleToNext();
}
public override CameraPose Evaluate( CameraPose current )
{
if ( CameraMarker.All.Count == 0 )
return current;
if ( _timeSinceCycle >= CycleDuration )
CycleToNext();
if ( !_currentMarker.IsValid() )
return current;
var t = MathX.Clamp( _timeSinceCycle / CycleDuration, 0f, 1f );
_currentMarker.Evaluate( t, out var position, out var rotation );
return new CameraPose( position, rotation, FieldOfView );
}
private void CycleToNext()
{
if ( CameraMarker.All.Count == 0 )
return;
_currentIndex = (_currentIndex + 1) % CameraMarker.All.Count;
_currentMarker = CameraMarker.All[_currentIndex];
_timeSinceCycle = 0f;
}
}