using System.Collections.Generic; using UnityEngine; using System.Collections; public class Passersby : MonoBehaviour { private Rigidbody rigBody; private Animator animator; private MovePath movePath; private Passersby nearPassersby; private SemaphorePeople nearSemaphore; private Transform nearCar; private Transform nearPlayer; private AnimationState lastState; [SerializeField] private float curMoveSpeed; private float moveSpeed; private float startWalkSpeed; private float startRunSpeed; private bool redSemaphore; private bool insideSemaphore; private bool tempStop; private bool timeToWalk = true; [Tooltip("Layers of car, traffic light, pedestrians, player / Слои автомобиля, светофора, пешеходов, игрока")] public LayerMask targetMask; [HideInInspector] public LayerMask obstacleMask; [SerializeField] private AnimationState animationState; [SerializeField] [Tooltip("Walking speed / Скорость ходьбы")] private float walkSpeed; [SerializeField] [Tooltip("Running speed / Скорость бега")] private float runSpeed; [SerializeField] [Tooltip("Swing speed / Скорость поворота")] private float speedRotation; [SerializeField] [Tooltip("Viewing Angle / Угол обзора")] private float viewAngle; [SerializeField] [Tooltip("Radius of visibility / Радиус видимости")] private float viewRadius; [SerializeField] [Tooltip("Distance to pedestrian / Расстояние до пешехода")] private float distToPeople; [SerializeField] [Tooltip("Set your animation speed / Установить свою скорость анимации?")] private bool _overrideDefaultAnimationMultiplier; [SerializeField] [Tooltip("Speed animation walking / Скорость анимации ходьбы")] private float _customWalkAnimationMultiplier = 1.0f; [SerializeField] [Tooltip("Running animation speed / Скорость анимации бега")] private float _customRunAnimationMultiplier = 1.0f; public AnimationState ANIMATION_STATE { get { return animationState; } set { animationState = value; } } public AnimationState LastState { get{ return lastState;} set{lastState = value;} } public float WALK_SPEED { get { return walkSpeed; } set { walkSpeed = value; } } public float RUN_SPEED { get { return runSpeed; } set { runSpeed = value; } } public float SPEED_ROTATION { get { return speedRotation; } set { speedRotation = value; } } public float VIEW_ANGLE { get { return viewAngle; } set { viewAngle = value; } } public float VIEW_RADIUS { get { return viewRadius; } set { viewRadius = value; } } public bool INSIDE { get { return insideSemaphore; } set { insideSemaphore = value; } } public bool RED { get { return redSemaphore; } set { redSemaphore = value; } } public float DIST_TO_PEOPLE { get{return distToPeople;} set{distToPeople = value;} } public float CustomWalkAnimationMultiplier { get { return _customWalkAnimationMultiplier; } set { _customWalkAnimationMultiplier = value; } } public float CustomRunAnimationMultiplier { get {return _customRunAnimationMultiplier;} set {_customRunAnimationMultiplier = value;} } public bool OverrideDefaultAnimationMultiplier { get { return _overrideDefaultAnimationMultiplier; } set { _overrideDefaultAnimationMultiplier = value; } } private void Awake() { rigBody = GetComponent<Rigidbody>(); animator = GetComponent<Animator>(); movePath = GetComponent<MovePath>(); } private void Start() { lastState = animationState; startWalkSpeed = walkSpeed; startRunSpeed = runSpeed; animator.CrossFade(animationState.ToString(), 0.1f, 0, Random.Range(0.0f, 1.0f)); } private void Update() { ActionNearPassersby(); ActionNearSemaphore(); ActionNearCar(); ActionNearPlayer(); Move(); if (insideSemaphore) { if (redSemaphore) { animationState = AnimationState.run; } } if(tempStop) { if(curMoveSpeed < 0.3f) { animator.Play("idle1"); } } else { animator.Play(animationState.ToString()); } curMoveSpeed = Mathf.Lerp(curMoveSpeed, moveSpeed, Time.deltaTime * 4.5f); AISight(); } private void FixedUpdate() { GetPath(); } private void Move() { switch (animationState) { case AnimationState.idle1: moveSpeed = 0.0f; if (curMoveSpeed < 0.15f) { curMoveSpeed = 0.0f; } break; case AnimationState.walk: moveSpeed = walkSpeed; if (_overrideDefaultAnimationMultiplier) { animator.speed = curMoveSpeed * _customWalkAnimationMultiplier; } else { animator.speed = curMoveSpeed * 1.2f; } break; case AnimationState.run: moveSpeed = runSpeed; if (_overrideDefaultAnimationMultiplier) { animator.speed = curMoveSpeed * _customRunAnimationMultiplier; } else { animator.speed = curMoveSpeed / 3; } break; } tempStop = (animationState == AnimationState.idle1) ? true : false; } private void AISight() { nearPassersby = null; nearSemaphore = null; nearCar = null; nearPlayer = null; Collider[] targetsInViewRadius = Physics.OverlapSphere(transform.position, viewRadius, targetMask); List<Passersby> passersby = new List<Passersby>(); List<SemaphorePeople> semaphores = new List<SemaphorePeople>(); List<Transform> cars = new List<Transform>(); List<Transform> players = new List<Transform>(); SortTargetsInView<Passersby>(passersby, targetsInViewRadius, "People"); SortTargetsInView<SemaphorePeople>(semaphores, targetsInViewRadius, "PeopleSemaphore"); SortTargetsInView<Transform>(cars, targetsInViewRadius, "Car"); SortTargetsInView<Transform>(players, targetsInViewRadius, "Player"); if (nearPassersby == null && nearSemaphore == null) { if (nearCar == null && nearPlayer == null) { if(!insideSemaphore && !redSemaphore) animationState = lastState; } } } private void GetPath() { Vector3 randFinishPos = new Vector3(movePath.finishPos.x + movePath.randXFinish, movePath.finishPos.y, movePath.finishPos.z + movePath.randZFinish); Vector3 targetPos = new Vector3(randFinishPos.x, rigBody.transform.position.y, randFinishPos.z); var richPointDistance = Vector3.Distance(Vector3.ProjectOnPlane(rigBody.transform.position, Vector3.up), Vector3.ProjectOnPlane(randFinishPos, Vector3.up)); if (richPointDistance < 0.2f && animationState == AnimationState.walk && ((movePath.loop) || (!movePath.loop && movePath.targetPoint > 0 && movePath.targetPoint < movePath.targetPointsTotal))) { if (movePath.forward) { if (movePath.targetPoint < movePath.targetPointsTotal) targetPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPoint + 1); else targetPos = movePath.walkPath.getNextPoint(movePath.w, 0); targetPos.y = rigBody.transform.position.y; } else { if (movePath.targetPoint > 0) targetPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPoint - 1); else targetPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPointsTotal); targetPos.y = rigBody.transform.position.y; } } if (richPointDistance < 0.5f && animationState == AnimationState.run && ((movePath.loop) || (!movePath.loop && movePath.targetPoint > 0 && movePath.targetPoint < movePath.targetPointsTotal))) { if (movePath.forward) { if (movePath.targetPoint < movePath.targetPointsTotal) targetPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPoint + 1); else targetPos = movePath.walkPath.getNextPoint(movePath.w, 0); targetPos.y = rigBody.transform.position.y; } else { if (movePath.targetPoint > 0) targetPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPoint - 1); else targetPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPointsTotal); targetPos.y = rigBody.transform.position.y; } } Vector3 direction = targetPos - transform.position; if (direction != Vector3.zero) { Vector3 newDir = Vector3.zero; rigBody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ; newDir = Vector3.RotateTowards(transform.forward, direction, speedRotation * Time.deltaTime, 0.0f); transform.rotation = Quaternion.LookRotation(newDir); //transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(direction), speedRotation * Time.deltaTime); } if (richPointDistance > movePath._walkPointThreshold) { if (Time.deltaTime > 0) { transform.position += transform.forward * curMoveSpeed * Time.deltaTime; //rigBody.MovePosition(transform.position + transform.forward * curMoveSpeed * Time.fixedDeltaTime); } } else if (richPointDistance <= movePath._walkPointThreshold && movePath.forward) { if (movePath.targetPoint != movePath.targetPointsTotal) { movePath.targetPoint++; movePath.finishPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPoint); } else if (movePath.targetPoint == movePath.targetPointsTotal) { if (movePath.loop) { movePath.finishPos = movePath.walkPath.getStartPoint(movePath.w); movePath.targetPoint = 0; } else { if (movePath != null) { movePath.walkPath.SpawnPoints[movePath.w].AddToSpawnQuery(new MovePathParams { }); } Destroy(gameObject); } } } else if (richPointDistance <= movePath._walkPointThreshold && !movePath.forward) { if (movePath.targetPoint > 0) { movePath.targetPoint--; movePath.finishPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPoint); } else if (movePath.targetPoint == 0) { if (movePath.loop) { movePath.finishPos = movePath.walkPath.getNextPoint(movePath.w, movePath.targetPointsTotal); movePath.targetPoint = movePath.targetPointsTotal; } else { movePath.walkPath.SpawnPoints[movePath.w].AddToSpawnQuery(new MovePathParams { }); Destroy(gameObject); } } } } private void SortTargetsInView<T>(IList<T> list, Collider[] targetsInViewRadius, string tag) { foreach(Collider c in targetsInViewRadius) { if(!c.transform.CompareTag(tag) || c.transform.position == transform.position) continue; if(typeof(T) == typeof(Passersby)) { if(c.transform.parent.name != transform.parent.name || c.GetComponent<MovePath>().w != movePath.w) continue; } Vector3 forward = transform.TransformDirection(Vector3.forward); Vector3 target = c.transform.position - transform.position; if (Vector3.Dot(forward, target) > 0) { list.Add(c.GetComponent<T>()); } } if(typeof(T) == typeof(Passersby)) { List<Passersby> passersby = list as List<Passersby>; NearTarget<Passersby>(passersby); } else if(typeof(T) == typeof(SemaphorePeople)) { List<SemaphorePeople> semaphore = list as List<SemaphorePeople>; NearTarget<SemaphorePeople>(semaphore); } else if(typeof(T) == typeof(Transform)) { if (tag == "Car") { List<Transform> cars = list as List<Transform>; NearTarget<Transform>(cars, "Car"); } else if(tag == "Player") { List<Transform> players = list as List<Transform>; NearTarget<Transform>(players, "Player"); } } } private void NearTarget<T>(IList<T> list, string tag = "") { foreach(T t in list) { Transform target = null; if(typeof(T) == typeof(Passersby)) { Passersby p = t as Passersby; target = p.GetComponent<Transform>(); } else if(typeof(T) == typeof(SemaphorePeople)) { SemaphorePeople s = t as SemaphorePeople; target = s.GetComponent<Transform>(); } else if(typeof(T) == typeof(Transform)) { if (tag == "Car") { Transform car = t as Transform; target = car.GetComponent<Transform>(); } else if(tag == "Player") { Transform player = t as Transform; target = player.GetComponent<Transform>(); } } Vector3 dirToTarget = ((new Vector3(target.position.x, target.position.y, target.position.z)) - transform.position).normalized; if (Vector3.Angle(transform.forward, dirToTarget) < viewAngle / 2) { float dstToTarget = Vector3.Distance(transform.position, target.position); float dstToNearTarget = 0.0f; if(typeof(T) == typeof(Passersby)) { if (nearPassersby != null) { dstToNearTarget = Vector3.Distance(transform.position, nearPassersby.transform.position); } } else if(typeof(T) == typeof(SemaphorePeople)) { if (nearSemaphore != null) { dstToNearTarget = Vector3.Distance(transform.position, nearSemaphore.transform.position); } } else if(typeof(T) == typeof(Transform)) { if (tag == "Car") { if (nearCar != null) { dstToNearTarget = Vector3.Distance(transform.position, nearCar.transform.position); } } else if(tag == "Player") { if (nearPlayer != null) { dstToNearTarget = Vector3.Distance(transform.position, nearPlayer.transform.position); } } } if (!Physics.Raycast(transform.position, dirToTarget, dstToTarget, obstacleMask)) { if(typeof(T) == typeof(Passersby)) { if (nearPassersby == null) { nearPassersby = t as Passersby; continue; } else { if (dstToTarget < dstToNearTarget) { nearPassersby = t as Passersby; } } } else if(typeof(T) == typeof(SemaphorePeople)) { if (nearSemaphore == null) { nearSemaphore = t as SemaphorePeople; continue; } else { if (dstToTarget < dstToNearTarget) { nearSemaphore = t as SemaphorePeople; } } } else if(typeof(T) == typeof(Transform)) { if (tag == "Car") { if (nearCar == null) { nearCar = t as Transform; continue; } else { if (dstToTarget < dstToNearTarget) { nearCar = t as Transform; } } } else if(tag == "Player") { if (nearPlayer == null) { nearPlayer = t as Transform; continue; } else { if (dstToTarget < dstToNearTarget) { nearPlayer = t as Transform; } } } } } } } } private void ActionNearPassersby() { if (nearPassersby != null) { float distance = Vector3.Distance(transform.position, nearPassersby.transform.position); if (distance < distToPeople) { if (nearPassersby.ANIMATION_STATE == AnimationState.idle1) { animationState = AnimationState.idle1; timeToWalk = false; } else { walkSpeed = nearPassersby.walkSpeed; runSpeed = nearPassersby.runSpeed; } } if(animationState == AnimationState.idle1 && nearPassersby.ANIMATION_STATE != AnimationState.idle1) { if (!timeToWalk) { StartCoroutine(StartMove()); timeToWalk = true; } } } else { walkSpeed = startWalkSpeed; runSpeed = startRunSpeed; } } private void ActionNearSemaphore() { if (nearSemaphore == null) return; float distance = Vector3.Distance(transform.position, nearSemaphore.transform.position); if(distance < 25.0f) { if(nearSemaphore.PEOPLE_CAN) { animationState = lastState; } else { if(!insideSemaphore) { animationState = AnimationState.idle1; } } } } private void ActionNearCar() { if (nearCar == null) return; float distance = Vector3.Distance(transform.position, nearCar.transform.position); if (distance < 10.0f) { animationState = AnimationState.idle1; } else { animationState = lastState; } } private void ActionNearPlayer() { if (nearPlayer == null) return; float distance = Vector3.Distance(transform.position, nearPlayer.transform.position); if (distance < 10.0f) { animationState = AnimationState.idle1; } else { animationState = lastState; } } IEnumerator StartMove() { yield return new WaitForSeconds(1.2f); animationState = lastState; tempStop = false; } public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal) { if (!angleIsGlobal) { angleInDegrees += transform.eulerAngles.y; } return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), 0, Mathf.Cos(angleInDegrees * Mathf.Deg2Rad)); } }