diff options
author | chai <215380520@qq.com> | 2024-03-13 11:00:58 +0800 |
---|---|---|
committer | chai <215380520@qq.com> | 2024-03-13 11:00:58 +0800 |
commit | 6ce8b9e22fc13be34b442c7b6af48b42cd44275a (patch) | |
tree | b38119d2acf0a982cb67e381f146924b9bfc3b3f /UnitySA.Characters.FirstPerson |
+init
Diffstat (limited to 'UnitySA.Characters.FirstPerson')
-rw-r--r-- | UnitySA.Characters.FirstPerson/FPCtrl.cs | 202 | ||||
-rw-r--r-- | UnitySA.Characters.FirstPerson/MLook.cs | 111 |
2 files changed, 313 insertions, 0 deletions
diff --git a/UnitySA.Characters.FirstPerson/FPCtrl.cs b/UnitySA.Characters.FirstPerson/FPCtrl.cs new file mode 100644 index 0000000..51d2efb --- /dev/null +++ b/UnitySA.Characters.FirstPerson/FPCtrl.cs @@ -0,0 +1,202 @@ +using UnityEngine; +using UnitySA.Utility; + +namespace UnitySA.Characters.FirstPerson; + +[RequireComponent(typeof(CharacterController))] +[RequireComponent(typeof(AudioSource))] +public class FPCtrl : MonoBehaviour +{ + [SerializeField] + private bool m_IsWalking; + + [SerializeField] + private float m_WalkSpeed; + + [SerializeField] + private float m_RunSpeed; + + [SerializeField] + [Range(0f, 1f)] + private float m_RunstepLenghten; + + [SerializeField] + private float m_JumpSpeed; + + [SerializeField] + private float m_StickToGroundForce; + + [SerializeField] + private float m_GravityMultiplier; + + [SerializeField] + private MLook m_MouseLook; + + [SerializeField] + private bool m_UseFovKick; + + [SerializeField] + private FOVZoom m_FovKick = new FOVZoom(); + + [SerializeField] + private bool m_UseHeadBob; + + [SerializeField] + private CurveCtrlBob m_HeadBob = new CurveCtrlBob(); + + [SerializeField] + private LerpCtrlBob m_JumpBob = new LerpCtrlBob(); + + [SerializeField] + private float m_StepInterval; + + private Camera m_Camera; + + private bool m_Jump; + + private float m_YRotation; + + private Vector2 m_Input; + + private Vector3 m_MoveDir = Vector3.zero; + + private CharacterController m_CharacterController; + + private CollisionFlags m_CollisionFlags; + + private bool m_PreviouslyGrounded; + + private Vector3 m_OriginalCameraPosition; + + private float m_StepCycle; + + private float m_NextStep; + + private bool m_Jumping; + + private void Start() + { + m_CharacterController = GetComponent<CharacterController>(); + m_Camera = Camera.main; + m_OriginalCameraPosition = m_Camera.transform.localPosition; + m_FovKick.Setup(m_Camera); + m_HeadBob.Setup(m_Camera, m_StepInterval); + m_StepCycle = 0f; + m_NextStep = m_StepCycle / 2f; + m_Jumping = false; + m_MouseLook.Init(base.transform, m_Camera.transform); + } + + private void Update() + { + RotateView(); + if (!m_Jump) + { + m_Jump = Input.GetButtonDown("Jump"); + } + if (!m_PreviouslyGrounded && m_CharacterController.isGrounded) + { + StartCoroutine(m_JumpBob.DoBobCycle()); + m_MoveDir.y = 0f; + m_Jumping = false; + } + if (!m_CharacterController.isGrounded && !m_Jumping && m_PreviouslyGrounded) + { + m_MoveDir.y = 0f; + } + m_PreviouslyGrounded = m_CharacterController.isGrounded; + } + + private void FixedUpdate() + { + GetInput(out var speed); + Vector3 vector = base.transform.forward * m_Input.y + base.transform.right * m_Input.x; + Physics.SphereCast(base.transform.position, m_CharacterController.radius, Vector3.down, out var hitInfo, m_CharacterController.height / 2f, -1, QueryTriggerInteraction.Ignore); + vector = Vector3.ProjectOnPlane(vector, hitInfo.normal).normalized; + m_MoveDir.x = vector.x * speed; + m_MoveDir.z = vector.z * speed; + if (m_CharacterController.isGrounded) + { + m_MoveDir.y = 0f - m_StickToGroundForce; + if (m_Jump) + { + m_MoveDir.y = m_JumpSpeed; + m_Jump = false; + m_Jumping = true; + } + } + else + { + m_MoveDir += Physics.gravity * m_GravityMultiplier * Time.fixedDeltaTime; + } + m_CollisionFlags = m_CharacterController.Move(m_MoveDir * Time.fixedDeltaTime); + ProgressStepCycle(speed); + UpdateCameraPosition(speed); + m_MouseLook.UpdateCursorLock(); + } + + private void ProgressStepCycle(float speed) + { + if (m_CharacterController.velocity.sqrMagnitude > 0f && (m_Input.x != 0f || m_Input.y != 0f)) + { + m_StepCycle += (m_CharacterController.velocity.magnitude + speed * ((!m_IsWalking) ? m_RunstepLenghten : 1f)) * Time.fixedDeltaTime; + } + if (m_StepCycle > m_NextStep) + { + m_NextStep = m_StepCycle + m_StepInterval; + } + } + + private void UpdateCameraPosition(float speed) + { + if (m_UseHeadBob) + { + Vector3 localPosition; + if (m_CharacterController.velocity.magnitude > 0f && m_CharacterController.isGrounded) + { + m_Camera.transform.localPosition = m_HeadBob.DoHeadBob(m_CharacterController.velocity.magnitude + speed * ((!m_IsWalking) ? m_RunstepLenghten : 1f)); + localPosition = m_Camera.transform.localPosition; + localPosition.y = m_Camera.transform.localPosition.y - m_JumpBob.Offset(); + } + else + { + localPosition = m_Camera.transform.localPosition; + localPosition.y = m_OriginalCameraPosition.y - m_JumpBob.Offset(); + } + m_Camera.transform.localPosition = localPosition; + } + } + + private void GetInput(out float speed) + { + float axis = Input.GetAxis("Horizontal"); + float axis2 = Input.GetAxis("Vertical"); + bool isWalking = m_IsWalking; + m_IsWalking = !Input.GetKey(KeyCode.LeftShift); + speed = ((!m_IsWalking) ? m_RunSpeed : m_WalkSpeed); + m_Input = new Vector2(axis, axis2); + if (m_Input.sqrMagnitude > 1f) + { + m_Input.Normalize(); + } + if (m_IsWalking != isWalking && m_UseFovKick && m_CharacterController.velocity.sqrMagnitude > 0f) + { + StopAllCoroutines(); + StartCoroutine(m_IsWalking ? m_FovKick.FOVKickDown() : m_FovKick.FOVKickUp()); + } + } + + private void RotateView() + { + m_MouseLook.LookRotation(base.transform, m_Camera.transform); + } + + private void OnControllerColliderHit(ControllerColliderHit hit) + { + Rigidbody attachedRigidbody = hit.collider.attachedRigidbody; + if (m_CollisionFlags != CollisionFlags.Below && !(attachedRigidbody == null) && !attachedRigidbody.isKinematic) + { + attachedRigidbody.AddForceAtPosition(m_CharacterController.velocity * 0.1f, hit.point, ForceMode.Impulse); + } + } +} diff --git a/UnitySA.Characters.FirstPerson/MLook.cs b/UnitySA.Characters.FirstPerson/MLook.cs new file mode 100644 index 0000000..ce78022 --- /dev/null +++ b/UnitySA.Characters.FirstPerson/MLook.cs @@ -0,0 +1,111 @@ +using System; +using UnityEngine; + +namespace UnitySA.Characters.FirstPerson; + +[Serializable] +public class MLook +{ + public float XSensitivity = 2f; + + public float YSensitivity = 2f; + + public bool clampVerticalRotation = true; + + public float MinimumX = -90f; + + public float MaximumX = 90f; + + public bool smooth; + + public float smoothTime = 5f; + + public bool lockCursor = true; + + private Quaternion m_CharacterTargetRot; + + private Quaternion m_CameraTargetRot; + + private bool m_cursorIsLocked = true; + + public void Init(Transform character, Transform camera) + { + m_CharacterTargetRot = character.localRotation; + m_CameraTargetRot = camera.localRotation; + } + + public void LookRotation(Transform character, Transform camera) + { + float y = Input.GetAxis("Mouse X") * XSensitivity; + float num = Input.GetAxis("Mouse Y") * YSensitivity; + m_CharacterTargetRot *= Quaternion.Euler(0f, y, 0f); + m_CameraTargetRot *= Quaternion.Euler(0f - num, 0f, 0f); + if (clampVerticalRotation) + { + m_CameraTargetRot = ClampRotationAroundXAxis(m_CameraTargetRot); + } + if (smooth) + { + character.localRotation = Quaternion.Slerp(character.localRotation, m_CharacterTargetRot, smoothTime * Time.deltaTime); + camera.localRotation = Quaternion.Slerp(camera.localRotation, m_CameraTargetRot, smoothTime * Time.deltaTime); + } + else + { + character.localRotation = m_CharacterTargetRot; + camera.localRotation = m_CameraTargetRot; + } + UpdateCursorLock(); + } + + public void SetCursorLock(bool value) + { + lockCursor = value; + if (!lockCursor) + { + Cursor.lockState = CursorLockMode.None; + Cursor.visible = true; + } + } + + public void UpdateCursorLock() + { + if (lockCursor) + { + InternalLockUpdate(); + } + } + + private void InternalLockUpdate() + { + if (Input.GetKeyUp(KeyCode.Escape)) + { + m_cursorIsLocked = false; + } + else if (Input.GetMouseButtonUp(0)) + { + m_cursorIsLocked = true; + } + if (m_cursorIsLocked) + { + Cursor.lockState = CursorLockMode.Locked; + Cursor.visible = false; + } + else if (!m_cursorIsLocked) + { + Cursor.lockState = CursorLockMode.None; + Cursor.visible = true; + } + } + + private Quaternion ClampRotationAroundXAxis(Quaternion q) + { + q.x /= q.w; + q.y /= q.w; + q.z /= q.w; + q.w = 1f; + float value = 114.59156f * Mathf.Atan(q.x); + value = Mathf.Clamp(value, MinimumX, MaximumX); + q.x = Mathf.Tan((float)Math.PI / 360f * value); + return q; + } +} |