BattleController.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. import { _decorator, Component, Node, Prefab, instantiate, Vec3, UITransform, EventHandler, tween, math, UIOpacity, Label, } from 'cc';
  2. import { ResourcesUtils } from '../../core/resourceManager/ResourcesUtils';
  3. import { Sound } from '../../core/sound/Sound';
  4. import { WindowManager } from '../../core/ui/window/WindowManager';
  5. import { WindowOpenMode } from '../../core/ui/window/WindowOpenMode';
  6. import { g } from '../../Data/g';
  7. import { LoginWaitWin } from '../../Windows/LoginWaitWin';
  8. import { BattleRedPacketWindow } from './BattleRedPacketWindow';
  9. import { BattleRole, BattleRoleState } from './BattleRole';
  10. const { ccclass, property } = _decorator;
  11. /**战斗控制器 */
  12. @ccclass('BattleController')
  13. export class BattleController extends Component {
  14. @property({ tooltip: "神将资源路径" })
  15. public battleRolePrefabPath = '';
  16. @property({ tooltip: "特效资源路径" })
  17. public battleEffectPrefabPath = '';
  18. @property({ type: EventHandler, tooltip: "对战结束" })
  19. battleOverHanedler: EventHandler;
  20. @property({ type: Node, tooltip: "战斗位置区域" })
  21. battleNode: Node;
  22. @property({ type: Label, tooltip: "我方队伍人数文本" })
  23. ourNumLabel: Label;
  24. @property({ type: Label, tooltip: "敌方队伍人数文本" })
  25. enemyNumLabel: Label;
  26. @property({ type: Node, tooltip: "跳过" })
  27. skipNode: Node;
  28. /**我方战斗神将 */
  29. private ourGenerals: Array<BattleRole> = [];
  30. /**敌方方战斗神将 */
  31. private enemyGenerals: Array<BattleRole> = [];
  32. /*攻击数据 */
  33. private attackList = [];
  34. /**距离战斗点的长度 */
  35. private battleSpacing = 100;
  36. /**距离战斗点的长度 */
  37. private battleBackSpacting = 125;
  38. private initX = [0, -130, 130, -260, 260];
  39. private initY = -1000;//我方
  40. private col_num = 5;//列数
  41. private ourMaxHP: number = 0;
  42. private enemyMaxHp: number = 0;
  43. private startTime = 0;
  44. private checkTime = 2000;
  45. private startCheck = false;
  46. private isOver = false;
  47. start() {
  48. this.isOver = false;
  49. this.isFirst = true;
  50. let enemyNum = (g.battleData.enemyFriendDatas.length + g.battleData.enemyGenerals.length);
  51. enemyNum = enemyNum || 1;
  52. this.enemyNumLabel.string = enemyNum + '人';
  53. let ourNum = g.battleData.ourBattleGenerals.length;
  54. ourNum = ourNum || 1;
  55. this.ourNumLabel.string = ourNum + '人';
  56. }
  57. public async setData(data: any) {
  58. this.skipNode.active = true;
  59. this.ourGenerals = [];
  60. this.enemyGenerals = [];
  61. this.createOurGenerals();
  62. }
  63. update() {
  64. if (this.startCheck && this.startTime < Date.now()) {
  65. this.startTime = Date.now() + this.checkTime;
  66. this.checkBattle();
  67. }
  68. }
  69. /**
  70. * 创建战斗神将
  71. */
  72. private async createOurGenerals() {
  73. let _window = await WindowManager.open("Prefabs/Windows/加载等待窗口", WindowOpenMode.NotCloseAndCover);
  74. //敌方神将
  75. for (let i = g.battleData.enemyBattleGenerals.length - 1, j = 0; i >= 0; i--) {
  76. let preFabsData = await ResourcesUtils.load<Prefab>(this.battleRolePrefabPath, Prefab, this.node);
  77. var generalNode = instantiate(preFabsData);
  78. let general = generalNode.getComponent(BattleRole);
  79. general.name = "name" + i;
  80. general.isPlayAaimation = false;
  81. generalNode.parent = this.node;
  82. generalNode.position = new Vec3(this.initX[j], Math.abs(this.initY - Math.random() * 300), 0);
  83. general.setData(g.battleData.enemyBattleGenerals[i], BattleRoleState.Fight, false);
  84. j = ++j == 5 ? 0 : j;
  85. this.enemyMaxHp += general.HP;
  86. this.enemyGenerals.push(general);
  87. // break;
  88. }
  89. //我方神将
  90. for (let i = 0, j = 0; i < g.battleData.ourBattleGenerals.length; i++) {
  91. let preFabsData = await ResourcesUtils.load<Prefab>(this.battleRolePrefabPath, Prefab, this.node);
  92. var generalNode = instantiate(preFabsData);
  93. let general = generalNode.getComponent(BattleRole);
  94. general.isPlayAaimation = false;
  95. general.name = "name" + i;
  96. generalNode.parent = this.node;
  97. generalNode.position = new Vec3(this.initX[j], this.initY - Math.random() * 300, 0);
  98. general.setData(g.battleData.ourBattleGenerals[i], BattleRoleState.Fight);
  99. j = ++j == 5 ? 0 : j;
  100. this.ourMaxHP += general.HP;
  101. this.ourGenerals.push(general);
  102. // break;
  103. }
  104. _window.getComponent(LoginWaitWin).close();//关闭加载等待界面
  105. // this.startCheck = true;
  106. // this.battleStart();
  107. this.checkBattle();
  108. }
  109. private isFirst = true;
  110. /**距离检测战斗 */
  111. private checkBattle() {
  112. if (this.isOver) {
  113. return;
  114. }
  115. if (!this.ourGenerals.length || !this.enemyGenerals.length) {
  116. this.battleOver();
  117. return;
  118. }
  119. this.enemyGenerals.length > this.ourGenerals.length ? this.ourGenerals.length : this.enemyGenerals.length;
  120. let len = this.enemyGenerals.length > this.ourGenerals.length ? this.ourGenerals.length : this.enemyGenerals.length;
  121. for (let i = 0; i < len; i++) {
  122. let distance = Vec3.distance(this.enemyGenerals[i].node.position, this.ourGenerals[i].node.position);//距离
  123. let newPos = this.getBattlePosition(this.enemyGenerals[i].node.position, this.ourGenerals[i].node.position, this.enemyGenerals[i].speed / (this.ourGenerals[i].speed + this.enemyGenerals[i].speed));
  124. let distance1 = Vec3.distance(this.enemyGenerals[i].node.position, newPos[0]);//距离
  125. let distance2 = Vec3.distance(this.ourGenerals[i].node.position, newPos[0]);//距离
  126. let attackDelay = Math.random() * 0.3;
  127. this.setAttackData(attackDelay, false, this.enemyGenerals[i], this.ourGenerals[i].generalBaseData.attack, distance1 / this.enemyGenerals[i].speed, newPos[1], newPos[0], newPos[3]);
  128. this.setAttackData(attackDelay, true, this.ourGenerals[i], this.enemyGenerals[i].generalBaseData.attack, distance2 / this.ourGenerals[i].speed, newPos[2], newPos[0], newPos[4]);
  129. }
  130. if (this.enemyGenerals.length > this.ourGenerals.length) {
  131. for (let i = len; i < this.enemyGenerals.length; i++) {
  132. if (this.enemyGenerals[i].showState == BattleRoleState.Fight) {
  133. this.move(this.enemyGenerals[i], this.getBattleWaitPosition());
  134. }
  135. }
  136. } else {
  137. for (let i = len; i < this.ourGenerals.length; i++) {
  138. if (this.ourGenerals[i].showState == BattleRoleState.Fight) {
  139. this.move(this.ourGenerals[i], this.getBattleWaitPosition());
  140. }
  141. }
  142. }
  143. this.playAttack();
  144. }
  145. private setAttackData(attackDelay: number, showEffect: boolean, battleRole: BattleRole, attack: number, duration: number, tagretPos: Vec3, battlePos: Vec3, battleBack: Vec3) {
  146. this.attackList.push({ attackDelay, showEffect, general: battleRole, attack: attack, duration: duration, tagretPos: tagretPos, battlePos: battlePos, battleBack: battleBack });
  147. }
  148. private playAttack() {
  149. let i = 0;
  150. while (i < this.attackList.length) {
  151. // console.log(this.attackList[i].general.node.position);
  152. this.attackList[i].general.node.setSiblingIndex(this.node.children.length - 1);
  153. this.moveGeneral(this.attackList[i].attackDelay, this.attackList[i].showEffect, this.attackList[i].general, this.attackList[i].attack, this.attackList[i].duration, this.attackList[i].tagretPos, this.attackList[i].battlePos, this.attackList[i].battleBack);
  154. this.attackList.splice(0, 1);
  155. }
  156. }
  157. /*移动初始位置 */
  158. private moveGeneral(attackDelay: number, showEffect: boolean, battleRole: BattleRole, attack: number, duration: number, tagretPos: Vec3, battlePos: Vec3, battleBack: Vec3) {
  159. tween(battleRole.node).to(duration, { position: tagretPos }).call(() => {
  160. this.attack(attackDelay, showEffect, battleRole, attack, battlePos, battleBack);
  161. }).start();
  162. }
  163. public attack(attackDelay: number, showEffect: boolean, general: BattleRole, attack: number, v1: Vec3, v3: Vec3) {
  164. if (this.isOver) {
  165. return;
  166. }
  167. let nowPostion = general.node.position.clone();
  168. tween(general.node).
  169. to(attackDelay, { position: v3 }, { easing: "sineOut" }).
  170. call(() => {
  171. showEffect && this.playAttackSoundAndEffect(v1);
  172. }).
  173. to(0.15, { position: v1 }, { easing: "sineOut" }).
  174. to(0.2, { position: v3 }, { easing: "sineIn" }).
  175. to(0.05, { position: nowPostion }, { easing: "sineIn" }).call(() => {
  176. this.attackFinish(general, attack);
  177. }).start();
  178. }
  179. private myGeneralNum = 0;
  180. public attackFinish(general: BattleRole, attack: number) {
  181. if (this.isOver) {
  182. return;
  183. }
  184. general.setHp(attack);
  185. if (general.HP <= 0) {//delete 死亡
  186. general.HP = 0;
  187. if (this.ourGenerals.indexOf(general) != -1) {
  188. this.ourGenerals.splice(this.ourGenerals.indexOf(general), 1);
  189. }
  190. if (this.enemyGenerals.indexOf(general) != -1) {
  191. this.enemyGenerals.splice(this.enemyGenerals.indexOf(general), 1);
  192. }
  193. this.enemyNumLabel.string = this.enemyGenerals.length + '人';
  194. if (!this.ourGenerals.length && !this.enemyGenerals.length) {
  195. this.ourNumLabel.string = (this.ourGenerals.length == this.ourMaxHP ? 0 : 1) + '人';
  196. this.myGeneralNum = 1;
  197. return;
  198. }
  199. this.ourNumLabel.string = this.ourGenerals.length + '人';
  200. tween(general.node.getComponent(UIOpacity)).to(0.3, { opacity: 0 }).call(() => {
  201. general.node.active = false;
  202. }).start();
  203. }
  204. }
  205. //播放战斗光效和声音
  206. private async playAttackSoundAndEffect(point: Vec3) {
  207. let effect = await ResourcesUtils.load<Prefab>(this.battleEffectPrefabPath, null, this.node);
  208. let effectNode = instantiate(effect);
  209. effectNode.parent = this.node;
  210. effectNode.setPosition(point);
  211. if (this.isFirst) {
  212. this.startTime = Date.now() + this.checkTime - 1000;
  213. this.isFirst = false;
  214. this.startCheck = true;
  215. }
  216. // this.attactSound.play();
  217. }
  218. /**没有攻击目标神将移动*/
  219. private move(general: BattleRole, point: Vec3) {
  220. tween(general.node).to(Math.random() * 5 + (Vec3.distance(general.node.position, point) / general.speed), { position: point }).call(() => {
  221. general.battleState = BattleRoleState.Move;
  222. }).start();
  223. }
  224. private onJump() {
  225. this.battleOver(true);
  226. }
  227. private battleOver(isJump: boolean = false) {
  228. if (this.isOver) {
  229. return;
  230. }
  231. this.isOver = true;
  232. if (isJump) {
  233. g.battleData.isWin = this.ourMaxHP >= this.enemyMaxHp;//谁血多谁赢
  234. } else {
  235. if (this.ourGenerals.length != this.enemyGenerals.length) {
  236. g.battleData.isWin = this.ourGenerals.length > this.enemyGenerals.length;
  237. } else {
  238. if (this.myGeneralNum) {
  239. g.battleData.isWin = true;
  240. this.myGeneralNum = 0;
  241. } else {
  242. g.battleData.isWin = this.ourMaxHP >= this.enemyMaxHp;//谁血多谁赢
  243. }
  244. }
  245. }
  246. this.skipNode.active = false;
  247. this.startCheck = false;
  248. for (let i = 0; i < this.ourGenerals.length; i++) {
  249. this.ourGenerals[i].battleState = BattleRoleState.Fight;
  250. }
  251. for (let i = 0; i < this.enemyGenerals.length; i++) {
  252. this.enemyGenerals[i].battleState = BattleRoleState.Fight;
  253. }
  254. this.enemyGenerals = [];
  255. this.ourGenerals = [];
  256. this.battleOverHanedler.emit([]);//战斗结束
  257. }
  258. /**战斗坐标计算 */
  259. private getBattlePosition(point1: Vec3, point2: Vec3, point1_ratio: number) {
  260. let w = point1.x > point2.x ? point1.x - point2.x : point2.x - point1.x;
  261. let h = point1.y > point2.y ? point1.y - point2.y : point2.y - point1.y;
  262. let newx = point1.x > point2.x ? point1.x - w * point1_ratio : point2.x - w * (1 - point1_ratio);
  263. let newy = point1.y > point2.y ? point1.y - h * point1_ratio : point2.y - h * (1 - point1_ratio);
  264. let battlePoint = new Vec3(newx, newy, 0);//战斗位置
  265. // console.log(battlePoint);
  266. let ration = Math.sqrt(this.battleSpacing * this.battleSpacing / (w * w + h * h));//神将位置比
  267. let ww = ration * w;
  268. let hh = ration * h;
  269. let point1Battle = new Vec3(newx + ww, newy + hh, 0);//神将位置1
  270. let point2Battle = new Vec3(newx - ww, newy - hh, 0);//神将位置2
  271. let ration1 = Math.sqrt(this.battleBackSpacting * this.battleBackSpacting / (w * w + h * h));//第一个神将战斗后退位置比
  272. let www = ration1 * w;
  273. let hhh = ration1 * h;
  274. let point1Back = new Vec3(newx + www, newy + hhh, 0);//神将战斗后退位置1
  275. let point2Back = new Vec3(newx - www, newy - hhh, 0);//神将战斗后退位置2
  276. //战斗占, 敌方点,我方点
  277. return [battlePoint, point1Battle, point2Battle, point1Back, point2Back];
  278. }
  279. /** */
  280. private getBattleWaitPosition() {
  281. let targetIndex = Math.floor(Math.random() * 5);
  282. let targetX = (Math.random() > 0.5 ? +Math.random() * 200 : -Math.random() * 200);
  283. let targetY = (Math.random() > 0.5 ? +Math.random() * 200 : -Math.random() * 200);
  284. return new Vec3(targetX, targetY, 0);
  285. }
  286. }