172 lines
5.6 KiB
C#
Raw Normal View History

2024-03-19 17:42:38 +03:00
using Characters.Enemy.States;
using Koptilnya.StateMachine;
using Mirror;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Animations.Rigging;
2024-03-19 21:38:59 +03:00
using UnityEngine.Serialization;
2024-03-19 17:42:38 +03:00
namespace Characters.Enemy
{
public class Enemy : Pawn
{
public NavMeshAgent agent;
public Animator animator;
public Rig aimRig;
public AudioSource audioSource;
2024-03-19 23:37:02 +03:00
public AudioSource footstepAudioSource;
2024-03-19 17:42:38 +03:00
public ParticleSystem hitVFX;
public Transform aimTransform;
public float aggressionDistance = 5f;
2024-03-19 21:38:59 +03:00
[SyncVar] public EnemyState state = EnemyState.Idle;
2024-03-19 17:42:38 +03:00
[SyncVar, HideInInspector] public float aimRigWeight;
public readonly StateMachine<EnemyState> stateMachine = new StateMachine<EnemyState>();
2024-03-19 21:38:59 +03:00
[FormerlySerializedAs("target")] public Transform targetTransform;
2024-03-19 20:18:01 +03:00
public NetworkAnimator networkAnimator;
2024-03-19 23:37:02 +03:00
public bool HasTarget => targetTransform != null;
2024-03-19 21:38:59 +03:00
public float DistanceToTarget => Vector3.Distance(targetTransform.transform.position, transform.position);
2024-03-19 17:42:38 +03:00
private CustomNetworkManager _networkManager;
private NetworkGameManager _networkGameManager;
private float _targetAimRigWeight;
private float _stepCycle;
private AudioClip _footstepClip;
2024-03-19 23:37:02 +03:00
private Vector3 _footstepPrevPosition;
private NavMeshPath _navMeshPath;
2024-03-19 17:42:38 +03:00
2024-03-19 23:37:02 +03:00
private const float StepDelay = 0.12f;
2024-03-19 17:42:38 +03:00
private const float RunSpeed = 4.974f;
private static readonly int SpeedAnimHash = Animator.StringToHash("speed");
void Start()
{
_networkManager = NetworkManager.singleton.GetComponent<CustomNetworkManager>();
_networkGameManager = NetworkGameManager.singleton;
2024-03-19 23:37:02 +03:00
_footstepClip = Resources.Load<AudioClip>("Audio/EnemySounds/Steps/monsterStep1");
_navMeshPath = new();
2024-03-19 20:18:01 +03:00
networkAnimator = GetComponent<NetworkAnimator>();
2024-03-19 17:42:38 +03:00
stateMachine.Add(new IdleState(this));
stateMachine.Add(new PatrolState(this));
stateMachine.Add(new ChaseState(this));
stateMachine.Add(new StunnedState(this));
2024-03-19 21:38:59 +03:00
stateMachine.Add(new AttackState(this));
2024-03-19 17:42:38 +03:00
2024-03-19 20:18:01 +03:00
stateMachine.SetCurrentState(state);
2024-03-19 17:42:38 +03:00
}
void Update()
{
2024-03-19 23:37:02 +03:00
Debug.DrawLine(transform.position, transform.forward * aggressionDistance, Color.green, 0f);
if (isClient)
{
Footsteps();
}
2024-03-19 17:42:38 +03:00
2024-03-19 21:38:59 +03:00
if (isServer)
{
agent.speed = _speedMul * RunSpeed;
animator.SetFloat(SpeedAnimHash, agent.velocity.magnitude);
}
2024-03-19 17:42:38 +03:00
aimRigWeight = isServer ? Mathf.Lerp(aimRigWeight, _targetAimRigWeight, Time.deltaTime) : aimRigWeight;
aimRig.weight = aimRigWeight;
2024-03-19 21:38:59 +03:00
stateMachine.Update();
2024-03-19 17:42:38 +03:00
}
void FixedUpdate()
{
stateMachine.FixedUpdate();
}
public void SetAimRigWeight(float value)
{
_targetAimRigWeight = value;
}
void Footsteps()
{
2024-03-19 23:37:02 +03:00
float velocity = ((_footstepPrevPosition - transform.position) / Time.deltaTime).magnitude;
2024-03-19 17:42:38 +03:00
float clampedVelocity = Mathf.Clamp(RunSpeed / velocity + 1, 1, RunSpeed);
if (Time.time > _stepCycle && velocity > 0)
{
2024-03-19 23:37:02 +03:00
footstepAudioSource.pitch = 1f + Random.Range(-0.1f, 0.1f);
footstepAudioSource.PlayOneShot(_footstepClip);
2024-03-19 17:42:38 +03:00
_stepCycle = Time.time + (clampedVelocity * StepDelay);
}
2024-03-19 23:37:02 +03:00
_footstepPrevPosition = transform.position;
2024-03-19 17:42:38 +03:00
}
2024-03-19 21:38:59 +03:00
[ClientRpc]
public void RpcKillTarget(Transform target)
{
Interactions interactions = target.GetComponent<Interactions>();
if (interactions != null) interactions.DropProp();
target.GetComponent<Pawn>().Die();
}
[ServerCallback]
2024-03-19 17:42:38 +03:00
public override void TakeDamage()
{
base.TakeDamage();
2024-03-19 21:38:59 +03:00
ChangeState(EnemyState.Stunned);
}
2024-03-19 20:18:01 +03:00
[Server]
2024-03-19 21:38:59 +03:00
public void ChangeState(EnemyState newState)
{
state = newState;
RpcChangeState(newState);
}
[ClientRpc]
private void RpcChangeState(EnemyState newState)
{
2024-03-19 21:38:59 +03:00
stateMachine.SetCurrentState(newState);
}
public Transform GetClosestTarget()
{
if (!agent.isOnNavMesh) return null;
2024-03-19 21:38:59 +03:00
var alivePlayers = _networkManager.alive;
2024-03-19 23:37:02 +03:00
if (HasTarget && alivePlayers.Count == 1 && alivePlayers[0].transform == targetTransform)
2024-03-19 20:18:01 +03:00
{
2024-03-19 21:38:59 +03:00
return targetTransform;
2024-03-19 20:18:01 +03:00
}
2024-03-19 21:38:59 +03:00
Transform closestTarget = null;
var sortDistance = float.MaxValue;
2024-03-19 21:38:59 +03:00
foreach (var player in _networkManager.alive)
2024-03-19 20:18:01 +03:00
{
var targetPosition = player.transform.position;
var distance = Vector3.Distance(targetPosition, transform.position);
var canReachTarget = agent.CalculatePath(targetPosition, _navMeshPath) && _navMeshPath.status == NavMeshPathStatus.PathComplete;
2024-03-19 21:38:59 +03:00
if (distance <= aggressionDistance && distance < sortDistance && canReachTarget)
2024-03-19 21:38:59 +03:00
{
sortDistance = distance;
closestTarget = player.transform;
}
2024-03-19 20:18:01 +03:00
}
2024-03-19 17:56:12 +03:00
2024-03-19 21:38:59 +03:00
return closestTarget;
2024-03-19 17:42:38 +03:00
}
}
}