gameCtr.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. import {
  2. _decorator,
  3. Animation,
  4. AnimationClip,
  5. CharacterController,
  6. Color,
  7. Component,
  8. director,
  9. EventMouse,
  10. EventTouch,
  11. Label,
  12. Node,
  13. NodeEventType,
  14. ProgressBar,
  15. Sprite,
  16. tween,
  17. Tween,
  18. UIOpacity,
  19. UITransform,
  20. v3,
  21. Vec2,
  22. Vec3
  23. } from "cc"
  24. import { noticePannelCtr } from "./noticePannelCtr"
  25. import { StoryPannelCtr } from "./StoryPannelCtr"
  26. import { OptionsCtr } from "./OptionsCtr"
  27. import { rankCtr } from "./rankCtr"
  28. import { RoleCtr } from "./RoleCtr"
  29. import { processCtr } from "./socket/processCtr"
  30. import { SocketClient } from "./socket/SocketClient"
  31. const { ccclass, property } = _decorator
  32. @ccclass("GameCtr")
  33. export class GameCtr extends Component {
  34. @property({ type: noticePannelCtr })
  35. public noticeCtr: noticePannelCtr | null = null
  36. @property({ type: SocketClient })
  37. public socketClient: SocketClient | null = null
  38. @property({ type: processCtr })
  39. public processCtr: processCtr | null = null
  40. @property({ type: RoleCtr })
  41. public roleCtr: RoleCtr | null = null
  42. @property({ type: StoryPannelCtr })
  43. public storyPannelCtr: StoryPannelCtr | null = null
  44. @property({ type: OptionsCtr })
  45. public optionsCtr: OptionsCtr | null = null
  46. @property({ type: rankCtr })
  47. public rankCtr: rankCtr | null = null
  48. @property({ type: Node })
  49. public titlePannel: Node = null
  50. @property({ type: Label })
  51. private dayLabel: Label | null = null
  52. @property(Animation)
  53. SunAnim: Animation = null
  54. @property(Animation)
  55. MoonAnim: Animation = null
  56. private sunIsUp: boolean = false
  57. private num: number = 1
  58. public roomId: number = 1
  59. public gameId: number = 1
  60. private gameInfo: any = null
  61. private historyInfo: any[] = []
  62. private initStoryPosition: Vec3 = null
  63. private initOptionsPosition: Vec3 = null
  64. //剧情布局变化状态:0:展示剧情 ,1:出现选项框 2:已选选项下方展示剧情,3:已选移除剧情上移出现选项框
  65. private storyActionStatus: number = 0
  66. //重启动画
  67. @property({ type: Label })
  68. public resetLabel: Label = null
  69. @property({ type: ProgressBar })
  70. public progressBar: ProgressBar = null
  71. @property({ type: Node })
  72. public resetNode: Node = null
  73. private _dotsCounter: number = 0
  74. private _dotsInterval: any = null
  75. //剧情选项相关
  76. private options: any[] = []
  77. private optionsLabel: string[] = []
  78. private storyHeight = 510
  79. private selectedOptionNum: number = 4
  80. //排名相关
  81. private rankInfo: any[] = []
  82. //角色信息
  83. private npc: any[] = null
  84. private player: any[] = null
  85. //简历角色名-node 字典
  86. private roleNodes = {}
  87. private modifyHp: any[]
  88. //确认正式同步后台数据正式开始标签
  89. private realStart: boolean = false
  90. //通知相关
  91. private noticeStr:string = ''
  92. init() {
  93. const roomUrl = `https://airpg1.izouma.com/api/room/${this.roomId}`
  94. fetch(roomUrl)
  95. .then((response) => {
  96. if (!response.ok) {
  97. throw new Error("Network response was not ok")
  98. }
  99. return response.json()
  100. })
  101. .then((data) => {
  102. //获取游戏ID,房间信息
  103. console.log(data.currentGameId + " " + data.active)
  104. this.gameId = data.currentGameId
  105. this.noticeStr = data.notice
  106. if (this.socketClient.socket) {
  107. this.socketClient.socket.disconnect();
  108. } else {
  109. this.socketClient.gameId = this.gameId
  110. this.socketClient.initSocketConnection();
  111. }
  112. const gameUrl = `https://airpg1.izouma.com/api/game/${this.gameId}`
  113. fetch(gameUrl)
  114. .then((response) => {
  115. if (!response.ok) {
  116. throw new Error("Network response was not ok")
  117. }
  118. return response.json()
  119. })
  120. .then((data) => {
  121. console.log(data)
  122. const historyUrl = `https://airpg1.izouma.com/api/game/${this.gameId}/history`
  123. this.gameInfo = data
  124. fetch(historyUrl)
  125. .then((response) => {
  126. if (!response.ok) {
  127. throw new Error("Network response was not ok")
  128. }
  129. return response.json()
  130. })
  131. .then((data) => {
  132. console.log("history")
  133. console.log(data)
  134. this.historyInfo = data
  135. //根据游戏信息与历史信息更新房间组件
  136. this.updateGame(this.gameInfo, this.historyInfo)
  137. })
  138. .catch((error) => {
  139. console.error("Fetch error:", error)
  140. })
  141. })
  142. .catch((error) => {
  143. console.error("Fetch error:", error)
  144. })
  145. })
  146. .catch((error) => {
  147. console.error("Fetch error:", error)
  148. })
  149. this.initRank(roomUrl + '/survivalRank')
  150. }
  151. initRank(url: string) {
  152. fetch(url)
  153. .then((response) => {
  154. if (!response.ok) {
  155. throw new Error("Network response was not ok")
  156. }
  157. return response.json()
  158. })
  159. .then((data) => {
  160. console.log("rank")
  161. console.log(data)
  162. this.rankInfo = data
  163. //根据游戏信息与历史信息更新房间组件
  164. this.rankCtr.updateRank(this.rankInfo)
  165. })
  166. .catch((error) => {
  167. console.error("Fetch error:", error)
  168. })
  169. }
  170. start() {
  171. // this.startResetAnimation()
  172. // this.scheduleOnce(() => { this.accessTargetComponent() }, 0.1)
  173. this.scheduleOnce(() => { this.init() }, 1)
  174. this.processCtr.init(this)
  175. this.schedule(this.chackGameInfo, 5 * 60);
  176. }
  177. chackGameInfo()
  178. {
  179. const roomUrl = `https://airpg1.izouma.com/api/room/${this.roomId}`
  180. fetch(roomUrl)
  181. .then((response) => {
  182. if (!response.ok) {
  183. throw new Error("Network response was not ok")
  184. }
  185. return response.json()
  186. })
  187. .then((data) => {
  188. //获取游戏ID,房间信息
  189. console.log(data.currentGameId + " " + data.active)
  190. if(this.gameId == data.currentGameId)
  191. {
  192. if(this.noticeStr == data.notice)
  193. {
  194. return
  195. }
  196. else
  197. {
  198. this.noticeCtr.updateText(data.notice)
  199. this.noticeStr = data.notice
  200. }
  201. }
  202. else
  203. {
  204. director.loadScene('game')
  205. }
  206. })
  207. .catch((error) => {
  208. console.error("Fetch error:", error)
  209. })
  210. }
  211. update(deltaTime: number) { }
  212. onButtonClick() {
  213. director.loadScene(director.getScene().name);
  214. // this.exchangeTime()
  215. // this.noticeCtr.updateText(
  216. // "在 Cocos Creator 编辑器中,将富文本组件拖放到脚本的 richText 属性框中。运行游戏,现在你应该可以看到富文本的内容逐字出现。"
  217. // )
  218. //options初始化
  219. // this.optionsCtr.selectOption(3)
  220. //重置测试
  221. //this.startResetAnimation()
  222. //测试排行切换
  223. // this.rankCtr.updateRankTop()
  224. //测试剧情Pannel移动
  225. // this.optionsAppearAction()
  226. //测试被攻击
  227. // this.roleCtr.attack(this.roleCtr.node.getChildByName('role_icon_npc1'));
  228. // this.roleCtr.attack(this.roleCtr.node.getChildByName('role_icon_npc3'));
  229. // this.roleCtr.treat(this.roleCtr.node.getChildByName('role_icon_npc2'));
  230. // this.roleCtr.newPlayer(this.roleCtr.node.getChildByName('role_icon_player1'));
  231. }
  232. //重启动画相关
  233. startResetAnimation() {
  234. // Fade in the black mask
  235. if (this._dotsInterval) {
  236. clearInterval(this._dotsInterval)
  237. this._dotsInterval = null
  238. }
  239. this.resetNode.getComponent(UIOpacity).opacity = 0
  240. this.progressBar.progress = 0
  241. this.resetNode.active = true
  242. tween(this.resetNode.getComponent(UIOpacity))
  243. .to(1, { opacity: 255 })
  244. .call(() => this.showResetTextAndProgress())
  245. .start()
  246. }
  247. showResetTextAndProgress() {
  248. this.updateDots()
  249. this._dotsInterval = setInterval(() => this.updateDots(), 500)
  250. // Simulate progress
  251. let progress = 0
  252. const progressInterval = setInterval(() => {
  253. progress += 0.1
  254. this.progressBar.progress = progress
  255. if (progress >= 1) {
  256. clearInterval(progressInterval)
  257. this.endResetAnimation()
  258. }
  259. }, 1000)
  260. }
  261. updateDots() {
  262. const dots = ".".repeat((this._dotsCounter % 3) + 1)
  263. this.resetLabel.string = `世界重置中${dots}`
  264. this._dotsCounter++
  265. }
  266. endResetAnimation() {
  267. clearInterval(this._dotsInterval)
  268. // Fade out the black mask and reset
  269. tween(this.resetNode.getComponent(UIOpacity))
  270. .to(1, { opacity: 0 })
  271. .call(() => {
  272. this.progressBar.progress = 0
  273. this.resetNode.active = false
  274. })
  275. .start()
  276. }
  277. handleStoryPannelMove(data: any) {
  278. this.storyPannelCtr.storyContent = data.data
  279. this.storyPannelCtr.isOnProcess = true;
  280. //初始化后第一次收到剧情,直接展示剧情
  281. if (this.storyActionStatus == 0) {
  282. if (this.storyPannelCtr) {
  283. this.storyPannelCtr.updateStory(data.data)
  284. } else {
  285. console.log("plot error")
  286. }
  287. this.realStart = true
  288. this.noticeCtr.updateText(this.noticeStr)
  289. } else if (this.storyActionStatus == 2) {
  290. this.optionsAppearAction()
  291. }
  292. }
  293. //处理收到选项事件
  294. handleOptions(data: any) {
  295. if (this.realStart) {
  296. this.options = data.data
  297. //更新optionsLabel
  298. for (let i = 0; i < 4; i++) {
  299. this.optionsLabel[i] = this.options[i].content
  300. }
  301. if (this.storyActionStatus === 0 || this.storyActionStatus === 3) {
  302. this.optionsAppearAction()
  303. }
  304. }
  305. else {
  306. this.processCtr.doneProcessing()
  307. }
  308. }
  309. //处理收到被选项事件
  310. handleVoteResul(data: any) {
  311. if (this.realStart) {
  312. this.modifyHp = data.data.modifyHp
  313. for (let i = 0; i < 4; i++) {
  314. if (this.options[i].content == data.data.content) {
  315. this.selectedOptionNum = i;
  316. }
  317. }
  318. if (this.storyActionStatus === 1) {
  319. this.optionsAppearAction()
  320. }
  321. } else {
  322. this.processCtr.doneProcessing()
  323. }
  324. }
  325. //处理新玩家加入
  326. handleNewPlayer(data: any) {
  327. this.player.push(data.data)
  328. let playerIndex = this.player.length
  329. if (playerIndex === 8) {
  330. return
  331. }
  332. const rolePannelName: string = "role_icon_player" + (playerIndex + 1)
  333. const role: Node = this.roleCtr.node.getChildByName(rolePannelName)
  334. role.active = true
  335. this.roleCtr.newPlayer(role, this.player[playerIndex])
  336. this.roleNodes[data.data.name] = role
  337. this.processCtr.doneProcessing()
  338. }
  339. //单独处理死亡
  340. handleDeath(data: any) {
  341. this.roleCtr.deathNodes = data.data
  342. this.processCtr.doneProcessing()
  343. }
  344. //处理收到state时间:如果realStart == false ,则更新游戏初始状态
  345. handleStateResul(data: any) {
  346. if (!this.realStart) {
  347. this.historyInfo.push(data.data)
  348. this.updateGame(this.gameInfo, this.historyInfo)
  349. }
  350. this.processCtr.doneProcessing()
  351. }
  352. //处理重置
  353. handleReset(data: any) {
  354. //director.reset()
  355. director.loadScene('game');
  356. this.processCtr.doneProcessing()
  357. }
  358. //处理所有剧情、选项的移动逻辑
  359. optionsAppearAction() {
  360. console.log("storyActionStatus:" + this.storyActionStatus)
  361. if (this.storyActionStatus == 0) {
  362. const storyNode = this.storyPannelCtr.node
  363. const storyUI = storyNode.getComponent(UITransform)
  364. if (storyUI.height > this.storyHeight) {
  365. this.initStoryPosition = storyNode.position.clone()
  366. tween(this.storyPannelCtr.node)
  367. .by(0.5, { position: new Vec3(0, storyUI.height - this.storyHeight, 0) })
  368. .call(() => {
  369. this.optionsCtr.setOptions(this.optionsLabel)
  370. //此处需要额外处理死亡,因为前一步有演示播放攻击动画,不排除死亡名单中有攻击后自然死亡角色
  371. this.roleCtr.dealDeath(this.roleNodes)
  372. })
  373. .start()
  374. } else {
  375. this.optionsCtr.setOptions(this.optionsLabel)
  376. }
  377. this.processCtr.doneProcessing()
  378. this.storyActionStatus = 1
  379. } else if (this.storyActionStatus === 1) {
  380. console.log("selectedOptionNum:" + this.selectedOptionNum)
  381. this.optionsCtr.selectOption(this.selectedOptionNum + 1)
  382. this.processCtr.doneProcessing()
  383. this.storyActionStatus = 2
  384. } else if (this.storyActionStatus === 2) {
  385. this.scheduleOnce(() => {
  386. //隐藏未被选中选项
  387. for (let i = 0; i < 4; i++) {
  388. var optionNode: Node = this.optionsCtr.optionNodes[i]
  389. if (i !== this.selectedOptionNum) {
  390. const optionTween = tween(optionNode.getComponent(UIOpacity))
  391. optionTween.to(1, { opacity: 0 })
  392. .start()
  393. }
  394. }
  395. //隐藏剧情面板
  396. tween(this.storyPannelCtr.node.parent.getComponent(UIOpacity))
  397. .to(1, { opacity: 0 })
  398. .call(() => {
  399. this.storyPannelCtr.node.getComponent(Label).string = ""
  400. this.storyPannelCtr.node.position = new Vec3(0, 0, 0)
  401. this.initOptionsPosition = this.optionsCtr.node.position.clone()
  402. const storyY = this.storyPannelCtr.node.parent.position.y
  403. const optionsY = this.optionsCtr.node.position.y
  404. const selectedOption = this.optionsCtr.optionNodes[this.selectedOptionNum]
  405. const selectedOptionHeight = selectedOption.getComponent(UITransform).contentSize.height
  406. //选中选项上移
  407. tween(this.optionsCtr.node)
  408. .by(1, {
  409. position: new Vec3(
  410. 0,
  411. storyY - optionsY - selectedOption.position.y - selectedOptionHeight / 2,
  412. 0
  413. )
  414. })
  415. .call(() => {
  416. this.storyPannelCtr.node.parent.getComponent(UIOpacity).opacity = 255
  417. //剧情面板在下方出现并开始展示
  418. tween(this.storyPannelCtr.node)
  419. .by(0.01, { position: new Vec3(0, -selectedOptionHeight, 0) })
  420. .call(() => {
  421. this.storyPannelCtr.isOnProcess = true;
  422. this.storyPannelCtr.updateStory(this.storyPannelCtr.storyContent)
  423. this.storyActionStatus = 3
  424. //延时触发扣血加血动画
  425. this.scheduleOnce(() => { this.updateHp() }, 2)
  426. })
  427. .start()
  428. })
  429. .start()
  430. })
  431. .start()
  432. }, 2)
  433. } else if (this.storyActionStatus == 3) {
  434. const selectedOption = this.optionsCtr.optionNodes[this.selectedOptionNum]
  435. //顶部备选项消失
  436. tween(selectedOption.getComponent(UIOpacity))
  437. .to(0.5, { opacity: 0 })
  438. .call(() => {
  439. //重置选项位置与透明度
  440. this.optionsCtr.node.position = this.initOptionsPosition
  441. this.optionsCtr.node.getComponent(UIOpacity).opacity = 0
  442. // 这是被选中的选项
  443. selectedOption.getChildByName("text_option").getComponent(Label).color = Color.WHITE
  444. // 移除选中背景图
  445. const spriteComponent = selectedOption.getComponent(Sprite)
  446. if (spriteComponent) {
  447. spriteComponent.spriteFrame = this.optionsCtr.notSelectedSprite.spriteFrame
  448. }
  449. for (let i = 0; i < 4; i++) {
  450. this.optionsCtr.optionNodes[i].getComponent(UIOpacity).opacity = 255
  451. }
  452. //剧情上移开始展示
  453. tween(this.storyPannelCtr.node)
  454. .to(0.2, { position: new Vec3(0, 0, 0) })
  455. .call(() => {
  456. this.storyActionStatus = 0
  457. this.optionsAppearAction()
  458. this.processCtr.doneProcessing()
  459. })
  460. .start()
  461. })
  462. .start()
  463. }
  464. }
  465. updateGame(gameInfo: any, historyInfo: any[]) {
  466. if (gameInfo && history) {
  467. this.updateDateByHistory(historyInfo[0], historyInfo[historyInfo.length - 1])
  468. const firstHistory = historyInfo[0]
  469. const lastHistory = historyInfo[historyInfo.length - 1]
  470. const charactors: any[] = lastHistory.charactors
  471. //初始化剧情!!!
  472. //触发剧情框文字
  473. if (this.storyPannelCtr) {
  474. this.storyPannelCtr.updateStory(lastHistory.plot)
  475. } else {
  476. console.log("plot error")
  477. }
  478. //初始化角色!!!
  479. this.player = []
  480. this.npc = []
  481. this.roleNodes = {}
  482. for (let i = 0; i < charactors.length; i++) {
  483. if (charactors[i].danmuUserId) {
  484. this.player.push(charactors[i])
  485. } else {
  486. this.npc.push(charactors[i])
  487. }
  488. }
  489. for (let i = 0; i < this.npc.length; i++) {
  490. const rolePannelName: string = "role_icon_npc" + (i + 1)
  491. console.log(rolePannelName)
  492. const role: Node = this.roleCtr.node.getChildByName(rolePannelName)
  493. role.active = true
  494. this.roleCtr.newPlayer(role, this.npc[i])
  495. this.roleNodes[this.npc[i].name] = role
  496. }
  497. for (let i = 0; i < this.player.length; i++) {
  498. const rolePannelName: string = "role_icon_player" + (i + 1)
  499. const role: Node = this.roleCtr.node.getChildByName(rolePannelName)
  500. role.active = true
  501. this.roleCtr.newPlayer(role, this.player[i])
  502. this.roleNodes[this.player[i].name] = role
  503. }
  504. this.scheduleOnce(() => {
  505. this.processCtr.doneProcessing()
  506. }, 3)
  507. } else {
  508. throw new Error("gameInfo or historyInfo is null")
  509. }
  510. }
  511. //更新日期
  512. updateDateByHistory(firstHistory: any, lastHistory: any) {
  513. //初始化标题与天数!!!
  514. const time: string = lastHistory.time
  515. if (time === "evening") {
  516. this.sunIsUp = false
  517. this.exchangeTime()
  518. }
  519. this.titlePannel.getChildByName("text_title").getComponent(Label).string = this.gameInfo.name
  520. this.titlePannel.getChildByName("text_gameNo").getComponent(Label).string = "No." + this.gameId
  521. // 计算日期差(结果单位为毫秒)
  522. const lastHistoryDate = new Date(lastHistory.date)
  523. const firstHistoryDate = new Date(firstHistory.date)
  524. const differenceInMilliseconds = lastHistoryDate.getTime() - firstHistoryDate.getTime()
  525. // 将毫秒转为天数
  526. const differenceInDays = differenceInMilliseconds / (1000 * 60 * 60 * 24) + 1
  527. this.dayLabel.string = "第" + differenceInDays + "天"
  528. }
  529. updateDateByWS(data: any) {
  530. const time: string = data.data.time
  531. if (time === "evening") {
  532. this.sunIsUp = false
  533. this.exchangeTime()
  534. }
  535. else {
  536. this.sunIsUp = true
  537. this.exchangeTime()
  538. }
  539. this.titlePannel.getChildByName("text_title").getComponent(Label).string = this.gameInfo.name
  540. this.titlePannel.getChildByName("text_gameNo").getComponent(Label).string = "No." + this.gameId
  541. // 计算日期差(结果单位为毫秒)
  542. const lastHistoryDate = new Date(data.data.date)
  543. const firstHistoryDate = new Date(this.historyInfo[0].date)
  544. const differenceInMilliseconds = lastHistoryDate.getTime() - firstHistoryDate.getTime()
  545. // 将毫秒转为天数
  546. const differenceInDays = differenceInMilliseconds / (1000 * 60 * 60 * 24) + 1
  547. this.dayLabel.string = "第" + differenceInDays + "天"
  548. this.processCtr.doneProcessing()
  549. }
  550. exchangeTime() {
  551. if (this.sunIsUp) {
  552. this.MoonAnim.play("moonUp")
  553. this.MoonAnim.on(Animation.EventType.FINISHED, () => {
  554. this.SunAnim.play("sunDown")
  555. this.MoonAnim.off(Animation.EventType.FINISHED)
  556. })
  557. this.sunIsUp = false
  558. } else {
  559. this.SunAnim.play("sunUp")
  560. this.SunAnim.on(
  561. Animation.EventType.FINISHED,
  562. () => {
  563. this.MoonAnim.play("moonDown")
  564. this.SunAnim.off(Animation.EventType.FINISHED)
  565. },
  566. this
  567. )
  568. this.sunIsUp = true
  569. }
  570. }
  571. updateHp() {
  572. if (this.modifyHp) {
  573. for (let i = 0; i < this.modifyHp.length; i++) {
  574. const roleNode: Node = this.roleNodes[this.modifyHp[i].name]
  575. const pbNode: Node = roleNode.getChildByName("progressbar_hp")
  576. const orgHp = pbNode.getComponent(ProgressBar).progress
  577. //已死亡不触发
  578. if (orgHp == 0) {
  579. return
  580. }
  581. let newHp = orgHp + this.modifyHp[i].changeValue / 100
  582. if (newHp <= 0) {
  583. newHp = 0
  584. } else if (newHp > 1) {
  585. newHp = 1
  586. }
  587. pbNode.getComponent(ProgressBar).progress = newHp
  588. console.log('updata HP: name:' + this.modifyHp[i].name + ' orgHp:' + orgHp + ' newHp:' + newHp)
  589. console.log(pbNode)
  590. if (this.modifyHp[i].changeValue > 0) {
  591. this.roleCtr.treat(roleNode)
  592. } else {
  593. this.roleCtr.attack(roleNode)
  594. }
  595. }
  596. }
  597. }
  598. }