Park/Rides/FlatRides/BumperCarsRide.cs
using HC3;
using System;
public sealed class BumperCarsRide : BasicRide
{
[Property] public List<GameObject> Carts { get; set; } = new();
[Property] Vector3 PlayAreaSize { get; set; } = new Vector3( 40, 20, 10 );
private Dictionary<GameObject, Vector3> cartVelocities = new();
private float speed = 80f;
private float radius = 20.5f;
protected override void DrawGizmos()
{
base.DrawGizmos();
Gizmo.Draw.LineBBox( BBox.FromPositionAndSize( WorldPosition, PlayAreaSize ) );
Gizmo.Draw.Color = Color.Red.WithAlpha( 0.5f );
Gizmo.Draw.SolidBox( BBox.FromPositionAndSize( WorldPosition, PlayAreaSize ) );
foreach ( var cart in Carts )
{
if ( !cart.IsValid() ) continue;
Gizmo.Draw.Color = Color.Blue.WithAlpha( 0.5f );
Gizmo.Draw.SolidSphere( cart.WorldPosition, radius * 2 );
}
}
protected override void OnUpdate()
{
base.OnUpdate();
if ( !RideStarted ) return;
var nextPositions = new Dictionary<GameObject, Vector3>();
foreach ( var cart in Carts )
{
if ( !cart.IsValid() ) continue;
var velocity = cartVelocities.GetValueOrDefault( cart, Vector3.Random.Normal.WithZ( 0 ) * speed );
var newPos = cart.WorldPosition + velocity * Time.Delta;
var local = newPos - WorldPosition;
var half = PlayAreaSize / 2;
// Bounce off walls
if ( MathF.Abs( local.x ) > half.x )
{
velocity.x *= -1;
local.x = MathF.Sign( local.x ) * half.x;
Sound.Play( "bumper_car_hit_01", newPos );
}
if ( MathF.Abs( local.y ) > half.y )
{
velocity.y *= -1;
local.y = MathF.Sign( local.y ) * half.y;
}
newPos = WorldPosition + local;
cartVelocities[cart] = velocity;
nextPositions[cart] = newPos;
}
for ( int i = 0; i < Carts.Count; i++ )
{
for ( int j = i + 1; j < Carts.Count; j++ )
{
var a = Carts[i];
var b = Carts[j];
if ( !a.IsValid() || !b.IsValid() ) continue;
var posA = nextPositions[a];
var posB = nextPositions[b];
var delta = posB - posA;
var distSq = delta.WithZ( 0 ).LengthSquared;
var minDist = radius * 2;
if ( distSq < minDist * minDist && distSq > 0.01f )
{
// Basic bounce: swap velocity
var vA = cartVelocities[a];
var vB = cartVelocities[b];
cartVelocities[a] = vB;
cartVelocities[b] = vA;
}
}
}
foreach ( var cart in Carts )
{
if ( !cart.IsValid() ) continue;
cart.WorldPosition = nextPositions[cart];
cart.WorldRotation = cart.WorldRotation.LerpTo( Rotation.LookAt( cartVelocities[cart].Normal, Vector3.Up ), Time.Delta * 10f );
}
}
protected override void OnRideStarted()
{
base.OnRideStarted();
cartVelocities.Clear();
foreach ( var cart in Carts )
{
if ( !cart.IsValid() ) continue;
var dir = Vector3.Random.Normal.WithZ( 0 ).Normal;
cartVelocities[cart] = dir * speed;
}
}
}