GudeMovement.cs
using Sandbox;
using System;
using System.Collections;
using System.Security.Cryptography.X509Certificates;


public sealed class GudeMovement : Component
{
	
	
	[Property] public GameObject Body { get; set; } // will reference the player game object (ball)
	[Property] public CameraComponent Camera { get; set; } // will reference the player's camera
	[Property] public Rigidbody Rigidbody { get; set; }// will reference the player's rigid body

	/// <summary>
	/// Gravity on the ball
	/// </summary>
	[Property] public float Gravity { get; set; } = 9f; //gravity on the ball

	/// <summary>
	/// Multiplier to increase jump height
	/// </summary>
	[Property] public float JumpForce { get; set; } = 8.0f; //multiplier to increase jump height

	/// <summary>
	/// Multiplier to drift the ball in the air
	/// </summary>
	[Property] public float DirectionalInfluence { get; set; } = 2.0f; //Multiplier to drift the ball in the air

	/// <summary>
	/// Multiplier to increase force of roll
	/// </summary>
	[Property] public float RollingForce = 45.0f; // multiplier to increase force of roll

	/// <summary>
	/// Radius of your ball, (default 34) change this manually!
	/// </summary>
	[Property] public float Radius { get; set; } = 34.0f;

	/// <summary>
	/// Plays when pressing jump!
	/// </summary>
	[Property] public SoundEvent JumpSound { get; set; } // will reference assigned jump sound
	[Property] public SoundEvent RollSound { get; set; } // will reference assigned roll sound
	SoundHandle rollSound;
	[Property] public SoundEvent LevelMusic { get; set; } // will reference assigned level music
	public SoundHandle levelMusic;

	public bool Spawned { get; set; } = true;

	/*
	private float endVolume = 1f;
	private float startVolume = 0.1f;
	private float desiredDuration = 2f;
	private float elapsedTime;
	*/
	protected override void OnAwake()
	{
		if ( !levelMusic.IsValid() )
		{
			levelMusic = Sound.Play( LevelMusic );
		}
	}

	protected override void OnUpdate()
	{
		var canJump = false;

		var Ball = Body.WorldPosition;

		// gravity apply
		Rigidbody.ApplyForce( new Vector3(0, 0, - (Gravity * 100f) ) );

		// trace to check for floor
		var floorTrace = Scene.Trace.Ray( Ball, new Vector3(Ball.x, Ball.y, Ball.z - 34.0f) )
			.WithoutTags( "player", "trigger" )
			.Size(30f)
			.Run();

		if ( floorTrace.Hit )
		{
			canJump = true;
		}

		ApplyRigidBodyTorqueRelativeToCamera( Input.AnalogMove.x, Input.AnalogMove.y, canJump );

		JumpFunction( Input.AnalogMove.x, Input.AnalogMove.y, canJump );
		
	}

	private void ApplyRigidBodyTorqueRelativeToCamera( float inputX, float inputY, bool canJump )
	{
		var camera = Camera;

		var cameraRotation = camera.WorldRotation;

		var speed = Rigidbody.AngularVelocity.Length;

		if ( !rollSound.IsValid() )
		{
			rollSound = Sound.Play( RollSound, Body.WorldPosition);
		}

		// get the forward vector of the camera
		var forwardVector = cameraRotation.Forward;

		// get the right vector of the camera
		var rightVector = cameraRotation.Right;

		// calculate the torque based on the input and the camera rotation
		var torque = rightVector * -inputX + forwardVector * -inputY;

		var forwardRelative = forwardVector * inputX;
		var rightRelative = rightVector * inputY;

		var moveDir = forwardRelative - rightRelative;

		// try to slow down the rotation *deprecated, use angular damping*
		//Rigidbody.AngularVelocity = Rigidbody.AngularVelocity.LerpTo( Vector3.Zero, Time.Delta * 0.5f );

		// apply the torque to the rigidbody
		Rigidbody.ApplyTorque( torque * RollingForce * 1000f);

		// Directional influence in the air
		Vector3 directionalInfluence = new Vector3( moveDir.x * DirectionalInfluence, moveDir.y * DirectionalInfluence, 0 );

		//float percentageComplete = 0f;

		if ( canJump == true && speed != 0 )
		{
			rollSound.Position = Body.WorldPosition;

			rollSound.Volume = Math.Clamp( speed/RollingForce, 0, 1 );

			/*
			elapsedTime += Time.Delta;

			percentageComplete = elapsedTime / desiredDuration;

			rollSound.Position = Body.WorldPosition;

			rollSound.Volume = MathX.Lerp( startVolume, endVolume, percentageComplete );
			*/
		}
		
		else
		{
			//elapsedTime = 0;

			rollSound.Stop();
		}

		if ( canJump == false )
		{
			Rigidbody.ApplyForce( directionalInfluence );
		}
		
	}

	private void JumpFunction( float inputX, float inputY, bool canJump)
	{

		var camera = Camera;

		var cameraRotation = camera.WorldRotation;

		// get the forward vector of the camera
		var forwardVector = cameraRotation.Forward;

		// get the right vector of the camera
		var rightVector = cameraRotation.Right;

		// make the vectors align linearly
		var forwardRelative = forwardVector * inputX;
		var rightRelative = rightVector * inputY;

		var moveDir = forwardRelative - rightRelative;

		// this is the jumping sum
		Vector3 jumpVector = new Vector3( moveDir.x * 2000f, moveDir.y * 2000f, JumpForce * 10000f );


		if ( Input.Pressed( "Jump" ) && canJump == true)
		{
			Rigidbody.ApplyForce( jumpVector );

			Sound.Play( JumpSound, Body.WorldPosition);

			canJump = false;
			
		}

	}
	protected override void OnDestroy()
	{
		base.OnDestroy();
		if ( rollSound.IsValid() )
		{
			rollSound.Stop();
		}
	}

}