Code/TopDownPlayerController.cs
using System;
using System.Collections.Specialized;
using System.Linq;
using Sandbox;
using Sandbox.Citizen;

[Title( "Top Down Player Controller" )]
public class TopDownPlayerController : Component
{
    [Property] public CharacterController CharacterController { get; set; }
	[Property] public CitizenAnimationHelper AnimationHelper { get; set; }
	[Property, Group("Speed")] public float Walk { get; set; } = 198f;
	[Property, Group("Speed")] public float Run { get; set; } = 320f;
	[Property, Group("Camera")] public float Distance { get; set; } = 600f;
	[Property, Group("Camera"), Range(0f, 90f)] public float VerticalAxis { get; set; } = 90;
	[Property, Group("Camera"), Range(0f, 360f)] public float HorizontalAxis { get; set; } = 90;

	protected override void OnUpdate()
	{
		
	}

	protected override void OnFixedUpdate()
	{
		base.OnFixedUpdate();
		MovementInput();
		UpdateAnimations();
	}

	protected override void OnPreRender()
	{
		UpdateCamera();
	}


	private void MovementInput()
	{
		if (CharacterController is null) return;

		Angles currentAngles = Transform.Rotation.Angles();	

		Vector3 analogMove = Input.AnalogMove;
		float speed = Input.Down("Run") ? Run : Walk;

		float angleInRadians = MathX.DegreeToRadian(HorizontalAxis);
		float cosAngle = MathF.Cos(angleInRadians);
		float sinAngle = MathF.Sin(angleInRadians);
		Vector3 wishVelocity = new Vector3(
			analogMove.x * cosAngle - analogMove.y * sinAngle,
			analogMove.x * sinAngle + analogMove.y * cosAngle,
			analogMove.z
		).Normal * speed;

		if (!wishVelocity.IsNearlyZero())
		{
			currentAngles.yaw = Rotation.LookAt(wishVelocity).Angles().yaw;
			Transform.Rotation = Rotation.From(currentAngles);
		}
		if (!CharacterController.IsOnGround) {
			wishVelocity += Scene.PhysicsWorld.Gravity;
		}

		CharacterController.Velocity = wishVelocity;
		CharacterController.Move();
		Transform.Rotation = currentAngles;
	}

	private void UpdateAnimations()
	{
		if (AnimationHelper is null) return;

		AnimationHelper.WithVelocity(CharacterController.Velocity);
	}

	private void UpdateCamera()
	{
		CameraComponent camera = Scene.GetAllComponents<CameraComponent>().Where( x => x.IsMainCamera ).FirstOrDefault();
		if ( camera is null || CharacterController is null ) return;

		Vector3 characterPostion = CharacterController.Transform.Position;

		float angleInRadians = MathX.DegreeToRadian(VerticalAxis);
		float verticalCos = MathF.Cos(angleInRadians);
		float verticalSin = MathF.Sin(angleInRadians);

		angleInRadians = MathX.DegreeToRadian(HorizontalAxis);
		float horizontalCos = MathF.Cos(angleInRadians);
		float horizontalSin = MathF.Sin(angleInRadians);

		camera.Transform.Position = new Vector3(
			characterPostion.x - verticalCos * horizontalCos * Distance,
			characterPostion.y - verticalCos * horizontalSin * Distance,
			characterPostion.z + CharacterController.Height + verticalSin * Distance
		);
		camera.Transform.Rotation = new Angles(VerticalAxis, HorizontalAxis, 0);
	}
}