components/player_controller.cs

Player controller component. Reads input, moves a CharacterController, applies gravity and jumping, toggles third/first person, positions the camera, traces for third-person camera clipping, and updates model visibility and FOV.

NetworkingFile Access
using Sandbox;

public class Player__Controller : Component
{ PhysicsWorld Physics_World = new PhysicsWorld();
	[Property] public CharacterController Character_Controller {get;set;}
	[Property] public ModelRenderer Model_Renderer {get;set;}
	
	[Property] public float Walk_Speed {get;set;} = 8192;
	[Property] public float Run_Speed {get;set;} = 16384;
	[Property] public float Duck_Speed {get;set;} = 4096;
	[Property] public float Jump_Power {get;set;} = 200;
	[Property] public float Camera_Offset {get;set;} = 64;
	
	GameObject c;
	protected override void OnStart()
	{c = Scene.Camera.GameObject;}
		
	float w;
	float a;
	float s;
	float d;
	
	float Speed;
	
	float x;
	float y;
	
	[Sync] public bool IsThirdPerson {get;set;}
	
	public string State
	{
		get
		{
			if (Character_Controller.Velocity.WithX(0).WithY(0).LengthSquared > 0)
			{
				if (Character_Controller.Velocity.z > 0)
					return "jump";
				return "fall";
			}
			
			if (Character_Controller.Velocity.WithZ(0).LengthSquared > 0)
			{
				if (Input.Down("shift"))
					return "run";
				return "walk";
			}
		return "idle"; }
	}
	
	public bool IsDucking {get {return Input.Down("ctrl");}}
	public float Offset {get {return IsDucking ? Camera_Offset / 2 : Camera_Offset;}}
	public Vector3 Aim {get {return new Angles(-y, 0, 0).Forward;}}
	
	protected override void OnUpdate()
	{ Visibility(); if (IsProxy) return;
		Control(); Camera(); }
	
	void Control()
	{
		w = Input.Down("w") ? 1 : 0;
		a = Input.Down("a") ? -1 : 0;
		s = Input.Down("s") ? -1 : 0;
		d = Input.Down("d") ? 1 : 0;
		
		if (Input.Down("ctrl"))
			Speed = Duck_Speed;
		else if (Input.Down("shift"))
			Speed = Run_Speed;
		else Speed = Walk_Speed;
		
		var Forward = new Vector3(c.WorldRotation.Forward.x, c.WorldRotation.Forward.y, 0).Normal;
		var Right = new Vector3(c.WorldRotation.Right.x, c.WorldRotation.Right.y, 0).Normal;
		
		var Direction = (w * Forward + s * Forward + a * Right + d * Right).Normal * Time.Delta * Speed;
		Character_Controller.Velocity = Character_Controller.Velocity.WithX(Direction.x).WithY(Direction.y);
		Character_Controller.Velocity += Physics_World.Gravity * Time.Delta;
		
		if (Input.Pressed("space") && Character_Controller.IsOnGround)
			Character_Controller.Punch(Vector3.Zero.WithZ(Jump_Power));
		
		if (Input.Pressed("x"))
			IsThirdPerson = !IsThirdPerson;
	Character_Controller.Move(); Character_Controller.Height = Offset; }
	
	void Camera()
	{
		var Delta = Input.MouseDelta * Time.Delta * Preferences.Sensitivity;
		x = (x + Delta.x) % 360;
		y = (y - Delta.y).Clamp(-89f, 89f);
		
		c.WorldPosition = WorldPosition + Vector3.Zero.WithZ(Offset); c.WorldRotation = new Angles(-y, -x, 0);
		WorldRotation = new Angles(WorldRotation.Pitch(), c.WorldRotation.Yaw(), WorldRotation.Roll());
		
		if (IsThirdPerson)
		{ c.WorldPosition += c.WorldRotation * Vector3.Zero.WithX(-64);
			SceneTraceResult Ray = Scene.Trace
			.Ray(WorldPosition + Vector3.Zero.WithZ(Offset), c.WorldPosition)
			.IgnoreGameObject(GameObject).Run();
			
			if (Ray.Hit)
				c.WorldPosition = Ray.HitPosition;
		}
	c.GetComponent<CameraComponent>().FieldOfView = Preferences.FieldOfView; }
	
	void Visibility()
	{
		if (IsProxy || IsThirdPerson) {Model_Renderer.RenderType = ModelRenderer.ShadowRenderType.On; return;}
		Model_Renderer.RenderType = ModelRenderer.ShadowRenderType.ShadowsOnly;
	}
}