using Boxfriend.Extensions; using Boxfriend.Input; using KinematicCharacterController; using UnityEngine; namespace Boxfriend.Player { [RequireComponent(typeof(InputDispatcher))] [RequireComponent(typeof(KinematicCharacterMotor))] public class PlayerMotor : MonoBehaviour, ICharacterController { [SerializeField, InspectorOnly] private KinematicCharacterMotor _characterMotor; [SerializeField, InspectorOnly] private InputDispatcher _input; private bool _isSprinting; private float _yRotation; private float _gravityVelocity; private Vector3 _moveDirection; private Vector3 _groundNormal = Vector3.up; [SerializeField, InspectorOnly] private float _moveSpeed; [SerializeField, InspectorOnly] private float _defaultGravity; [SerializeField, InspectorOnly] private float _jumpForce; private void Awake () { _input.OnLook += OnLook; _input.OnMove += OnMove; _input.OnJump += OnJump; _input.OnSprint += OnSprint; _characterMotor.CharacterController = this; } private void OnLook (Vector2 delta) => _yRotation = Mathf.Repeat(_yRotation + delta.x, 360); private void OnMove (Vector2 inputDir) => _moveDirection = inputDir.To3D(); private void OnSprint (bool sprinting) => _isSprinting = sprinting; private void OnJump () { if (!_characterMotor.GroundingStatus.IsStableOnGround) return; _characterMotor.ForceUnground(); _groundNormal = Vector3.up; _gravityVelocity = _jumpForce; } public void UpdateRotation (ref Quaternion currentRotation, float deltaTime) => currentRotation = Quaternion.Euler(0, _yRotation, 0); public void UpdateVelocity (ref Vector3 currentVelocity, float deltaTime) { if (!_characterMotor.GroundingStatus.IsStableOnGround) { _gravityVelocity += _defaultGravity * deltaTime; currentVelocity.y = _gravityVelocity; return; } _gravityVelocity = 0; var moveDir = transform.TransformDirection(_moveDirection); var direction = _characterMotor.GetDirectionTangentToSurface(moveDir, _groundNormal); direction *= _isSprinting ? _moveSpeed * 1.5f : _moveSpeed; direction.y += _gravityVelocity; currentVelocity = direction; } public void BeforeCharacterUpdate (float deltaTime) { } public void PostGroundingUpdate (float deltaTime) { } public void AfterCharacterUpdate (float deltaTime) { } public bool IsColliderValidForCollisions (Collider coll) => coll != _characterMotor.Capsule; public void OnGroundHit (Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) => _groundNormal = hitNormal; public void OnMovementHit (Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { } public void ProcessHitStabilityReport (Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) { } public void OnDiscreteCollisionDetected (Collider hitCollider) { } private void Reset () { _characterMotor = GetComponent(); _input = GetComponent(); } } }