470 lines
15 KiB
C#
470 lines
15 KiB
C#
using UnityEngine;
|
|
using Mirror;
|
|
using TMPro;
|
|
using Characters;
|
|
using Debuffs;
|
|
|
|
/* Note: animations are called via the controller for both the character and capsule using animator null checks
|
|
*/
|
|
|
|
namespace StarterAssets
|
|
{
|
|
[RequireComponent(typeof(CharacterController))]
|
|
|
|
public class PersonController : Pawn
|
|
{
|
|
[Header("Oscar nasral v kod")]
|
|
public GameObject headPosition;
|
|
public GameObject floatingInfo;
|
|
public TMP_Text nicknameInput;
|
|
public AudioSource audioSource;
|
|
public AudioClip footStepClip;
|
|
private AudioClip _gotEnergyClip;
|
|
|
|
private Interactions _interactions;
|
|
|
|
private Vector2 _lerpInputVec, _inputVec;
|
|
private float _controllerVelocity, lerp;
|
|
|
|
private bool _inputJump;
|
|
|
|
private Vector2 _inputMove;
|
|
public float _stepCycle, _stepTiming = 1;
|
|
|
|
[Header("Player")]
|
|
[Tooltip("Move speed of the character in m/s")]
|
|
public float MoveSpeed = 2.0f;
|
|
[Tooltip("Sprint speed of the character in m/s")]
|
|
public float SprintSpeed = 5.335f;
|
|
|
|
[Tooltip("Acceleration and deceleration")]
|
|
public float SpeedChangeRate = 10.0f;
|
|
|
|
[Space(10)]
|
|
[Tooltip("The height the player can jump")]
|
|
public float JumpHeight = 1.2f;
|
|
[Tooltip("The character uses its own gravity value. The engine default is -9.81f")]
|
|
public float Gravity = -15.0f;
|
|
|
|
[Space(10)]
|
|
[Tooltip("Time required to pass before being able to jump again. Set to 0f to instantly jump again")]
|
|
public float JumpTimeout = 0.50f;
|
|
[Tooltip("Time required to pass before entering the fall state. Useful for walking down stairs")]
|
|
public float FallTimeout = 0.15f;
|
|
|
|
[Header("Player Grounded")]
|
|
[Tooltip("If the character is grounded or not. Not part of the CharacterController built in grounded check")]
|
|
public bool Grounded = true;
|
|
[Tooltip("Useful for rough ground")]
|
|
public float GroundedOffset = -0.14f;
|
|
[Tooltip("The radius of the grounded check. Should match the radius of the CharacterController")]
|
|
public float GroundedRadius = 0.28f;
|
|
[Tooltip("What layers the character uses as ground")]
|
|
public LayerMask GroundLayers;
|
|
|
|
public bool LockCameraPosition = false;
|
|
|
|
private float _cinemachineTargetYaw;
|
|
|
|
[SyncVar]
|
|
public Transform _parent;
|
|
|
|
private float _speed;
|
|
private float _animationBlend;
|
|
|
|
private float _verticalVelocity;
|
|
private float _terminalVelocity = 53.0f;
|
|
|
|
private float _jumpTimeoutDelta;
|
|
private float _fallTimeoutDelta;
|
|
|
|
// animation IDs
|
|
private int _animIDSpeed, _animIDGrounded, _animIDJump, _animIDFreeFall, _animIDMotionSpeed, _animIDX, _animIDY;
|
|
|
|
public Animator _animator;
|
|
private CharacterController _controller;
|
|
public GameObject mainCamera;
|
|
|
|
private const float _threshold = 0.01f;
|
|
private bool _hasAnimator = true;
|
|
|
|
[SyncVar(hook = nameof(OnPlayerSetup))]
|
|
public string playerName;
|
|
|
|
[SyncVar, HideInInspector]
|
|
public Color gunColor;
|
|
|
|
private Vector3 _position;
|
|
|
|
[Command]
|
|
public void CmdSetupPlayer(string _name, float r, float g, float b)
|
|
{
|
|
gunColor = new Color(r, g, b);
|
|
|
|
playerName = _name;
|
|
}
|
|
|
|
public void OnPlayerSetup(string _Old, string _New)
|
|
{
|
|
nicknameInput.text = playerName;
|
|
}
|
|
|
|
public override void OnStartLocalPlayer()
|
|
{
|
|
CmdSetupPlayer(
|
|
PlayerPrefs.GetString("NickName"),
|
|
PlayerPrefs.GetFloat("GunColorR"),
|
|
PlayerPrefs.GetFloat("GunColorG"),
|
|
PlayerPrefs.GetFloat("GunColorB")
|
|
);
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
_controller = GetComponent<CharacterController>();
|
|
this.OnDamage += OnTakeDamage;
|
|
|
|
_gotEnergyClip = Resources.Load<AudioClip>("Audio/CharacterSounds/GetEnergy");
|
|
|
|
Live();
|
|
|
|
_interactions = GetComponent<Interactions>();
|
|
|
|
if (isLocalPlayer)
|
|
{
|
|
floatingInfo.SetActive(false);
|
|
}
|
|
|
|
if (!isLocalPlayer) return;
|
|
|
|
AssignAnimationIDs();
|
|
|
|
_jumpTimeoutDelta = JumpTimeout;
|
|
_fallTimeoutDelta = FallTimeout;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (Alive)
|
|
{
|
|
CalculateFootstepTriggers();
|
|
setParent();
|
|
}
|
|
|
|
if (!isLocalPlayer)
|
|
{
|
|
if (netIdentity.isActiveAndEnabled && floatingInfo != null)
|
|
floatingInfo.transform.LookAt(Camera.main.transform);
|
|
return;
|
|
}
|
|
|
|
if (Cursor.lockState == CursorLockMode.None) return;
|
|
|
|
if (Alive)
|
|
{
|
|
CalculateEnergy();
|
|
GroundedCheck();
|
|
JumpAndGravity();
|
|
Move();
|
|
}
|
|
else
|
|
{
|
|
SpectatorMove();
|
|
}
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (!isLocalPlayer) return;
|
|
if (Cursor.lockState == CursorLockMode.None) return;
|
|
CameraRotation();
|
|
SetCamToHeadPos();
|
|
}
|
|
|
|
private void SetCamToHeadPos()
|
|
{
|
|
CinemachineCameraTarget.transform.position = headPosition.transform.position;
|
|
}
|
|
|
|
private void AssignAnimationIDs()
|
|
{
|
|
_animIDSpeed = Animator.StringToHash("Speed");
|
|
_animIDGrounded = Animator.StringToHash("Grounded");
|
|
_animIDJump = Animator.StringToHash("Jump");
|
|
_animIDFreeFall = Animator.StringToHash("FreeFall");
|
|
_animIDMotionSpeed = Animator.StringToHash("MotionSpeed");
|
|
_animIDX = Animator.StringToHash("x");
|
|
_animIDY = Animator.StringToHash("y");
|
|
}
|
|
|
|
private void GroundedCheck()
|
|
{
|
|
Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z);
|
|
Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers, QueryTriggerInteraction.Ignore);
|
|
|
|
if (_hasAnimator)
|
|
{
|
|
_animator.SetBool(_animIDGrounded, Grounded);
|
|
}
|
|
}
|
|
|
|
public float currentEnergy = 100f, shootDepletion = 15f, _flashLightDepletion = 0.3f;
|
|
private float _maxEnergy = 1000f, _depletionSpeed = 0.5f, _regenerationSpeed = 1f, _jumpDepletion = 5f;
|
|
private void CalculateEnergy()
|
|
{
|
|
if (Input.GetKey(KeyCode.LeftShift) && _inputMove.magnitude != 0)
|
|
{
|
|
currentEnergy = Mathf.MoveTowards(currentEnergy, 0, _depletionSpeed * Time.deltaTime);
|
|
}
|
|
else if (currentEnergy <= _maxEnergy)
|
|
{
|
|
currentEnergy = Mathf.MoveTowards(currentEnergy, _maxEnergy, _regenerationSpeed * Time.deltaTime);
|
|
}
|
|
|
|
if (currentEnergy <= 0)
|
|
{
|
|
CmdDie();
|
|
}
|
|
}
|
|
public void InstantStaminaReduction(float Reduction)
|
|
{
|
|
currentEnergy = Mathf.Clamp(currentEnergy -= Reduction, 0, _maxEnergy);
|
|
}
|
|
public void InstantStaminaRegeneration(float Regeneration)
|
|
{
|
|
currentEnergy = Mathf.Clamp(currentEnergy += Regeneration, 0, _maxEnergy);
|
|
CmdGotEnergy();
|
|
}
|
|
|
|
[Command(requiresAuthority = false)]
|
|
void CmdGotEnergy()
|
|
{
|
|
RpcGotEnergy();
|
|
}
|
|
|
|
[ClientRpc]
|
|
void RpcGotEnergy()
|
|
{
|
|
audioSource.PlayOneShot(_gotEnergyClip);
|
|
}
|
|
|
|
[Command]
|
|
void CmdSetCameraPitch(float value)
|
|
{
|
|
_cinemachineTargetPitch = value;
|
|
}
|
|
|
|
void SetCameraPitch()
|
|
{
|
|
lerp = Mathf.Lerp(lerp, _cinemachineTargetPitch, Time.deltaTime * 10f);
|
|
|
|
CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(lerp, 0.0f, 0.0f);
|
|
}
|
|
|
|
private void Move()
|
|
{
|
|
_inputMove = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
|
|
|
|
float targetSpeed = Input.GetKey(KeyCode.LeftShift) ? (currentEnergy <= _depletionSpeed ? MoveSpeed : SprintSpeed) : MoveSpeed;
|
|
targetSpeed *= _speedMul;
|
|
|
|
if (_inputMove == Vector2.zero) targetSpeed = 0.0f;
|
|
|
|
float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
|
|
|
|
float speedOffset = 0.1f;
|
|
float inputMagnitude = 1f;
|
|
|
|
if (currentHorizontalSpeed < targetSpeed - speedOffset || currentHorizontalSpeed > targetSpeed + speedOffset)
|
|
{
|
|
_speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude, Time.deltaTime * SpeedChangeRate);
|
|
|
|
_speed = Mathf.Round(_speed * 1000f) / 1000f;
|
|
}
|
|
else
|
|
{
|
|
_speed = targetSpeed;
|
|
}
|
|
_animationBlend = Mathf.Lerp(_animationBlend, targetSpeed, Time.deltaTime * SpeedChangeRate);
|
|
|
|
|
|
Vector3 inputDirection = new Vector3(_inputMove.x, 0.0f, _inputMove.y).normalized;
|
|
|
|
if (_inputMove != Vector2.zero)
|
|
{
|
|
inputDirection = transform.right * _inputMove.x + transform.forward * _inputMove.y;
|
|
}
|
|
|
|
RaycastHit hit;
|
|
|
|
if (Physics.Raycast(transform.position, -transform.up, out hit, 1f, LayerMask.NameToLayer("Player")))
|
|
{
|
|
if (hit.collider.tag == "MovingPlatform" && hit.collider.GetComponentInParent<NetworkIdentity>() != null)
|
|
{
|
|
CmdSetParent(hit.collider.transform.parent);
|
|
}
|
|
else
|
|
{
|
|
CmdSetParent(null);
|
|
}
|
|
}
|
|
|
|
_controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
|
|
|
|
if (_hasAnimator)
|
|
{
|
|
_lerpInputVec = Vector2.Lerp(_lerpInputVec, _inputMove, Time.deltaTime * 10);
|
|
|
|
_animator.SetFloat(_animIDSpeed, _animationBlend);
|
|
_animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
|
|
|
|
_animator.SetFloat(_animIDX, _lerpInputVec.x);
|
|
_animator.SetFloat(_animIDY, _lerpInputVec.y);
|
|
}
|
|
}
|
|
|
|
void SpectatorMove()
|
|
{
|
|
float inputZ = (Input.GetKey(KeyCode.E) ? 1 : 0) - (Input.GetKey(KeyCode.Q) ? 1 : 0) + (Input.GetKey(KeyCode.Space) ? 1 : 0) - (Input.GetKey(KeyCode.LeftShift) ? 1 : 0);
|
|
|
|
float targetSpeed = MoveSpeed; //Input.GetKey(KeyCode.LeftShift) ? SprintSpeed : MoveSpeed;
|
|
|
|
_inputMove = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
|
|
|
|
Vector3 inputDirection = transform.right * _inputMove.x + transform.forward * _inputMove.y + transform.up * inputZ;
|
|
|
|
|
|
transform.position += inputDirection * Time.deltaTime * targetSpeed * 10f;
|
|
}
|
|
|
|
void setParent()
|
|
{
|
|
transform.parent = _parent;
|
|
}
|
|
|
|
[Command]
|
|
void CmdSetParent(Transform transf)
|
|
{
|
|
_parent = transf;
|
|
}
|
|
|
|
// server
|
|
void OnTakeDamage(Pawn self)
|
|
{
|
|
_animator.SetTrigger("damage");
|
|
InstantStaminaReduction(shootDepletion * 0.7f);
|
|
// Debug.Log(self.GetComponent<PersonController>().playerName);
|
|
|
|
// hitVFX.Stop();
|
|
// hitVFX.Play();
|
|
|
|
// self.GetComponent<Interactions>().DropProp();
|
|
}
|
|
|
|
private void JumpAndGravity()
|
|
{
|
|
if (Grounded)
|
|
{
|
|
_inputJump = Input.GetKeyDown(KeyCode.Space);
|
|
// reset the fall timeout timer
|
|
_fallTimeoutDelta = FallTimeout;
|
|
|
|
// update animator if using character
|
|
if (_hasAnimator)
|
|
{
|
|
_animator.SetBool(_animIDJump, false);
|
|
_animator.SetBool(_animIDFreeFall, false);
|
|
}
|
|
|
|
// stop our velocity dropping infinitely when grounded
|
|
if (_verticalVelocity < 0.0f)
|
|
{
|
|
_verticalVelocity = -2f;
|
|
}
|
|
|
|
// Jump
|
|
if (_inputJump && _jumpTimeoutDelta <= 0.0f && currentEnergy >= _jumpDepletion)
|
|
{
|
|
// the square root of H * -2 * G = how much velocity needed to reach desired height
|
|
_verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
|
|
|
|
InstantStaminaReduction(_jumpDepletion);
|
|
|
|
// update animator if using character
|
|
if (_hasAnimator)
|
|
{
|
|
_animator.SetBool(_animIDJump, true);
|
|
}
|
|
}
|
|
|
|
// jump timeout
|
|
if (_jumpTimeoutDelta >= 0.0f)
|
|
{
|
|
_jumpTimeoutDelta -= Time.deltaTime;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// reset the jump timeout timer
|
|
_jumpTimeoutDelta = JumpTimeout;
|
|
|
|
// fall timeout
|
|
if (_fallTimeoutDelta >= 0.0f)
|
|
{
|
|
_fallTimeoutDelta -= Time.deltaTime;
|
|
}
|
|
else
|
|
{
|
|
// update animator if using character
|
|
if (_hasAnimator)
|
|
{
|
|
_animator.SetBool(_animIDFreeFall, true);
|
|
}
|
|
}
|
|
|
|
// if we are not grounded, do not jump
|
|
_inputJump = false;
|
|
}
|
|
|
|
// apply gravity over time if under terminal (multiply by delta time twice to linearly speed up over time)
|
|
if (_verticalVelocity < _terminalVelocity)
|
|
{
|
|
_verticalVelocity += Gravity * Time.deltaTime;
|
|
}
|
|
}
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
|
|
Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
|
|
|
|
if (Grounded) Gizmos.color = transparentGreen;
|
|
else Gizmos.color = transparentRed;
|
|
|
|
// when selected, draw a gizmo in the position of, and matching radius of, the grounded collider
|
|
Gizmos.DrawSphere(new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z), GroundedRadius);
|
|
}
|
|
|
|
void CalculateFootstepTriggers()
|
|
{
|
|
float _controllerVelocity = ((_position - transform.position) / Time.deltaTime).magnitude;
|
|
// Debug.Log(_controllerVelocity);
|
|
float clampedVelocity = Mathf.Clamp(SprintSpeed / _controllerVelocity + 1, 1, SprintSpeed);
|
|
|
|
if (Time.time > _stepCycle && Grounded && _controllerVelocity > 0.1)
|
|
{
|
|
CallFootstepClip();
|
|
|
|
_stepCycle = Time.time + (clampedVelocity * _stepTiming);
|
|
}
|
|
|
|
_position = transform.position;
|
|
}
|
|
|
|
public void CallFootstepClip()
|
|
{
|
|
audioSource.pitch = 1f + Random.Range(-0.1f, 0.1f);
|
|
audioSource.PlayOneShot(footStepClip);
|
|
}
|
|
}
|
|
} |