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; 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(); } public NavMeshPath navMeshPath; public bool isKilling = false; 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 (_target != null) // Да { controller.destination = _target.position; float distance = Vector3.Distance(_target.transform.position, transform.position); if (distance < aggressionDistance) // (_remainingDistance < aggressionDistance && _remainingDistance > 0) { aimTarget.position = _target.position + _target.up * 1.2f; targetLayerWeight = 1f; // Debug.Log(_remainingDistance); // Если подошли к нему if (distance < 1f) { // Debug.Log("da"); // _target.GetComponent().DropProp(); if (isKilling == false) { RpcKillPlayer(_target); animator.SetTrigger("attack"); StartCoroutine(AfterKillTimer()); } isKilling = true; } } else { _target = null; } } else { //if (controller.GetPathRemainingDistance() <= 0f) // Нет mojet doiti targetLayerWeight = 0f; // Ищем ближайшего игрока foreach (var player in players) { float distance = Vector3.Distance(player.transform.position, transform.position); // Debug.Log(CalculateNewPath(player.transform)); 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(); } } // if (_target == null) // { // float pointDistance = Vector3.Distance(_patrolPoints[_currenPointId].position, transform.position); // if (pointDistance < 2) // { // _currenPointId = Random.Range(0, _patrolPoints.Length); // } // controller.destination = _patrolPoints[_currenPointId].position; // foreach (var player in players) // { // float distance = Vector3.Distance(player.transform.position, transform.position); // if (distance < aggressionDistance) // { // state = ENEMY_STATE.ROTATE; // _target = player.transform; // targetLayerWeight = 1f; // break; // } // } // } // else // { // if (layerWeight >= 0.9f && hasPath) // { // if (state == ENEMY_STATE.ROTATE) // { // state = ENEMY_STATE.CHASE; // } // controller.destination = _target.position; // } // if (controller.velocity.magnitude <= 1 && !hasPath) // { // _target = null; // state = ENEMY_STATE.PATROL; // } // target.position = _target.position + _target.up * 1.2f; // var distance = Vector3.Distance(_target.transform.position, transform.position); // if (distance <= 1) // { // _target.GetComponent().Die(); // } // if (distance >= aggressionDistance) // { // state = ENEMY_STATE.PATROL; // _target = null; // targetLayerWeight = 0f; // } // } } bool CalculateNewPath(Transform target) { controller.CalculatePath(target.position, navMeshPath); if (navMeshPath.status != NavMeshPathStatus.PathComplete) { return false; } else { return true; } } [ClientRpc] void RpcKillPlayer(Transform target) { Interactions interactions = target.GetComponent(); if (interactions != null) interactions.DropProp(); target.GetComponent().Die(); } IEnumerator AfterKillTimer() { yield return new WaitForSeconds(5); isKilling = false; _target = null; 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() { // // NavMeshTriangulation navMeshData = NavMesh.CalculateTriangulation(); // int maxIndices = navMeshData.indices.Length - 3; // // Pick the first indice of a random triangle in the nav mesh // int firstVertexSelected = Random.Range(0, maxIndices); // int secondVertexSelected = Random.Range(0, maxIndices); // //Spawn on Verticies // Vector3 point = navMeshData.vertices[navMeshData.indices[firstVertexSelected]]; // Vector3 firstVertexPosition = navMeshData.vertices[navMeshData.indices[firstVertexSelected]]; // Vector3 secondVertexPosition = navMeshData.vertices[navMeshData.indices[secondVertexSelected]]; // //Eliminate points that share a similar X or Z position to stop spawining in square grid line formations // if ((int)firstVertexPosition.x == (int)secondVertexPosition.x || // (int)firstVertexPosition.z == (int)secondVertexPosition.z // ) // { // point = GetRandomLocation(); //Re-Roll a position - I'm not happy with this recursion it could be better // } // else // { // // Select a random point on it // point = Vector3.Lerp( // firstVertexPosition, // secondVertexPosition, //[t + 1]], // Random.Range(0.05f, 0.95f) // Not using Random.value as clumps form around Verticies // ); // } // //Vector3.Lerp(point, navMeshData.vertices[navMeshData.indices[t + 2]], Random.value); //Made Obsolete // return point; 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) { animator.SetTrigger("damage"); hitVFX.Stop(); hitVFX.Play(); } }