Boss.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. using Spine.Unity;
  2. using Spine;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using TMPro;
  7. using Sirenix.OdinInspector;
  8. public enum AttackCategories
  9. {
  10. A = 0,
  11. B = 1,
  12. C = 2,
  13. }
  14. public class Boss : MoveCharacter
  15. {
  16. private enum ChangeRoomState
  17. {
  18. none,
  19. disappear,
  20. teleport,
  21. createRoom,
  22. }
  23. //(主要针对受击状态等)
  24. public enum BossState
  25. {
  26. normal = 0,
  27. weak = 1,
  28. invincible = 2,
  29. rise = 3, //从weak回到normal时回升高度
  30. }
  31. [Space(30)]
  32. [Header("Boss属性")]
  33. [Header("当前索敌是对塔还是对玩家")]
  34. public TargetType curTarget;
  35. [HideInInspector]
  36. public PlayerController pc;
  37. [Header("idle动画")]
  38. public string[] idleAniNames;
  39. public int[] weight;
  40. [Header("Boss攻击规律")]
  41. public string circulate; //循环配置
  42. private int len;
  43. public AttackCategories[] categories; //循环大类
  44. private AttackCategories curCategory; //当前攻击大类
  45. private int curCategoryID;
  46. public float minInterval, maxInterval; //间隔时间
  47. public float curInterval;
  48. [FoldoutGroup("角色信息")]
  49. public BossState bossState;
  50. private BossState oldState;
  51. /*[LabelText("耐力值")]
  52. public int totalPatience; //初始耐力值上限
  53. private int curPatience; //当前耐力值
  54. public UIHP uiPatience; //耐力值的条
  55. [LabelText("每次的上限值缩减量")]
  56. public float[] delPorpotation;
  57. private int curDelPorID;
  58. private int curTotalPatience; //当前耐力值上限
  59. private bool noNeedChange; //耐力值到底了,不用再缩减了*/
  60. [LabelText("虚弱时长")]
  61. public float weakTime;
  62. private float pastWeakTime;
  63. [Header("boss独立房间")]
  64. [LabelText("boss的独立空间")]
  65. public GameObject bossRoom;
  66. private GameObject bossRoomIns;
  67. private int startHP; //开始计数的血量
  68. private ChangeRoomState rs;
  69. private bool isToBossRoom; //要切换到boss空间中
  70. private bool isInBossRoom; //在boss空间中
  71. [LabelText("切换到boss空间的血量扣除值")]
  72. public float toBossNeedHP;
  73. [LabelText("切换到boss空间的次数")]
  74. public int toBossTime;
  75. [LabelText("切换回原空间所需的时间")]
  76. public float toOrigNeedTime;
  77. private float changeBackTime;
  78. [LabelText("切换到原空间所需的血量")]
  79. public float toOrigNeedHP;
  80. //动画时长
  81. [LabelText("消失动画时长")]
  82. public float disappearAniTime;
  83. [LabelText("消失时长")]
  84. public float disappearTime;
  85. [LabelText("制造房间动画时长")]
  86. public float createRoomTime;
  87. [LabelText("出现后多久切换房间")]
  88. public float changeRoomTime;
  89. private float changeAniTime;
  90. private AttributeStatus status;
  91. public override void Init()
  92. {
  93. //确保组件不丢失
  94. if (!ani)
  95. {
  96. ani = GetComponentInChildren<Animator>();
  97. }
  98. if (!mecanim)
  99. {
  100. mecanim = GetComponentInChildren<SkeletonMecanim>();
  101. }
  102. if (!meshRenderer)
  103. {
  104. meshRenderer = mecanim.GetComponent<MeshRenderer>();
  105. }
  106. //玩家
  107. pc = PlayersInput.instance[0];
  108. nowCanFly = canFly;
  109. //血量重置
  110. hp = totalHp;
  111. startHP = totalHp;
  112. uiHp.Show(hp, totalHp);
  113. ChangeState(CharacterState.Idle);
  114. curInterval = Random.Range(minInterval, maxInterval);
  115. /*
  116. //耐力条
  117. curTotalPatience = totalPatience;
  118. curPatience = curTotalPatience;
  119. uiPatience.Show(curPatience, curTotalPatience);*/
  120. //特殊状态脚本
  121. status = beHitTrigger.GetComponent<AttributeStatus>();
  122. }
  123. public virtual void Start()
  124. {
  125. len = circulate.Length;
  126. int cur = 0;
  127. categories = new AttackCategories[len];
  128. foreach(char c in circulate)
  129. {
  130. switch (c)
  131. {
  132. case 'A':
  133. categories[cur] = AttackCategories.A;
  134. break;
  135. case 'B':
  136. categories[cur] = AttackCategories.B;
  137. break;
  138. case 'C':
  139. categories[cur] = AttackCategories.C;
  140. break;
  141. default:
  142. break;
  143. }
  144. cur++;
  145. }
  146. curCategory = categories[0];
  147. }
  148. public override void BeHit(AttackController.AttackMethod attackMethod, Character attackFrom, int damage = -1)
  149. {
  150. switch (bossState)
  151. {
  152. //有耐力值
  153. case BossState.normal:
  154. base.BeHit(attackMethod, attackFrom, damage);
  155. /*//打耐力条
  156. int damageData;
  157. if (damage == -1)
  158. {
  159. damageData = attackInfo.damage;
  160. }
  161. else
  162. {
  163. damageData = damage;
  164. }
  165. curPatience -= damageData;
  166. //耐力值打完了,该次溢出伤害不记录,进入weak状态
  167. if (curPatience <= 0)
  168. {
  169. curPatience = 0;
  170. ChangeBossState(BossState.weak);
  171. }
  172. uiPatience.Show(curPatience, curTotalPatience);*/
  173. break;
  174. //耐力值破
  175. case BossState.weak:
  176. base.BeHit(attackMethod, attackFrom, damage);
  177. if (hp > 0)
  178. {
  179. JudgeIfChangeBG();
  180. }
  181. break;
  182. //霸体
  183. case BossState.invincible:
  184. break;
  185. }
  186. }
  187. public virtual void Attack()
  188. {
  189. }
  190. public virtual void OnAttack()
  191. {
  192. }
  193. //攻击时被强制切换状态,清空所有遗留在外的技能
  194. //如:水诡释放黑伞时被击晕,黑伞消失
  195. public virtual void ClearAllSkills()
  196. {
  197. }
  198. //切换boss状态(主要针对受击状态等)
  199. public void ChangeBossState(BossState bs)
  200. {
  201. if (bs == bossState)
  202. {
  203. return;
  204. }
  205. oldState = bossState;
  206. switch (bossState)
  207. {
  208. case BossState.weak:
  209. //计算当前耐力值上限缩减程度
  210. rb.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionZ | RigidbodyConstraints.FreezePositionY;
  211. /*float curDelPor = delPorpotation[curDelPorID];
  212. if (curDelPorID < delPorpotation.Length - 1)
  213. {
  214. curDelPorID++;
  215. }
  216. else
  217. {
  218. noNeedChange = true;
  219. }
  220. if (!noNeedChange)
  221. {
  222. //调整耐力值UI长度
  223. uiPatience.ChangeLength(curDelPor);
  224. //调整耐力值上限
  225. curTotalPatience = (int)(totalPatience * curDelPor);
  226. }
  227. //将当前耐力值重置为新上限
  228. curPatience = curTotalPatience;
  229. //重置耐力条
  230. uiPatience.Show(curPatience, curTotalPatience);*/
  231. //清空特殊状态
  232. status.OutSpecialState();
  233. //飞行
  234. nowCanFly = canFly;
  235. //播放roar动画
  236. ani.Play("roar", 0, 0);
  237. break;
  238. }
  239. bossState = bs;
  240. switch (bs)
  241. {
  242. case BossState.weak:
  243. ClearAllSkills();
  244. ani.Play("fall", 0, 0);
  245. rb.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionZ;
  246. ChangeState(CharacterState.Idle);
  247. pastWeakTime = weakTime;
  248. nowCanFly = false;
  249. rb.useGravity = true;
  250. break;
  251. case BossState.rise:
  252. if (oldState != BossState.weak)
  253. {
  254. int randomAni = RandomWithWeight(weight);
  255. ani.Play(idleAniNames[randomAni], 0, 0);
  256. }
  257. rb.velocity = Vector3.zero;
  258. flyHeight = Random.Range(minFlyHeight, maxFlyHeight);
  259. break;
  260. }
  261. ani.speed = 1;
  262. }
  263. private void OnBossState()
  264. {
  265. switch (bossState)
  266. {
  267. case BossState.weak:
  268. pastWeakTime -= Time.deltaTime;
  269. if (pastWeakTime <= 0)
  270. {
  271. ChangeBossState(BossState.rise);
  272. }
  273. break;
  274. case BossState.rise:
  275. if (AdjustHeight())
  276. {
  277. ChangeBossState(BossState.normal);
  278. }
  279. break;
  280. }
  281. }
  282. public override void ChangeState(CharacterState newState)
  283. {
  284. if (state == newState || newState == CharacterState.FramePause)
  285. {
  286. return;
  287. }
  288. switch (state)
  289. {
  290. case CharacterState.Attack:
  291. ClearAllSkills();
  292. break;
  293. case CharacterState.Run:
  294. rb.velocity = Vector3.zero;
  295. break;
  296. default:
  297. break;
  298. }
  299. state = newState;
  300. switch (newState)
  301. {
  302. case CharacterState.Idle:
  303. if (bossState != BossState.weak)
  304. {
  305. int randomAni = RandomWithWeight(weight);
  306. ani.Play(idleAniNames[randomAni], 0, 0);
  307. }
  308. break;
  309. case CharacterState.Run:
  310. ToMove();
  311. break;
  312. case CharacterState.Die:
  313. ani.Play("die", 0, 0);
  314. gameObject.SetActive(false);
  315. break;
  316. case CharacterState.Attack:
  317. if (!isToBossRoom)
  318. {
  319. Attack();
  320. }
  321. break;
  322. default:
  323. break;
  324. }
  325. }
  326. public override void OnState()
  327. {
  328. switch (state)
  329. {
  330. case CharacterState.Idle:
  331. if (isToBossRoom)
  332. {
  333. OnChangeBG();
  334. }
  335. else if (bossState != BossState.weak)
  336. {
  337. curInterval -= Time.deltaTime;
  338. if (curInterval <= 0)
  339. {
  340. RandomAttackState();
  341. }
  342. }
  343. break;
  344. case CharacterState.Run:
  345. OnMove();
  346. break;
  347. case CharacterState.Attack:
  348. OnAttack();
  349. break;
  350. case CharacterState.HitStun:
  351. hitFeedbackSystem.HitStunUpdate();
  352. break;
  353. case CharacterState.SpecialStatus_Float:
  354. attributeStatus.SpecialStateEffect(SpecialState.FloatState);
  355. break;
  356. case CharacterState.SpecialStatus_BlowUp:
  357. attributeStatus.SpecialStateEffect(SpecialState.BlownUp);
  358. break;
  359. case CharacterState.SpecialStatus_ShotDown:
  360. attributeStatus.SpecialStateEffect(SpecialState.ShotDown);
  361. break;
  362. case CharacterState.SpecialStatus_Weak:
  363. attributeStatus.SpecialStateEffect(SpecialState.Weak);
  364. break;
  365. default:
  366. break;
  367. }
  368. if (isInBossRoom)
  369. {
  370. changeBackTime += Time.deltaTime;
  371. if (changeBackTime >= toOrigNeedTime)
  372. {
  373. ChangeBG(false);
  374. changeBackTime = 0;
  375. }
  376. }
  377. OnBossState();
  378. }
  379. public virtual void ToMove()
  380. {
  381. }
  382. public virtual void OnMove()
  383. {
  384. }
  385. //根据当前大类随机攻击方式
  386. public virtual void RandomAttackType(AttackCategories cate)
  387. {
  388. }
  389. public void RandomAttackState()
  390. {
  391. switch (curCategory)
  392. {
  393. case AttackCategories.A:
  394. RandomAttackType(AttackCategories.A);
  395. break;
  396. case AttackCategories.B:
  397. RandomAttackType(AttackCategories.B);
  398. break;
  399. default:
  400. break;
  401. }
  402. curCategoryID++;
  403. if (curCategoryID == len)
  404. {
  405. curCategoryID = 0;
  406. }
  407. curCategory = categories[curCategoryID];
  408. ChangeState(CharacterState.Attack);
  409. }
  410. public void EndCurAttackState(bool hasIntervalTime)
  411. {
  412. //和下一个动作有没有间隔
  413. if (hasIntervalTime)
  414. {
  415. curInterval = Random.Range(minInterval, maxInterval);
  416. }
  417. ChangeState(CharacterState.Idle);
  418. ChangeBossState(BossState.rise);
  419. }
  420. //权重随机
  421. //传入权重int[],返回第random组
  422. public int RandomWithWeight(int[] weight)
  423. {
  424. int all = 0;
  425. foreach(int i in weight)
  426. {
  427. all += i;
  428. }
  429. int a = Random.Range(0, all);
  430. int b = 0;
  431. for(int i = 0; i < weight.Length - 1; i++)
  432. {
  433. b += weight[i];
  434. if (a < b)
  435. {
  436. return i;
  437. }
  438. }
  439. return weight.Length - 1;
  440. }
  441. private void ToChangeRoom(ChangeRoomState crs)
  442. {
  443. //消失前动画-消失动画-瞬移特效-出现动画-制造房间动画
  444. if (rs == crs)
  445. {
  446. return;
  447. }
  448. rs = crs;
  449. switch (rs)
  450. {
  451. case ChangeRoomState.none:
  452. break;
  453. case ChangeRoomState.disappear:
  454. ani.Play("roar", 0, 0);
  455. startHP = hp;
  456. break;
  457. case ChangeRoomState.teleport: //瞬移
  458. //ani.Play("", 0, 0);
  459. bodyTrans.gameObject.SetActive(false);
  460. break;
  461. case ChangeRoomState.createRoom:
  462. transform.position = pc.transform.position;
  463. bodyTrans.gameObject.SetActive(true);
  464. ani.Play("roar", 0, 0);
  465. ChangeBG(true);
  466. break;
  467. default:
  468. break;
  469. }
  470. }
  471. private void OnChangeBG()
  472. {
  473. switch (rs)
  474. {
  475. case ChangeRoomState.disappear:
  476. changeAniTime += Time.deltaTime;
  477. if (changeAniTime >= disappearAniTime)
  478. {
  479. ToChangeRoom(ChangeRoomState.teleport);
  480. changeAniTime = 0;
  481. }
  482. break;
  483. case ChangeRoomState.teleport:
  484. changeAniTime += Time.deltaTime;
  485. if (changeAniTime >= disappearTime)
  486. {
  487. ToChangeRoom(ChangeRoomState.createRoom);
  488. changeAniTime = 0;
  489. }
  490. break;
  491. case ChangeRoomState.createRoom:
  492. changeAniTime += Time.deltaTime;
  493. if (changeAniTime >= createRoomTime)
  494. {
  495. ToChangeRoom(ChangeRoomState.none);
  496. changeAniTime = 0;
  497. isToBossRoom = false;
  498. ChangeState(CharacterState.Idle);
  499. ChangeBossState(BossState.rise);
  500. }
  501. break;
  502. default:
  503. break;
  504. }
  505. }
  506. //拉入boss房间(通过切换bg实现)
  507. private void ChangeBG(bool isToBossBG)
  508. {
  509. if (isToBossBG)
  510. {
  511. isInBossRoom = true;
  512. if (!bossRoomIns)
  513. {
  514. bossRoomIns = Instantiate(bossRoom);
  515. }
  516. bossRoomIns.SetActive(true);
  517. GameManager.instance.chapterBG.SetActive(false);
  518. }
  519. else
  520. {
  521. isInBossRoom = false;
  522. bossRoomIns.SetActive(false);
  523. GameManager.instance.chapterBG.SetActive(true);
  524. }
  525. pc.foot.trigGroundList.Clear();
  526. startHP = hp;
  527. ChangeBossState(BossState.invincible);
  528. }
  529. //判断是否要切换boss房间
  530. private void JudgeIfChangeBG()
  531. {
  532. if (isToBossRoom) //换房间中
  533. {
  534. return;
  535. }
  536. if (isInBossRoom)
  537. {
  538. if (startHP - hp >= toOrigNeedHP)
  539. {
  540. ani.Play("roar", 0, 0);
  541. isToBossRoom = true;
  542. ChangeBG(false);
  543. }
  544. return;
  545. }
  546. if (toBossTime <= 0) //boss是否还有转房间次数
  547. {
  548. return;
  549. }
  550. if (startHP - hp >= toBossNeedHP)
  551. {
  552. toBossTime--;
  553. isToBossRoom = true;
  554. ChangeState(CharacterState.Idle);
  555. ToChangeRoom(ChangeRoomState.disappear);
  556. }
  557. }
  558. }