using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class Yeji : TargetAnimal { //动画播放器 AnimationPlayer ap; //寻路代理 NavMeshAgent agent; //血量 [System.NonSerialized] public int hp = 3; public TreeAreaRecorder treeAreaRecorder; //模型的偏移Y(即坐标为Zero时,模型超出地面的高度) public const float modelOffsetY = 0.33f; [System.NonSerialized] public float flyPlaneHeight = 5; public void SetFlyHeight(float value) { float agentBaseOffset = value - flyPlaneHeight - modelOffsetY; this.agent.baseOffset = agentBaseOffset / 2; } void Awake() { ap = GetComponent(); agent = GetComponent(); } void Start() { //初始动画 playAniFly(); //初始化自动策略 InitAutoStrategy(); } void Update() { //寻路过程监测 if (HasCloseToDestination()) { OnReachDestination(); } else { OnMovingToDestination(); } UpdateAction(); UpdateActionTime(); UpdateAutoStrategy(); if (Input.GetKeyDown(KeyCode.S)) { } } public void Disappear() { Destroy(this.gameObject); } public override void OnHit(Arrow arrow, Vector3 hitPoint, string partName) { arrow.Head().position = hitPoint + arrow.transform.forward * 0.1f; arrow.Hit(); if (partName == "Wing") { hp -= 1; this.agent.speed /= 2f; } else if (partName == "Body") hp -= 2; else if (partName == "Head") hp -= 3; if (hp <= 0) { Die(arrow); } else { Hurt(); } } void Die(Arrow arrow) { if (dead) return; arrow.onDoNextShoot += delegate() { Disappear(); }; dead = true; this.agent.enabled = false; PuaseAutoStrategy(); onDie?.Invoke(this); AudioMgr.ins.PlayAnimalEffect("bird_die", AudioMgr.GetAudioSource(this.gameObject)); } void Hurt() { AudioMgr.ins.PlayAnimalEffect("bird_injured", AudioMgr.GetAudioSource(this.gameObject)); } //是否已经死亡 bool dead = false; //是否处于移动状态 bool _moving = false; bool moving { get { return _moving; } set { if (_moving && !value) { movingTime = 0; } if (!_moving && value) stayingTime = 0; _moving = value; } } //实时记录“单次移动的持续时间” float movingTime = 0; //实时停留时间 float stayingTime = 0; //启动寻路 void SetDestination(Vector3 pos) { moving = true; this.agent.destination = pos; } //寻路过程 void OnMovingToDestination() { if (!moving) return; } //寻路结束 void OnReachDestination() { if (!moving) return; moving = false; } //是否已经接近目的地(寻路完成判断) bool HasCloseToDestination() { if (!moving) return true; if (movingTime > 0.1) { if (this.agent.velocity.magnitude < 0.05f) { return true; } } return false; } //更新动作 void UpdateAction() { if (dead) { if (!isAniDie()) playAniDie(); } else { if (!isAniFly()) playAniFly(); } } //记录动作时间 void UpdateActionTime() { if (moving) { movingTime += Time.deltaTime; } else { stayingTime += Time.deltaTime; } } float willStayTime; float willMoveTime; bool autoMoving = false; float autoMovingTime; bool autoStrategy = true; //自动策略的更新逻辑 void UpdateAutoStrategy() { if (!autoStrategy) return; if (stayingTime > willStayTime) { autoMoving = true; RandomMove(); RandomWillStayTime(); } if (autoMoving) { if (moving) { autoMovingTime += Time.deltaTime; } else if (autoMovingTime < willMoveTime) { RandomMove(); } else if (autoMovingTime >= willMoveTime) { Stay(); RandomWillMoveTime(); autoMoving = false; autoMovingTime = 0; } } } void InitAutoStrategy() { autoStrategy = true; this.willStayTime = 1; RandomWillMoveTime(); } void PuaseAutoStrategy() { this.autoStrategy = false; } void ResumeAutoStrategy() { this.autoStrategy = true; RandomWillStayTime(); RandomWillMoveTime(); this.autoMoving = false; this.autoMovingTime = 0; } void RandomWillStayTime() { this.willStayTime = 1; } void RandomWillMoveTime() { this.willMoveTime = 20; } //逃跑远离猎人 void RunAwayFromHunter() { Vector3 backVec = GetPointerHunterToMe(); SetDestination(transform.position + backVec.normalized * 5); } //能够在前几棵树徘徊 [System.NonSerialized] public int canFlyTreeCount = 4; //将会绕树转 bool willMoveRoundTree = false; Queue roundTreePostions = new Queue(); //随机移动 void RandomMove() { if (willMoveRoundTree && roundTreePostions.Count > 0) { Vector3 pos = roundTreePostions.Dequeue(); SetDestination(pos); return; } else { willMoveRoundTree = false; } Vector3 myPos = this.transform.position; TreeAreaRecorder.AreaInfo[] areaInfos = treeAreaRecorder.copyAreaInfos(canFlyTreeCount); for (int i = 0; i < canFlyTreeCount; i++) { areaInfos[i].teamCompareValue = areaInfos[i].distanceInHorizontal(myPos); } System.Array.Sort(areaInfos, new ComparerAreaInfosByDistance()); //如果离这棵树比较近,有几率使其绕着树转 TreeAreaRecorder.AreaInfo firstAreaInfo = areaInfos[0]; bool isNearTree4th = areaInfos.Length == 4 && firstAreaInfo == treeAreaRecorder.getValidAreaInfo(3); if (!isNearTree4th && firstAreaInfo.teamCompareValue < firstAreaInfo.radius + 1.5f && Random.value < 0.5) { willMoveRoundTree = true; Vector3 treePos = areaInfos[0].transform.position; treePos.y = myPos.y; Vector3 pointer = myPos - treePos; roundTreePostions.Clear(); int direction = Random.value >= 0.5 ? 1 : -1; for (int i = 1; i <= 6; i++) { roundTreePostions.Enqueue(treePos + Quaternion.AngleAxis(i * 60 * direction, Vector3.up) * pointer); } RandomMove(); return; } TreeAreaRecorder.AreaInfo areaInfo = areaInfos[Random.Range(1, canFlyTreeCount)]; Vector3 newPos = YejiHuntGameMode.CalculateNewPosByTreePos(animalsBaseT, flyPlaneHeight, areaInfo); SetDestination(newPos); } class ComparerAreaInfosByDistance : IComparer { public int Compare(object x, object y) { TreeAreaRecorder.AreaInfo a = (TreeAreaRecorder.AreaInfo)x; TreeAreaRecorder.AreaInfo b = (TreeAreaRecorder.AreaInfo)y; if (a.teamCompareValue - b.teamCompareValue > 0) return 1; if (a.teamCompareValue - b.teamCompareValue < 0) return -1; else return 0; } } //停留 void Stay() { if (moving) { this.agent.destination = this.agent.nextPosition; OnReachDestination(); } } //当前动画索引 int curAnimIndex = 0; void playAniDie() { ap.play(curAnimIndex = 1, WrapMode.Once); } bool isAniDie() { return curAnimIndex == 1; } void playAniFly() { ap.play(curAnimIndex = 0, WrapMode.Loop); } bool isAniFly() { return curAnimIndex == 0; } //委托 public System.Action onDie; }