Components/CharctorController.cs
using Sandbox;
using Sandbox.Citizen;
public sealed class CharacterController1 : Component
{
[Property] public float GroundControl { get; set; } = 4.0f;
[Property] public float AirControl { get; set; } = 0.1f;
[Property] public float MaxForce { get; set; } = 50f;
[Property] public float Speed { get; set; } = 160f;
[Property] public float RunSpeed { get; set; } = 290f;
[Property] public float CrouchSpeed { get; set; } = 90f;
[Property] public float JumpForce { get; set; } = 400f;
[Property] public GameObject Head { get; set; }
[Property] public GameObject Body { get; set; }
public Vector3 WishVelocity { get; set; }
public bool IsCrouching = false;
public bool IsSprinting = false;
public bool canUnCrouch = false;
private CharacterController characterController;
private CitizenAnimationHelper animationHelper;
protected override void OnAwake()
{
base.OnAwake();
characterController = Components.Get<CharacterController>();
animationHelper = Components.Get<CitizenAnimationHelper>();
}
protected override void OnUpdate()
{
base.OnUpdate();
UpdateCrouch();
IsSprinting = Input.Down( "Run" );
RotateBody();
if ( Input.Pressed( "Jump" ) ) Jump();
UpdateAnimations();
}
protected override void OnFixedUpdate()
{
base.OnFixedUpdate();
BuildWishVelocity();
Move();
}
void BuildWishVelocity()
{
WishVelocity = 0;
var rot = Head.Transform.Rotation;
if ( Input.Down( "Forward" ) ) WishVelocity += rot.Forward;
if ( Input.Down( "Backward" ) ) WishVelocity += rot.Backward;
if ( Input.Down( "Left" ) ) WishVelocity += rot.Left;
if ( Input.Down( "Right" ) ) WishVelocity += rot.Right;
WishVelocity = WishVelocity.WithZ( 0 );
if ( !WishVelocity.IsNearZeroLength ) WishVelocity = WishVelocity.Normal;
if ( IsCrouching ) WishVelocity *= CrouchSpeed; // Crouching takes presedence over sprinting
else if ( IsSprinting ) WishVelocity *= RunSpeed; // Sprinting takes presedence over walking
else WishVelocity *= Speed;
}
void Move()
{
// Get gravity from our scene
var gravity = Scene.PhysicsWorld.Gravity;
if ( characterController.IsOnGround )
{
// Apply Friction/Acceleration
characterController.Velocity = characterController.Velocity.WithZ( 0 );
characterController.Accelerate( WishVelocity );
characterController.ApplyFriction( GroundControl );
}
else
{
// Apply Air Control / Gravity
characterController.Velocity += gravity * Time.Delta * 0.5f;
characterController.Accelerate( WishVelocity.ClampLength( MaxForce ) );
characterController.ApplyFriction( AirControl );
}
// Move the character controller
characterController.Move();
// Apply the second half of gravity after movement
if ( !characterController.IsOnGround )
{
characterController.Velocity += gravity * Time.Delta * 0.5f;
}
else
{
characterController.Velocity = characterController.Velocity.WithZ( 0 );
}
}
void RotateBody()
{
if ( Body is null ) return;
var targetAngle = new Angles( 0, Head.Transform.Rotation.Yaw(), 0 ).ToRotation();
float rotateDiffrence = Body.Transform.Rotation.Distance( targetAngle );
if ( rotateDiffrence > 10f || characterController.Velocity.Length > 10f )
{
Body.Transform.Rotation = Rotation.Lerp( Body.Transform.Rotation, targetAngle, Time.Delta * 2f );
}
}
void Jump()
{
if ( !characterController.IsOnGround ) return;
characterController.Punch( Vector3.Up * JumpForce );
animationHelper?.TriggerJump();
}
void UpdateAnimations()
{
if(animationHelper is null) return;
animationHelper.WithWishVelocity( WishVelocity );
animationHelper.WithVelocity( characterController.Velocity );
animationHelper.AimAngle = Head.Transform.Rotation;
animationHelper.IsGrounded = characterController.IsOnGround;
animationHelper.WithLook( Head.Transform.Rotation.Forward, 1f, 0.75f, 0.5f );
animationHelper.MoveStyle = CitizenAnimationHelper.MoveStyles.Run;
animationHelper.DuckLevel = IsCrouching ? 1f : 0f;
}
void UpdateCrouch()
{
if ( characterController is null ) return;
if ( Input.Pressed( "Duck" ) && !IsCrouching)
{
IsCrouching = true;
characterController.Height /= 2f;
}
var duckTrace = characterController.TraceDirection( Vector3.Up * characterController.Height );
if ( duckTrace.Hit )
{
canUnCrouch = false;
}
else {
canUnCrouch = true;
}
if ( Input.Released( "Duck" ) && IsCrouching && canUnCrouch ) //| IsCrouching && !Input.Pressed( "Duck" ) && canUnCrouch
{
IsCrouching = false;
characterController.Height *= 2f;
}
if ( IsCrouching && !Input.Down( "Duck" ) && canUnCrouch )
{
IsCrouching = false;
characterController.Height *= 2f;
}
}
}