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