JumpPad.cs

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 );
			}
		}
	}
}