Relevant to this issue are two MonoBehaviour scripts: Actor and Player. Actor handles velocity, movement, things like that. Player uses inputs to control an Actor component. This is the code (note that functionality unrelated to movement has been removed for clarity):
// Actor.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class Actor : MonoBehaviour
{
// *snip*
//public UpdateVector3 isDirection
called once per frame{
void Update() get
{
if (controller.isGrounded) return _direction;
{}
set
Vector3 planarTarget = new Vector3(_direction.x,{
0, _direction = value.z);normalized;
}
if}
(planarTarget.sqrMagnitude > 0.01f) public Vector3 Velocity
{
{get
{
Quaternion targetRot = Quaternion.LookRotation(planarTarget); return _velocity;
}
transform.rotationset
= Quaternion.RotateTowards(transform.rotation, targetRot, 600.0f * Time.deltaTime); {
}_velocity = value;
}
}
Accelerate(refpublic _velocity.x,float refacceleration _direction.x);= 48;
public float deceleration = Accelerate(ref56;
_velocity.z, ref _direction.z);
public float skidAcceleration = 72;
public float topSpeed = Decelerate(ref5;
_velocity.x, ref _direction.x); private CharacterController controller;
private Vector3 _direction;
Decelerate(ref _velocity.z, refprivate _direction.z);Vector3 _velocity;
// Start is called ifbefore the first frame update
void Start(!controller.isGrounded)
{
{controller = gameObject.GetComponent<CharacterController>();
}
// Update is called ifonce (IsJumpingper &&frame
_velocity.y > extendedJumpThreshold void Update()
{
if (controller.isGrounded)
_velocity.y -= jumpingGravity * Time.deltaTime; {
else
Vector3 planarTarget = new Vector3(_direction.x, 0, _direction.z);
_velocity.y -= gravityif *(planarTarget.sqrMagnitude Time> 0.deltaTime;01f)
}
{
if Quaternion targetRot = Quaternion.LookRotation(IsCrouchingplanarTarget);
Height transform.rotation = DefaultHeightQuaternion.RotateTowards(transform.rotation, *targetRot, crouchHeight;
600.0f * Time.deltaTime);
else
}
Height = DefaultHeight;}
Accelerate(ref _velocity.yx, =ref Mathf_direction.Clampx);
Accelerate(ref _velocity.yz, -terminalVelocity,ref terminalVelocity_direction.z);
controller.MoveDecelerate(ref _velocity.x, *ref Time_direction.deltaTimex);
}
void FixedUpdateDecelerate(ref _velocity.z, ref _direction.z);
{
controller.Move(_velocity * Time.deltaTime);
}
void Accelerate(ref float velComponent, ref float dirComponent)
{
bool moving = Mathf.Abs(dirComponent) > 0.0f;
if (moving)
{
float absMotion = Mathf.Abs(velComponent);
float crouchFactor = IsCrouching ? crouchSpeed : 1.0f;
if ((velComponent > 0 && dirComponent < 0) ||
(velComponent < 0 && dirComponent > 0))
{
velComponent += dirComponent * skidAcceleration * Time.deltaTime;
}
else if (absMotion < topSpeed * crouchFactor)
{
velComponent += dirComponent * acceleration * Time.deltaTime;
}
else if (absMotion > topSpeed * crouchFactor)
{
velComponent -= dirComponent * deceleration * Time.deltaTime;
}
}
}
void Decelerate(ref float velComponent, ref float dirComponent)
{
bool moving = Mathf.Abs(dirComponent) > 0.0f;
if (!moving)
{
if (velComponent < 0)
{
velComponent += deceleration * Time.deltaTime;
if (velComponent > 0)
velComponent = 0;
}
else if (velComponent > 0)
{
velComponent -= deceleration * Time.deltaTime;
if (velComponent < 0)
velComponent = 0;
}
}
}
}
// Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Player : MonoBehaviour
{
public Transform camTransform;
private Actor actor;
private InputAction moveAction;
private InputAction jumpAction;
private InputAction crouchAction;
// *snip*Start is called before the first frame update
void Start()
{
actor = gameObject.GetComponent<Actor>();
moveAction = InputSystem.actions.FindAction("move");
jumpAction = InputSystem.actions.FindAction("jump");
crouchAction = InputSystem.actions.FindAction("crouch");
}
// Update is called once per frame
void Update()
{
float oldCamPitch = camTransform.eulerAngles.x;
float oldCamRoll = camTransform.eulerAngles.z;
Vector2 moveInput = moveAction.ReadValue<Vector2>();
Vector3 camForward = camTransform.forward;
Vector3 camRight = camTransform.right;
camForward.y = 0;
camRight.y = 0;
camForward.Normalize();
camRight.Normalize();
Vector3 moveDir = camForward * moveInput.y + camRight * moveInput.x;
actor.Direction = moveDir.normalized;
if (jumpAction.WasPressedThisFrame())
actor.Jump();
actor.IsJumping = jumpAction.IsPressed();
actor.IsCrouching = crouchAction.IsPressed();
}
}
EDIT: an example project demonstrating this system in an isolated environment was requested, so I uploaded one here: https://www.mediafire.com/file/i076ubl7pgnlj6x/PlatformerExample.zip/file.