using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; using Mirror; using UnityEngine.Animations.Rigging; using Player; public partial class EnemyController : Pawn { public bool spawnCube = false; public NavMeshAgent controller; public Animator animator; public Rig targetLayer; public AudioSource audioSource; public ParticleSystem hitVFX; public bool hasPath; public GameObject propPrefab; public Transform aimTarget; public float aggressionDistance = 5f; public float _stepTiming = 0.15f; CustomNetworkManager networkManager; NetworkGameManager networkGameManager; private Transform _target = null; private List players; private Vector3 _position; private float _stepCycle; private float _runSpeed = 4.974f; //_walkSpeed = 0.299f private float targetLayerWeight; private int _currenPointId; [SyncVar] private float layerWeight; private float _remainingDistance; NavMeshTriangulation navMeshData; [SyncVar(hook = nameof(OnStateChanged))] private ENEMY_STATE state = ENEMY_STATE.PATROL; private AudioClip skrClip, agressiveClip; public NavMeshPath navMeshPath; public bool isKilling = false; [SerializeField] private bool canAttack = true; void Start() { // Time.timeScale = 10; skrClip = Resources.Load("Audio/EnemySounds/woodSkr"); agressiveClip = Resources.Load("Audio/EnemySounds/FX/agressive2"); networkManager = NetworkManager.singleton.GetComponent(); networkGameManager = NetworkGameManager.singleton; players = networkManager.alive; if (!isServer) return; this.OnDamage += TakeDamageAnimation; navMeshData = NavMesh.CalculateTriangulation(); if (spawnCube) { Vector3 randLoc = navMeshData.vertices[navMeshData.indices[Random.Range(0, navMeshData.indices.Length - 3)]]; GameObject gameObject = Instantiate(propPrefab, randLoc + Vector3.up * 1, Quaternion.identity); gameObject.GetComponent().Original = true; NetworkServer.Spawn(gameObject); } navMeshPath = new NavMeshPath(); } void Update() { controller.speed = _speedMul * _runSpeed; CalculateFootstepTriggers(); layerWeight = isServer ? Mathf.Lerp(layerWeight, targetLayerWeight, Time.deltaTime) : layerWeight; targetLayer.weight = layerWeight; if (!isServer) return; animator.SetFloat("speed", controller.velocity.magnitude); _remainingDistance = controller.GetPathRemainingDistance(); hasPath = controller.pathStatus != NavMeshPathStatus.PathComplete; // if (controller.pathStatus == NavMeshPathStatus.PathComplete && !controller.pathPending && _target != null) // { // _target = null; // } // Есть таргет? if (_target != null) // Да { controller.destination = _target.position; float distance = Vector3.Distance(_target.transform.position, transform.position); if (distance < aggressionDistance) { aimTarget.position = _target.position + _target.up * 1.2f; targetLayerWeight = 1f; if (distance < 1f) { if (canAttack && !isKilling) { RpcKillPlayer(_target); animator.SetTrigger("attack"); StartCoroutine(AfterKillTimer()); } } } else { _target = null; } } else { targetLayerWeight = 0f; // Ищем ближайшего игрока foreach (var player in players) { float distance = Vector3.Distance(player.transform.position, transform.position); if (distance <= aggressionDistance && CalculateNewPath(player.transform)) // && _remainingDistance > 0 { //if (_remainingDistance < aggressionDistance && controller.GetPathRemainingDistance() >= 0) _target = player.transform; break; } } if (_target == null && _remainingDistance <= 1.5f) //!controller.pathPending || { SetRandomDestination(); } } } bool CalculateNewPath(Transform target) { controller.CalculatePath(target.position, navMeshPath); if (navMeshPath.status != NavMeshPathStatus.PathComplete) { return false; } return true; } [ClientRpc] void RpcKillPlayer(Transform target) { Interactions interactions = target.GetComponent(); if (interactions != null) interactions.DropProp(); target.GetComponent().Die(); } IEnumerator AfterKillTimer() { isKilling = true; _target = null; _speedMul = 0; yield return new WaitForSeconds(7); _speedMul = 1; isKilling = false; aimTarget.position = transform.position; SetRandomDestination(); } [Server] void SetRandomDestination() { var targetPoint = GetRandomLocation(); // var targetPoint = navMeshData.vertices[2000]; //_patrolPoints[Random.Range(0, _patrolPoints.Length - 1)].position; // hasPath = controller.SetDestination(targetPoint); controller.destination = targetPoint; // hasPath = controller.hasPath; } void OnStateChanged(ENEMY_STATE oldState, ENEMY_STATE newState) { audioSource.Stop(); switch (newState) { case ENEMY_STATE.PATROL: audioSource.reverbZoneMix = 1f; break; case ENEMY_STATE.ROTATE: audioSource.clip = skrClip; audioSource.Play(); break; case ENEMY_STATE.CHASE: // audioSource.clip = agressiveClip; // audioSource.reverbZoneMix = 0f; // audioSource.Play(); break; } } private List _points = new List(); Vector3 GetRandomLocation() { var point = navMeshData.vertices[navMeshData.indices[Random.Range(0, navMeshData.indices.Length - 3)]]; _points.Add(point); return point; } void OnDrawGizmos() { foreach (var point in _points) { Gizmos.DrawSphere(point, 1f); } } void CalculateFootstepTriggers() { float _velocity = ((_position - transform.position) / Time.deltaTime).magnitude; // Debug.Log(_controllerVelocity); float clampedVelocity = Mathf.Clamp(_runSpeed / _velocity + 1, 1, _runSpeed); if (Time.time > _stepCycle && _velocity > 0) { CallFootstepClip(); _stepCycle = Time.time + (clampedVelocity * _stepTiming); } _position = transform.position; } public void CallFootstepClip() { audioSource.pitch = 1f + Random.Range(-0.1f, 0.1f); audioSource.PlayOneShot(Resources.Load("Audio/EnemySounds/Steps/monsterStep1")); } void TakeDamageAnimation(Pawn self) { canAttack = false; _speedMul = 0; animator.SetTrigger("damage"); hitVFX.Stop(); hitVFX.Play(); StartCoroutine(AfterTakeDamage()); } IEnumerator AfterTakeDamage() { yield return new WaitForSeconds(6); _speedMul = 1; canAttack = true; } }