A jump pad component. Watches for trigger contact and launches the touching player's CharacterController or a Rigidbody upward along the pad's up/forward direction, plays a bounce sound and shakes the player camera.
using Sandbox;
using System;
public sealed class JumpPad : Component, Component.ITriggerListener
{
[Property] public float LaunchForce { get; set; } = 1050f;
[Property] public float ForwardBoost { get; set; } = 200f;
[Property] public string BounceSound { get; set; } = "music/buttonhover.sound";
[Property] public bool IsGhostPlaced { get; set; } = false;
[Sync] private TimeSince _timeSinceBounce { get; set; } = 1f;
public void OnTriggerEnter( Collider other )
{
if ( !other.GameObject.IsValid() ) return;
var root = other.GameObject.Root;
if ( root == GameObject.Root ) return;
if ( _timeSinceBounce < 0.25f ) return;
_timeSinceBounce = 0f;
bool launched = false;
Vector3 launchDir = ( WorldRotation.Up + WorldRotation.Forward * ( ForwardBoost / MathF.Max( 1f, LaunchForce ) ) ).Normal;
var cc = root.Components.Get<CharacterController>() ?? root.Components.GetInChildren<CharacterController>();
if ( cc.IsValid() )
{
var vel = cc.Velocity;
vel.z = 0;
cc.Velocity = vel + launchDir * LaunchForce;
launched = true;
var playerCam = root.Components.GetInChildren<CameraJuice>();
playerCam?.Shake( 16f, 4f );
}
var rb = root.Components.Get<Rigidbody>() ?? root.Components.GetInChildren<Rigidbody>();
if ( rb.IsValid() )
{
rb.Velocity = Vector3.Zero;
rb.ApplyImpulse( launchDir * LaunchForce * 45f );
launched = true;
}
if ( launched )
{
if ( !string.IsNullOrEmpty( BounceSound ) )
{
Sound.Play( BounceSound, WorldPosition );
}
}
}
}