Boss.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. using Spine.Unity;
  2. using Spine;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using TMPro;
  7. public enum AttackState
  8. {
  9. Idle = 0, //待机
  10. Attack = 1, //攻击
  11. Die = 2, //死亡
  12. Weak = 3, //虚弱
  13. }
  14. public enum AttackCategories
  15. {
  16. A = 0,
  17. B = 1,
  18. }
  19. [System.Serializable]
  20. public struct BossState
  21. {
  22. public int coreHp; //核心血量
  23. public float scale; //体型
  24. public StateWeakness[] weaknesses; //弱点
  25. public GameObject core;
  26. }
  27. [System.Serializable]
  28. public struct StateWeakness
  29. {
  30. public GameObject obj;
  31. public int Hp;
  32. }
  33. public class Boss : MoveCharacter
  34. {
  35. [Header("Boss属性")]
  36. public BossState[] states; //阶段
  37. private int maxStateId; //最高为第几阶段,0开始
  38. public int curStateId; //当前处于阶段n
  39. private BossState curState;
  40. private int curStateTotalHp; //当前阶段总血量
  41. public int restWeaknessNum; //剩余弱点数量
  42. private Weakness coreWeakness;
  43. public GameObject roarEffect;
  44. public float roarTime;
  45. public bool isChangeState;
  46. [Header("核心受到伤害倍率")]
  47. public int coreDamageRate;
  48. [Header("当前索敌是对塔还是对玩家")]
  49. public TargetType curTarget;
  50. [Header("Boss攻击规律")]
  51. public string circulate; //循环配置
  52. private int len;
  53. public AttackCategories[] categories; //循环大类
  54. private AttackCategories curCategory; //当前攻击大类
  55. public int curCategoryID;
  56. public float minInterval, maxInterval; //间隔时间
  57. private float curInterval;
  58. //计算当前形态总血量
  59. private void CalculateHp()
  60. {
  61. curStateTotalHp = curState.coreHp * coreDamageRate;
  62. foreach(StateWeakness w in curState.weaknesses)
  63. {
  64. curStateTotalHp += w.Hp;
  65. }
  66. totalHp = curStateTotalHp;
  67. hp = totalHp;
  68. uiHp.Show(hp, totalHp);
  69. }
  70. //切换形态
  71. private void ChangeBossState()
  72. {
  73. curState = states[curStateId];
  74. toLargeSize = curState.scale;
  75. beLarger = true;
  76. ChangeWeakness();
  77. CalculateHp();
  78. curInterval = Random.Range(minInterval, maxInterval);
  79. }
  80. //切换弱点
  81. private void ChangeWeakness()
  82. {
  83. StateWeakness[] ws = curState.weaknesses;
  84. restWeaknessNum = ws.Length;
  85. for (int i = 0; i < restWeaknessNum; i++)
  86. {
  87. Weakness w = ws[i].obj.GetComponent<Weakness>();
  88. w.totalHp = ws[i].Hp;
  89. w.boss = this;
  90. ws[i].obj.SetActive(true);
  91. ws[i].obj.GetComponentInChildren<ParticleSystem>().Play();
  92. }
  93. }
  94. public override void Init()
  95. {
  96. //确保组件不丢失
  97. if (!ani)
  98. {
  99. ani = GetComponentInChildren<Animator>();
  100. }
  101. //血量重置
  102. hp = totalHp;
  103. uiHp.Show(hp, totalHp);
  104. ChangeState(CharacterState.Idle);
  105. curInterval = Random.Range(minInterval, maxInterval);
  106. }
  107. private void Awake()
  108. {
  109. }
  110. public virtual void Start()
  111. {
  112. len = circulate.Length;
  113. ChangeBossState();
  114. Init();
  115. maxStateId = states.Length - 1;
  116. int cur = 0;
  117. categories = new AttackCategories[len];
  118. foreach(char c in circulate)
  119. {
  120. switch (c)
  121. {
  122. case 'A':
  123. categories[cur] = AttackCategories.A;
  124. break;
  125. case 'B':
  126. categories[cur] = AttackCategories.B;
  127. break;
  128. default:
  129. break;
  130. }
  131. cur++;
  132. }
  133. curCategory = categories[0];
  134. }
  135. public override void BeHit(int damage, Vector3 force, bool changeHurt, float repelValue)
  136. {
  137. if (restWeaknessNum == 0)
  138. {
  139. damage *= coreDamageRate;
  140. }
  141. hp -= damage;
  142. //伤害跳字
  143. if (showInjuryNum)
  144. {
  145. GameObject injuryNum = Instantiate(injuryNumText);
  146. injuryNum.transform.position = new Vector3(transform.position.x + Random.Range(-1f, 1f), transform.position.y + 1, transform.position.z);
  147. TextMeshProUGUI text = injuryNum.GetComponentInChildren<TextMeshProUGUI>();
  148. text.text = damage.ToString();
  149. if (gameObject.CompareTag("Player"))
  150. {
  151. text.color = Color.red;
  152. }
  153. }
  154. uiHp.Show(hp, totalHp);
  155. if (hp <= 0)
  156. {
  157. coreWeakness.ChangeState(CharacterState.Die);
  158. if (curStateId < maxStateId)
  159. {
  160. curStateId++;
  161. isChangeState = true;
  162. roarEffect.SetActive(true);
  163. roarEffect.GetComponentInChildren<ParticleSystem>().Play();
  164. ChangeState(CharacterState.Idle);
  165. Invoke("ChangeBossState", roarTime);
  166. }
  167. else
  168. {
  169. ChangeState(CharacterState.Die);
  170. }
  171. return;
  172. }
  173. }
  174. public void CheckCoreOut()
  175. {
  176. restWeaknessNum -= 1;
  177. if (restWeaknessNum == 0)
  178. {
  179. coreWeakness = curState.core.GetComponent<Weakness>();
  180. coreWeakness.boss = this;
  181. coreWeakness.isCore = true;
  182. curState.core.SetActive(true);
  183. curState.core.GetComponentInChildren<ParticleSystem>().Play();
  184. }
  185. }
  186. public override void Update()
  187. {
  188. if (beLarger)
  189. {
  190. Enlarge();
  191. if (toLargeSize == 0)
  192. {
  193. isChangeState = false;
  194. }
  195. }
  196. }
  197. public virtual void Attack()
  198. {
  199. }
  200. public override void ChangeState(CharacterState newState)
  201. {
  202. if (newState == state)
  203. {
  204. return;
  205. }
  206. switch (state)
  207. {
  208. case CharacterState.Run:
  209. rb.velocity = Vector3.zero;
  210. break;
  211. default:
  212. break;
  213. }
  214. state = newState;
  215. switch (newState)
  216. {
  217. case CharacterState.Idle:
  218. ani.Play("idle", 0, 0);
  219. break;
  220. case CharacterState.Run:
  221. ToMove();
  222. break;
  223. case CharacterState.Die:
  224. ani.Play("die", 0, 0);
  225. gameObject.SetActive(false);
  226. break;
  227. case CharacterState.Attack:
  228. Attack();
  229. break;
  230. default:
  231. break;
  232. }
  233. }
  234. public override void OnState()
  235. {
  236. switch (state)
  237. {
  238. case CharacterState.Idle:
  239. if (!isChangeState)
  240. {
  241. curInterval -= Time.deltaTime;
  242. if (curInterval <= 0)
  243. {
  244. RandomAttackState();
  245. }
  246. }
  247. break;
  248. case CharacterState.Run:
  249. OnMove();
  250. break;
  251. default:
  252. break;
  253. }
  254. }
  255. public virtual void ToMove()
  256. {
  257. }
  258. public virtual void OnMove()
  259. {
  260. }
  261. public void CheckTarget()
  262. {
  263. Character curTar = null;
  264. switch (curTarget)
  265. {
  266. case TargetType.Tower:
  267. float minDis = -1;
  268. foreach(GameObject g in TowerMap.myTowers)
  269. {
  270. float dis = Vector2.Distance(g.transform.position, transform.position);
  271. if (minDis == -1 || dis < minDis)
  272. {
  273. minDis = dis;
  274. curTar = g.GetComponent<Character>();
  275. }
  276. }
  277. break;
  278. case TargetType.Player:
  279. PlayerController p1 = PlayersInput.instance[0];
  280. PlayerController p2 = PlayersInput.instance[1];
  281. bool p1Alive = (p1 != null && !p1.isRevive);
  282. bool p2Alive = (p2 != null && !p2.isRevive);
  283. float dis1 = Vector2.Distance(transform.position, p1.transform.position);
  284. float dis2 = Vector2.Distance(transform.position, p2.transform.position);
  285. if (p1Alive)
  286. {
  287. if (p2Alive)
  288. {
  289. curTar = dis1 > dis2 ? p1 : p2;
  290. }
  291. else
  292. {
  293. curTar = p1;
  294. }
  295. }
  296. else
  297. {
  298. if(p2Alive)
  299. {
  300. curTar = p2;
  301. }
  302. }
  303. break;
  304. default:
  305. break;
  306. }
  307. targetCharacter = curTar;
  308. }
  309. public virtual void RandomAttackType(AttackCategories cate)
  310. {
  311. }
  312. public void RandomAttackState()
  313. {
  314. switch (curCategory)
  315. {
  316. case AttackCategories.A:
  317. RandomAttackType(AttackCategories.A);
  318. break;
  319. case AttackCategories.B:
  320. RandomAttackType(AttackCategories.B);
  321. break;
  322. default:
  323. break;
  324. }
  325. curCategoryID++;
  326. if (curCategoryID == len)
  327. {
  328. curCategoryID = 0;
  329. }
  330. curCategory = categories[curCategoryID];
  331. ChangeState(CharacterState.Attack);
  332. }
  333. public void EndCurAttackState(bool hasIntervalTime)
  334. {
  335. //和下一个动作有没有间隔
  336. if (hasIntervalTime)
  337. {
  338. curInterval = Random.Range(minInterval, maxInterval);
  339. }
  340. ChangeState(CharacterState.Idle);
  341. }
  342. }