Yeji.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.AI;
  5. public class Yeji : TargetAnimal
  6. {
  7. //动画播放器
  8. Animator animator;
  9. //寻路代理
  10. NavMeshAgent agent;
  11. //血量
  12. [System.NonSerialized] public int hp = 3;
  13. [System.NonSerialized] public TreeAreaRecorder treeAreaRecorder;
  14. [System.NonSerialized] public float flyPlaneHeight = 5;
  15. float currentHeight = 0;
  16. float toFlyHeight = float.NaN;
  17. public void SetFlyHeight(float value) {
  18. if (toFlyHeight.Equals(float.NaN)) toFlyHeight = value;
  19. currentHeight = value;
  20. float agentBaseOffset = value - flyPlaneHeight;
  21. this.agent.baseOffset = agentBaseOffset / 1.2f;//因为agent的baseoffset会受节点的scale影响
  22. state.flying = currentHeight > 0;
  23. }
  24. void Awake()
  25. {
  26. state = new State();
  27. state.animal = this;
  28. animator = GetComponent<Animator>();
  29. agent = GetComponent<NavMeshAgent>();
  30. this.agent.avoidancePriority = avoidancePriority;
  31. }
  32. static int _avoidancePriority = 0;
  33. static int avoidancePriority {
  34. get {
  35. if (_avoidancePriority < 50) {
  36. _avoidancePriority++;
  37. } else {
  38. _avoidancePriority = 1;
  39. }
  40. return _avoidancePriority;
  41. }
  42. }
  43. void OnDestroy() {
  44. tryReleaseOccupyTree();
  45. ReleasePreHeight(this);
  46. }
  47. void Update()
  48. {
  49. //寻路过程监测
  50. if (HasCloseToDestination()) {
  51. OnReachDestination();
  52. } else {
  53. OnMovingToDestination();
  54. }
  55. UpdateAutoStrategy();
  56. }
  57. #region 被击触发
  58. public override void OnHit(Arrow arrow, Vector3 hitPoint, string partName)
  59. {
  60. arrow.Head().position = hitPoint + arrow.transform.forward * 0.1f;
  61. arrow.Hit();
  62. if (partName == "Wing") {
  63. hp -= 1;
  64. this.agent.speed /= 2f;
  65. }
  66. else if (partName == "Body") hp -= 2;
  67. else if (partName == "Head") hp -= 3;
  68. if (hp <= 0) {
  69. Die(arrow);
  70. } else {
  71. Hurt();
  72. }
  73. }
  74. void Die(Arrow arrow) {
  75. if (state.dead) return;
  76. arrow.onDoNextShoot += delegate() {
  77. Destroy(this.gameObject);
  78. };
  79. this.animator.speed = 1;
  80. state.dead = true;
  81. this.agent.enabled = false;
  82. ReleasePreHeight(this);
  83. onDie?.Invoke(this);
  84. AudioMgr.ins.PlayAnimalEffect("bird_injured", AudioMgr.GetAudioSource(this.gameObject));
  85. if (currentHeight < 1.5f) {
  86. arrow.arrowCameraComp.arrowCameraTemplate.SendMsg(0, null);
  87. }
  88. }
  89. void Hurt() {
  90. CancelStand();
  91. CancelFlyStay();
  92. AudioMgr.ins.PlayAnimalEffect("bird_injured", AudioMgr.GetAudioSource(this.gameObject));
  93. }
  94. #endregion
  95. #region 寻路导航
  96. bool _moving;
  97. bool moving {
  98. get { return _moving; }
  99. set {
  100. movingTime = 0;
  101. _moving = value;
  102. }
  103. }
  104. float movingTime;
  105. //启动寻路
  106. void SetDestination(Vector3 pos) {
  107. moving = true;
  108. this.agent.destination = pos;
  109. }
  110. //寻路过程
  111. void OnMovingToDestination() {
  112. if (!moving) return;
  113. movingTime += Time.deltaTime;
  114. }
  115. //寻路结束
  116. void OnReachDestination() {
  117. if (!moving) return;
  118. moving = false;
  119. }
  120. //是否已经接近目的地(寻路完成判断)
  121. bool HasCloseToDestination() {
  122. if (!moving) return true;
  123. return movingTime > 0.1 && this.agent.velocity.magnitude < 0.05f;
  124. }
  125. //停止寻路
  126. void StopNavigation() {
  127. if (!moving) return;
  128. this.agent.destination = this.agent.nextPosition;
  129. this.agent.velocity = Vector3.zero;
  130. this.transform.position = this.agent.destination;
  131. OnReachDestination();
  132. }
  133. #endregion
  134. #region 自动逻辑
  135. //自动策略的更新逻辑
  136. void UpdateAutoStrategy() {
  137. if (state.dead) return;
  138. UpdateFlyUpDown();
  139. UpdateBehavior();
  140. }
  141. float canStandTime = 3f;
  142. float canFlyStayTime = 3f;
  143. //能够在前几棵树徘徊
  144. [System.NonSerialized] public int canFlyTreeCount = 4;
  145. const float downSpeed = 2.0f;
  146. //更新逻辑-起飞降落
  147. void UpdateFlyUpDown() {
  148. if (state.up && state.landing) { //起飞阶段
  149. AnimatorStateInfo animatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
  150. bool isTakeOff = animatorStateInfo.IsName("FlyFromGround");
  151. if (isTakeOff) {
  152. if (animatorStateInfo.normalizedTime >= 1.0) {
  153. state.landing = false;
  154. state.flying = true;
  155. }
  156. }
  157. return;
  158. }
  159. if (state.up && state.flying) { //上升阶段
  160. float surplusHeight = toFlyHeight - currentHeight;
  161. float smoothValue = surplusHeight / toFlyHeight;
  162. float nextFlyHeight = currentHeight + Time.deltaTime * (1f + 2.5f * smoothValue);
  163. this.animator.speed = 1f + 2f * smoothValue;
  164. if (nextFlyHeight >= toFlyHeight) { //上升完成
  165. nextFlyHeight = toFlyHeight;
  166. this.animator.speed = 1;
  167. state.up = false;
  168. }
  169. SetFlyHeight(nextFlyHeight);
  170. return;
  171. }
  172. if (state.down && state.flying) { //下降阶段
  173. float nextH = currentHeight - Time.deltaTime * downSpeed;
  174. if (nextH <= 0) { //下降完成
  175. nextH = 0;
  176. state.landing = true;
  177. state.flying = false;
  178. StopNavigation();
  179. }
  180. SetFlyHeight(nextH);
  181. return;
  182. }
  183. if (state.down && state.landing) { //着落阶段
  184. AnimatorStateInfo animatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
  185. bool isLand = animatorStateInfo.IsName("LandOnGround");
  186. if (isLand) {
  187. if (animatorStateInfo.normalizedTime >= 1.0) {
  188. state.down = false;
  189. //进入站立状态
  190. state.standing = true;
  191. canStandTime = 8f + Random.value * 2f;
  192. animator.CrossFade("IdleOnGround2", 0.2f);
  193. }
  194. }
  195. return;
  196. }
  197. }
  198. TreeAreaRecorder.AreaInfo targetAreaInfo;
  199. bool needCheckFlyDown = false;
  200. bool willStayOnTree = false;
  201. void UpdateBehavior() {
  202. if (state.flyStaying) {
  203. canFlyStayTime -= Time.deltaTime;
  204. if (canFlyStayTime <= 0) {
  205. state.flyStaying = false;
  206. }
  207. return;
  208. }
  209. if (state.standing) {
  210. canStandTime -= Time.deltaTime;
  211. if (canStandTime <= 0) {
  212. CancelStand();
  213. }
  214. return;
  215. }
  216. if (state.landing) return;
  217. if (state.flying && !state.down && !state.up) {
  218. if (needCheckFlyDown) {
  219. float downNeedTime = currentHeight / downSpeed;
  220. float keyDistance = this.agent.speed * downNeedTime; //触发下降的水平距离阈值
  221. Vector3 myP = this.transform.position;
  222. Vector3 desP = this.agent.destination;
  223. desP.y = myP.y;
  224. float distance = Vector3.Distance(myP, desP);
  225. if (distance < keyDistance) {
  226. needCheckFlyDown = false;
  227. if (Random.value < 0.5 && tryOccupyTree()) {
  228. state.down = true;
  229. } else {
  230. willStayOnTree = true;
  231. }
  232. }
  233. }
  234. }
  235. if (moving) return;
  236. if (willStayOnTree) {
  237. willStayOnTree = false;
  238. state.flyStaying = true;
  239. canFlyStayTime = 9f + Random.value * 1f;
  240. return;
  241. }
  242. //飞向别的树
  243. #region
  244. Vector3 myPos = this.transform.position;
  245. TreeAreaRecorder.AreaInfo[] areaInfos = treeAreaRecorder.copyAreaInfos(canFlyTreeCount);
  246. for (int i = 0; i < canFlyTreeCount; i++) {
  247. areaInfos[i].teamCompareValue = areaInfos[i].distanceInHorizontal(myPos);
  248. }
  249. System.Array.Sort(areaInfos, new ComparerAreaInfosByDistance());
  250. TreeAreaRecorder.AreaInfo areaInfo = areaInfos[Random.Range(1, canFlyTreeCount)];
  251. Vector3 newPos = YejiHuntGameMode.CalculateNewPosByTreePos(animalsBaseT, flyPlaneHeight, areaInfo);
  252. SetDestination(newPos);
  253. targetAreaInfo = areaInfo;
  254. needCheckFlyDown = true;
  255. #endregion
  256. }
  257. class ComparerAreaInfosByDistance : IComparer {
  258. public int Compare(object x, object y) {
  259. TreeAreaRecorder.AreaInfo a = (TreeAreaRecorder.AreaInfo)x;
  260. TreeAreaRecorder.AreaInfo b = (TreeAreaRecorder.AreaInfo)y;
  261. if (a.teamCompareValue - b.teamCompareValue > 0) return 1;
  262. if (a.teamCompareValue - b.teamCompareValue < 0) return -1;
  263. else return 0;
  264. }
  265. }
  266. void CancelStand() {
  267. if (!state.standing) return;
  268. state.standing = false;
  269. state.up = true;
  270. animator.CrossFade("FlyFromGround", 0.1f);
  271. tryReleaseOccupyTree();
  272. }
  273. void CancelFlyStay() {
  274. if (!state.flyStaying) return;
  275. canFlyStayTime = 0;
  276. }
  277. bool tryOccupyTree() {
  278. if (targetAreaInfo == null) return false;
  279. if (targetAreaInfo.occupy != null) return false;
  280. else {
  281. targetAreaInfo.occupy = this;
  282. return true;
  283. }
  284. }
  285. void tryReleaseOccupyTree() {
  286. if (targetAreaInfo != null && targetAreaInfo.occupy != null && targetAreaInfo.occupy.Equals(this)) {
  287. targetAreaInfo.occupy = null;
  288. }
  289. }
  290. static float[] preFlyHeights;
  291. static object[] preFlyHeightCools;
  292. public static void InitPreHeights() {
  293. preFlyHeights = new float[]{1.7f, 2.2f};
  294. preFlyHeightCools = new object[]{null, null};
  295. }
  296. public static float RandomOnePreHeight(Yeji yeji) {
  297. for (int i = 0; i < preFlyHeightCools.Length; i++) {
  298. if (preFlyHeightCools[i] == null) {
  299. preFlyHeightCools[i] = yeji;
  300. return preFlyHeights[i];
  301. }
  302. }
  303. return 2.5f;
  304. }
  305. public static void ReleasePreHeight(Yeji yeji) {
  306. for (int i = 0; i < preFlyHeightCools.Length; i++) {
  307. if (yeji.Equals(preFlyHeightCools[i])) {
  308. preFlyHeightCools[i] = null;
  309. }
  310. }
  311. }
  312. #endregion
  313. //状态
  314. [System.Serializable]
  315. public class State {
  316. public bool standing = false;
  317. [SerializeField] private bool _flyStaying = false;
  318. public bool flyStaying {
  319. get { return _flyStaying; }
  320. set {
  321. _flyStaying = value;
  322. animal.animator.SetBool("flyStaying", value);
  323. }
  324. }
  325. [SerializeField] private bool _dead;
  326. public bool dead {
  327. get { return _dead; }
  328. set {
  329. _dead = value;
  330. animal.animator.SetBool("dead", value);
  331. }
  332. }
  333. [SerializeField] private bool _down;
  334. public bool down {
  335. get { return _down; }
  336. set {
  337. _down = value;
  338. animal.animator.SetBool("down", value);
  339. }
  340. }
  341. [SerializeField] private bool _landing;
  342. public bool landing {
  343. get { return _landing; }
  344. set {
  345. _landing = value;
  346. animal.animator.SetBool("landing", value);
  347. }
  348. }
  349. [SerializeField] private bool _up;
  350. public bool up {
  351. get { return _up; }
  352. set {
  353. _up = value;
  354. animal.animator.SetBool("up", value);
  355. }
  356. }
  357. [SerializeField] private bool _flying;
  358. public bool flying {
  359. get { return _flying; }
  360. set {
  361. _flying = value;
  362. animal.animator.SetBool("flying", value);
  363. }
  364. }
  365. public Yeji animal;
  366. }
  367. [SerializeField] public State state;
  368. //委托
  369. public System.Action<Yeji> onDie;
  370. }