324 lines
10 KiB
C#
324 lines
10 KiB
C#
using UnityEngine;
|
|
|
|
namespace NBF
|
|
{
|
|
[RequireComponent(typeof(CharacterController))]
|
|
[RequireComponent(typeof(AudioSource))]
|
|
public class FirstPersonController : MonoBehaviour
|
|
{
|
|
[SerializeField] private bool m_IsWalking;
|
|
|
|
[SerializeField] public float m_WalkSpeed;
|
|
|
|
[SerializeField] public 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] public MouseLook m_MouseLook;
|
|
|
|
[SerializeField] private bool m_UseFovKick;
|
|
|
|
[SerializeField] private FOVKick m_FovKick = new FOVKick();
|
|
|
|
[SerializeField] private bool m_UseHeadBob;
|
|
|
|
[SerializeField] private CurveControlledBob m_HeadBob = new CurveControlledBob();
|
|
|
|
[SerializeField] private LerpControlledBob m_JumpBob = new LerpControlledBob();
|
|
|
|
[SerializeField] private float m_StepInterval;
|
|
|
|
[SerializeField] private AudioClip[] m_FootstepSounds;
|
|
|
|
[SerializeField] private AudioClip[] m_FootstepSoundsBridge;
|
|
|
|
[SerializeField] private AudioClip[] m_FootstepSoundsStone;
|
|
|
|
[SerializeField] private AudioClip m_JumpSound;
|
|
|
|
[SerializeField] private AudioClip m_LandSound;
|
|
|
|
private Camera m_Camera;
|
|
|
|
private bool m_Jump;
|
|
|
|
public bool frezzeRotation;
|
|
|
|
public bool frezzePosition;
|
|
|
|
public bool rotateMouseInFixedUpdate = true;
|
|
|
|
public Vector2 m_Input;
|
|
|
|
public Vector3 m_MoveDir = Vector3.zero;
|
|
|
|
public 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 AudioSource m_AudioSource;
|
|
|
|
private string groundTypeTag = "";
|
|
|
|
public float horizontal;
|
|
|
|
public float vertical;
|
|
|
|
public bool isJumping;
|
|
|
|
public bool isRuning;
|
|
|
|
public bool notMove;
|
|
|
|
public bool isWater;
|
|
|
|
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_AudioSource = GetComponent<AudioSource>();
|
|
m_MouseLook.Init(transform, m_Camera.transform);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!frezzeRotation && !rotateMouseInFixedUpdate)
|
|
{
|
|
RotateView();
|
|
}
|
|
|
|
if (!m_Jump)
|
|
{
|
|
m_Jump = isJumping;
|
|
}
|
|
|
|
if (!m_PreviouslyGrounded && m_CharacterController.isGrounded)
|
|
{
|
|
StartCoroutine(m_JumpBob.DoBobCycle());
|
|
PlayLandingSound();
|
|
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 PlayLandingSound()
|
|
{
|
|
m_AudioSource.clip = m_LandSound;
|
|
m_AudioSource.Play();
|
|
m_NextStep = m_StepCycle + 0.5f;
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
if (!frezzeRotation && rotateMouseInFixedUpdate)
|
|
{
|
|
RotateView();
|
|
}
|
|
|
|
if (frezzePosition)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetInput(out var speed);
|
|
Vector3 vector = transform.forward * m_Input.y + transform.right * m_Input.x;
|
|
Physics.SphereCast(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 && !isWater)
|
|
{
|
|
if ((bool)transform.parent && transform.parent.gameObject.layer == LayerMask.NameToLayer("Boat"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_MoveDir.y = m_JumpSpeed;
|
|
PlayJumpSound();
|
|
m_Jump = false;
|
|
m_Jumping = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_MoveDir += Physics.gravity * m_GravityMultiplier * Time.fixedDeltaTime;
|
|
}
|
|
|
|
if (!notMove)
|
|
{
|
|
m_CollisionFlags = m_CharacterController.Move(m_MoveDir * Time.fixedDeltaTime);
|
|
}
|
|
|
|
ProgressStepCycle(speed);
|
|
UpdateCameraPosition(speed);
|
|
m_MouseLook.UpdateCursorLock();
|
|
}
|
|
|
|
private void PlayJumpSound()
|
|
{
|
|
m_AudioSource.clip = m_JumpSound;
|
|
m_AudioSource.Play();
|
|
}
|
|
|
|
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 ? 1f : m_RunstepLenghten)) *
|
|
Time.fixedDeltaTime;
|
|
}
|
|
|
|
if (m_StepCycle > m_NextStep)
|
|
{
|
|
m_NextStep = m_StepCycle + m_StepInterval;
|
|
PlayFootStepAudio();
|
|
}
|
|
}
|
|
|
|
private void PlayFootStepAudio()
|
|
{
|
|
if (!m_CharacterController.isGrounded)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (groundTypeTag == "Bridge" || groundTypeTag == "Boat")
|
|
{
|
|
if (m_FootstepSoundsBridge.Length != 0)
|
|
{
|
|
int num = Random.Range(1, m_FootstepSoundsBridge.Length);
|
|
m_AudioSource.clip = m_FootstepSoundsBridge[num];
|
|
m_AudioSource.PlayOneShot(m_AudioSource.clip, 0.3f);
|
|
m_FootstepSoundsBridge[num] = m_FootstepSoundsBridge[0];
|
|
m_FootstepSoundsBridge[0] = m_AudioSource.clip;
|
|
}
|
|
}
|
|
else if (groundTypeTag == "Stone")
|
|
{
|
|
if (m_FootstepSoundsStone.Length != 0)
|
|
{
|
|
int num2 = Random.Range(1, m_FootstepSoundsStone.Length);
|
|
m_AudioSource.clip = m_FootstepSoundsStone[num2];
|
|
m_AudioSource.PlayOneShot(m_AudioSource.clip, 0.3f);
|
|
m_FootstepSoundsStone[num2] = m_FootstepSoundsStone[0];
|
|
m_FootstepSoundsStone[0] = m_AudioSource.clip;
|
|
}
|
|
}
|
|
else if (m_FootstepSounds.Length != 0)
|
|
{
|
|
int num3 = Random.Range(1, m_FootstepSounds.Length);
|
|
m_AudioSource.clip = m_FootstepSounds[num3];
|
|
m_AudioSource.PlayOneShot(m_AudioSource.clip, 0.3f);
|
|
m_FootstepSounds[num3] = m_FootstepSounds[0];
|
|
m_FootstepSounds[0] = m_AudioSource.clip;
|
|
}
|
|
}
|
|
|
|
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 ? 1f : m_RunstepLenghten));
|
|
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)
|
|
{
|
|
bool isWalking = m_IsWalking;
|
|
m_IsWalking = !isRuning;
|
|
speed = (m_IsWalking ? m_WalkSpeed : m_RunSpeed);
|
|
m_Input = new Vector2(horizontal, vertical);
|
|
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.FOVKickUp() : m_FovKick.FOVKickDown());
|
|
}
|
|
}
|
|
|
|
public void RotateView()
|
|
{
|
|
m_MouseLook.LookRotation(transform, m_Camera.transform);
|
|
}
|
|
|
|
private void OnControllerColliderHit(ControllerColliderHit hit)
|
|
{
|
|
Rigidbody attachedRigidbody = hit.collider.attachedRigidbody;
|
|
groundTypeTag = hit.collider.tag;
|
|
|
|
if (m_CollisionFlags != CollisionFlags.Below && !(attachedRigidbody == null))
|
|
{
|
|
_ = attachedRigidbody.isKinematic;
|
|
}
|
|
}
|
|
|
|
private void OnTriggerStay(Collider other)
|
|
{
|
|
if (other.CompareTag("Water"))
|
|
{
|
|
isWater = true;
|
|
}
|
|
}
|
|
|
|
private void OnTriggerExit(Collider other)
|
|
{
|
|
if (other.CompareTag("Water"))
|
|
{
|
|
isWater = false;
|
|
}
|
|
}
|
|
}
|
|
} |