279 lines
7.3 KiB
C#
279 lines
7.3 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
|
|
public class PlayerController : CharacterBase {
|
|
|
|
public Display WildDisplay;
|
|
public Display3DFriend FriendDisplay;
|
|
[SerializeField] protected MeleeAttackCollider AttackCollider;
|
|
|
|
[Header("Camera")]
|
|
public Camera Camera;
|
|
public Transform CameraTarget;
|
|
public float CameraDistanceMax;
|
|
public float CameraDistance;
|
|
public LayerMask CameraCollisionMask;
|
|
|
|
[Header("Effects")]
|
|
[SerializeField] private ParticleSystem SandstarParticles;
|
|
[SerializeField] private ParticleSystem DeathParticles;
|
|
|
|
private List<Interactable> _interactablesInRange = new List<Interactable>();
|
|
|
|
private NavMeshAgent _agent;
|
|
private DialogueController _currentDialogue;
|
|
private bool _lastAttackState = false;
|
|
|
|
public bool IsAttacking()
|
|
{
|
|
if (Display.GetAnimatorLayersCount() < 1) return false;
|
|
return Display.GetCurrentAnimatorStateInfo(1).IsName("Attack");
|
|
}
|
|
|
|
public bool IsRecoil()
|
|
{
|
|
return Display.GetCurrentAnimatorStateInfo(0).IsName("Hit");
|
|
}
|
|
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
_agent = GetComponent<NavMeshAgent>();
|
|
}
|
|
|
|
protected override void Start()
|
|
{
|
|
if(GameManager.Instance != null)
|
|
{
|
|
GameManager.Instance.Player = this;
|
|
}
|
|
}
|
|
|
|
protected override void Update()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (Input.GetKeyDown(Controls.Debug_K))
|
|
{
|
|
TakeDamage(9999);
|
|
}
|
|
#endif
|
|
|
|
if (!IsAlive() || !_cc.enabled || _currentDialogue != null) return;
|
|
Vector3 input = new Vector3(Input.GetAxis(Controls.XAxis), 0, Input.GetAxis(Controls.YAxis));
|
|
|
|
bool isAttacking = IsAttacking();
|
|
bool isRecoil = IsRecoil();
|
|
|
|
if (_lastAttackState != isAttacking && !isAttacking)
|
|
{
|
|
AttackEnd();
|
|
}
|
|
|
|
if (isRecoil)
|
|
{
|
|
if (isAttacking)
|
|
{
|
|
Display.SetEvent("InterruptAttack", true);
|
|
}
|
|
input = Vector3.zero;
|
|
}
|
|
|
|
if (Input.GetKeyDown(Controls.Interact))
|
|
{
|
|
if (TryInteract())
|
|
{
|
|
return;
|
|
}
|
|
else if (!isAttacking)
|
|
{
|
|
AttackStart();
|
|
}
|
|
}
|
|
|
|
if (isAttacking)
|
|
{
|
|
input /= 2;
|
|
}
|
|
|
|
_cc.SimpleMove(transform.forward * input.z * Speed);
|
|
Display.SetFloat("Input", input.z);
|
|
|
|
if (input != Vector3.zero)
|
|
{
|
|
_cc.transform.Rotate(Vector3.up, input.x * 120 * Time.deltaTime);
|
|
}
|
|
|
|
if (input.z != 0)
|
|
{
|
|
PlayFootstep();
|
|
}
|
|
|
|
_lastAttackState = isAttacking;
|
|
}
|
|
|
|
void LateUpdate()
|
|
{
|
|
RaycastHit hit;
|
|
if (Physics.Raycast(CameraTarget.position, -CameraTarget.forward, out hit, CameraDistanceMax, CameraCollisionMask.value))
|
|
{
|
|
CameraDistance = hit.distance;
|
|
}
|
|
else
|
|
{
|
|
CameraDistance = Mathf.Lerp(CameraDistance, CameraDistanceMax, 0.5f);
|
|
}
|
|
|
|
Camera.transform.position = CameraTarget.position - CameraTarget.forward * CameraDistance;
|
|
}
|
|
|
|
private bool TryInteract()
|
|
{
|
|
for (int i = _interactablesInRange.Count - 1; i>=0; i--)
|
|
{
|
|
if(_interactablesInRange[i] == null)
|
|
{
|
|
_interactablesInRange.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
if (_interactablesInRange.Count == 0)
|
|
return false;
|
|
|
|
if (!_interactablesInRange[0].Interact(this)) return false;
|
|
|
|
Display.PlayState("Interact");
|
|
return true;
|
|
}
|
|
|
|
private void AttackStart()
|
|
{
|
|
Display.SetEvent("InterruptAttack", false);
|
|
AttackCollider.Toggle(true);
|
|
AttackCollider.OnHit.AddListener((target) =>
|
|
{
|
|
if ((PlayerController)target == this) return;
|
|
target.TakeDamage(1);
|
|
});
|
|
Display.SetLayerWeight(1, 1);
|
|
Display.PlayState("Attack", 1);
|
|
}
|
|
|
|
private void AttackEnd()
|
|
{
|
|
if (AttackCollider.gameObject.activeSelf)
|
|
{
|
|
AttackCollider.Toggle(false);
|
|
AttackCollider.OnHit.RemoveAllListeners();
|
|
}
|
|
Display.SetLayerWeight(1, 0);
|
|
}
|
|
|
|
public void ToggleCharacterController(bool enabled)
|
|
{
|
|
_cc.enabled = enabled;
|
|
_interactablesInRange.Clear();
|
|
}
|
|
|
|
public void ToggleSandstarEmission(bool value)
|
|
{
|
|
var emission = SandstarParticles.emission;
|
|
emission.enabled = value;
|
|
}
|
|
|
|
public override void TakeDamage(int dmg)
|
|
{
|
|
base.TakeDamage(dmg);
|
|
if (IsAlive())
|
|
{
|
|
Display.PlayState("Hit");
|
|
}
|
|
}
|
|
|
|
protected override void OnDeath()
|
|
{
|
|
ToggleCharacterController(false);
|
|
Display.PlayState("Die");
|
|
StartCoroutine(PlayDeathSequence(2));
|
|
}
|
|
|
|
private IEnumerator PlayDeathSequence(float delay)
|
|
{
|
|
yield return new WaitForSeconds(delay);
|
|
FriendDisplay.gameObject.SetActive(false);
|
|
DeathParticles.gameObject.SetActive(true);
|
|
|
|
yield return new WaitForSeconds(0.5f);
|
|
transform.SetParent(null);
|
|
WildDisplay.gameObject.SetActive(true);
|
|
Display = WildDisplay;
|
|
yield return PathfindToEntrance();
|
|
}
|
|
|
|
private IEnumerator PathfindToEntrance()
|
|
{
|
|
var entrance = GameManager.Instance.CurrentExit;
|
|
if(entrance == null) { entrance = GameManager.Instance.Exits[0]; }
|
|
ToggleCharacterController(false);
|
|
|
|
float timeOut = 2; //seconds
|
|
_agent.enabled = true;
|
|
_agent.SetDestination(entrance.GetComponent<ILocationChange>().GetExitLocator().position);
|
|
Display.SetFloat("Input", 1);
|
|
|
|
do
|
|
{
|
|
timeOut -= Time.deltaTime;
|
|
yield return 0;
|
|
}
|
|
while ((_agent.remainingDistance > _agent.stoppingDistance) && timeOut > 0);
|
|
|
|
Display.SetFloat("Input", 0);
|
|
Debug.Log("Pathfound");
|
|
|
|
if(string.IsNullOrEmpty(GameManager.Instance.PreviousExit.TargetScene))
|
|
{
|
|
Debug.LogError("Previous scene not found! Using default");
|
|
GameManager.ChangeSceneAsync(entrance.GetComponent<ILocationChange>().GetDefaultExit());
|
|
}
|
|
else
|
|
{
|
|
GameManager.ChangeSceneAsync(GameManager.Instance.PreviousExit);
|
|
}
|
|
}
|
|
|
|
public void SetDialogue(DialogueController controller)
|
|
{
|
|
Display.SetFloat("Input", 0);
|
|
_currentDialogue = controller;
|
|
}
|
|
|
|
void OnControllerColliderHit(ControllerColliderHit hit)
|
|
{
|
|
var triggers = hit.gameObject.GetComponent<CollisionTriggers>();
|
|
if (triggers != null && triggers.CollisionTags.Contains(this.tag))
|
|
{
|
|
triggers.OnCollisionEnterAction.Invoke();
|
|
}
|
|
}
|
|
|
|
void OnTriggerEnter(Collider other)
|
|
{
|
|
var interactable = other.GetComponent<Interactable>();
|
|
if (interactable != null)
|
|
{
|
|
_interactablesInRange.Add(interactable);
|
|
}
|
|
}
|
|
|
|
void OnTriggerExit(Collider other)
|
|
{
|
|
var interactable = other.GetComponent<Interactable>();
|
|
if (interactable != null && _interactablesInRange.Contains(interactable))
|
|
{
|
|
_interactablesInRange.Remove(interactable);
|
|
}
|
|
}
|
|
}
|