FightCore.ts 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. /** @format */
  2. import {FILTER_ROLE_NODE} from '../ECS/systems/SysRoleState'
  3. import {ITouchProcessor} from '../ECS/systems/SysCocosView'
  4. import {FightWorld} from '../ECS/worlds/FightWorld'
  5. import {Data, Mgr} from '../GameControl'
  6. import {ccUtils} from '../utils/ccUtils'
  7. import {ComRole} from '../ECS/components/ComRole'
  8. import {EntityIndex} from '../ECS/lib/Const'
  9. import {cCollider} from '../collision/Collider'
  10. import {ComEnemy} from '../ECS/components/ComEnemy'
  11. import {cObject} from '../collision/Object'
  12. import {IStageConfig, StageConfig} from '../config/StageConfig'
  13. import {ConstValue} from '../data/ConstValue'
  14. import {IRoleConfig, RoleConfig} from '../config/RoleConfig'
  15. import {
  16. BUILDING,
  17. BUILDING_ATTR,
  18. CARD_CAST_AREA,
  19. CARD_END_POS,
  20. CARD_MORE_DIR,
  21. START_POS,
  22. ENTRY,
  23. GAME_ROLE_TIP,
  24. GAME_TYPE,
  25. GAME_WIN_TYPE,
  26. LANGUAGE_TYPE,
  27. MONSTER_TYPE,
  28. ROLE_TYPE,
  29. SKILL_DIR_TYPE,
  30. SKILL_TYPE,
  31. MOD,
  32. GAME_PREFAB_TYPE,
  33. GOODS,
  34. } from '../enums/Enum'
  35. import {UI} from '../enums/UI'
  36. import {FILTER_CAN_ATTACK_ENEMY, FILTER_CAN_ATTACK_FRIEND} from '../ECS/systems/SysFindEnemy'
  37. import {msgCmd} from '../proto/msg_cmd'
  38. import {adventureEndRsp, adventureLayer, adventureLayerRsp, speedUpDataRsp} from '../proto/game'
  39. import {label, list, node, observer, render} from '../mobx/observer'
  40. import {IStageInfoConfig, StageInfoConfig} from '../config/StageInfoConfig'
  41. import {SkillConfig} from '../config/SkillConfig'
  42. import {ICardSkillConfig} from '../config/CardSkillConfig'
  43. import {ComTransform} from '../ECS/components/ComTransform'
  44. import {ComMovable} from '../ECS/components/ComMovable'
  45. import {EntryObj} from '../ECS/core/GameInterface'
  46. import {SkillOptCell} from '../cell/SkillOptCell'
  47. import {MonsterConfig} from '../config/MonsterConfig'
  48. import {EliteInfoConfig, IEliteInfoConfig} from '../config/EliteInfoConfig'
  49. import {IGameResult, IRewardNty} from '../interface/UIInterface'
  50. import {ICard, IRole} from '../interface/GlobalInterface'
  51. import {GoodsConfig} from '../config/GoodsConfig'
  52. import {SOUND} from '../enums/Sound'
  53. import {i18nLabel} from '../uiutils/i18nLabel'
  54. import {idNum} from '../proto/typedef'
  55. import {AwardConfig} from '../config/AwardConfig'
  56. import {ZumaUI} from '../ui/ZumaUI'
  57. import {ZumabuffConfig} from '../config/ZumabuffConfig'
  58. import {BuffConfig} from '../config/BuffConfig'
  59. import List from '../uiutils/List'
  60. const {ccclass, property} = cc._decorator
  61. enum FightTip {
  62. wave = 1, //大波敌人
  63. boss = 2, //boss
  64. }
  65. export enum RoundOutType {
  66. time = 1, //时间轴出怪
  67. dieOut = 2, //相同时间数值的一组死亡后立刻出下一组
  68. average = 3, //平均时间出怪
  69. }
  70. interface IRoleCreate {
  71. id: number
  72. pos: number
  73. drop: idNum
  74. }
  75. enum ITrailType {
  76. stage = 1, //主线关卡触发
  77. oneFailStage = 2, //指定关卡首次失败触发
  78. }
  79. @ccclass
  80. @observer
  81. export default class FightCore extends cc.Component {
  82. get teamNowHP(): number {
  83. return this._teamNowHP
  84. }
  85. set teamNowHP(value: number) {
  86. if (value != this._teamNowHP && this.teamPb.progress < 1 && this.roundFight) {
  87. }
  88. this._teamNowHP = value
  89. ccUtils.setLabel(Math.toKMBNum(value), this.node, 'teamHpNode/num')
  90. }
  91. get teamNowShieldHP(): number {
  92. return this._teamNowShieldHP
  93. }
  94. set teamNowShieldHP(value: number) {
  95. if (value != this._teamNowShieldHP && this.teamShieldPb.progress < 1 && this.roundFight) {
  96. }
  97. this._teamNowShieldHP = value
  98. }
  99. @node('cost/mask')
  100. private costMaskNode: cc.Node
  101. @node('skillPop')
  102. public skillPop: cc.Node
  103. @node('fightTip')
  104. private fightTip: cc.Node
  105. @node('gameTypeTip/tipLb')
  106. private tipLb: cc.Node
  107. @node('gameTypeTip/time')
  108. private tipTime: cc.Node
  109. @node('gameTypeTip/time/lb')
  110. private tipTimeLb: cc.Node
  111. @node('gameTypeTip/killNum')
  112. private tipKillNum: cc.Node
  113. @node('gameTypeTip/killNum/lb')
  114. private tipKillNumLb: cc.Node
  115. @node('top/round')
  116. private roundNode: cc.Node
  117. @node('top/goods')
  118. private goods: cc.Node
  119. @node('goodsParent')
  120. private goodsParent: cc.Node
  121. @node('touchNode')
  122. private touchNode: cc.Node
  123. @node('speed')
  124. private speed: cc.Node
  125. @node('Layers/drop')
  126. private dropParent: cc.Node
  127. @node('bossHP')
  128. private bossHPNode: cc.Node
  129. @node('teamHpNode/HPS')
  130. private teamHPS: cc.Node
  131. @node('bag')
  132. bag: cc.Node
  133. @list('bag/scrollView')
  134. bagCardList: List
  135. @node('bgs/roll')
  136. bgRolls: cc.Node
  137. public dropPool: Map<number, cc.NodePool> = new Map()
  138. public getDrop: Map<number, number> = new Map()
  139. public roleTipPool: Map<string, cc.NodePool>
  140. public gamePool: Map<string, cc.NodePool>
  141. public roleEntityMap: Map<number, EntityIndex[]>
  142. public stageInfo: IStageInfoConfig | IEliteInfoConfig
  143. public teamEntity: EntityIndex[] = []
  144. private _teamNowHP: number
  145. private _teamNowShieldHP: number
  146. public teamHP: number
  147. public teamPb: cc.ProgressBar
  148. public teamShieldPb: cc.ProgressBar
  149. public bossNum: number
  150. public eliteNum: number
  151. public monsterNum: number
  152. public world: FightWorld = null
  153. public gameOver: boolean
  154. public isStop: boolean = false
  155. public isTestScene: boolean = false
  156. public startTime: number
  157. private testClickNum: number = 0
  158. private curStage: number
  159. private roundFight: boolean
  160. private curRoundIndex: number
  161. private roundTime: number
  162. private roundNextRoleTime: number
  163. private curRoundCreateIndex: number
  164. private curRoundCfg: IStageConfig
  165. private _touchHandler: ITouchProcessor[] = []
  166. private skillArea: cc.Node
  167. private skillAreaCObject: cObject
  168. private curCardSkillCfg: ICardSkillConfig
  169. private curCard: ICard
  170. private curSkillOptCell: SkillOptCell
  171. private gameTime: number
  172. private roundOutType: RoundOutType = RoundOutType.time
  173. private roundOutTime: number = 0
  174. private smallRoundArr: IRoleCreate[][] = []
  175. private timeRolesTime: number[]
  176. private timeRoles: number[]
  177. private timeRolesPos: number[]
  178. private timeRolesDrop: idNum[]
  179. private createEnemyNum: number
  180. private extraEnemyCreateArr: boolean[]
  181. private rightAreaFriend: number[] = []
  182. private allRoundNum: number = 0
  183. private isScrollMap: Boolean = false
  184. private zumaUI: ZumaUI
  185. protected onLoad() {
  186. this.skillArea = cc.find('skillArea', this.node)
  187. this.skillAreaCObject = cc.find('skillAreaObject', this.node).getComponent(cObject)
  188. this.teamPb = cc.find('teamHpNode/HP', this.node).getComponent(cc.ProgressBar)
  189. this.teamShieldPb = cc.find('teamHpNode/HPshield', this.node).getComponent(cc.ProgressBar)
  190. this._touchHandler.length = 0
  191. this.roleTipPool = new Map()
  192. for (let key in GAME_ROLE_TIP) {
  193. this.roleTipPool.set(key, new cc.NodePool())
  194. }
  195. this.gamePool = new Map()
  196. for (let key in GAME_PREFAB_TYPE) {
  197. this.gamePool.set(key, new cc.NodePool())
  198. }
  199. this.roleEntityMap = new Map<number, EntityIndex[]>()
  200. this.registerTouchEvent()
  201. }
  202. init(zumaUI: ZumaUI) {
  203. this.zumaUI = zumaUI
  204. this.world = FightWorld.getInstance()
  205. this.world.fightCore = this
  206. this.resetGameWorld()
  207. Mgr.audio.playBGM(SOUND.gameBgm)
  208. if (CC_DEV || (Mgr.platform.isH5() && window.location.href.includes('dev.black-art.cn/b22'))) {
  209. this.isTestScene = cc.director.getScene().name == 'test'
  210. //if (this.isTestScene) Mgr.ui.show(UI.GameDevUI, this)
  211. }
  212. //初始化战场大小
  213. let skillTouch = cc.find('skillTouch', this.skillPop)
  214. //扩大200触摸范围,让边缘角色可以点击
  215. skillTouch.width = Data.game.fightSizeMaxX - Data.game.fightSizeMinX + 200
  216. skillTouch.height = Data.game.fightSizeMaxY - Data.game.fightSizeMinY
  217. skillTouch.y = (Data.game.fightSizeMaxY + Data.game.fightSizeMinY) / 2
  218. skillTouch.x = (Data.game.fightSizeMaxX + Data.game.fightSizeMinX) / 2
  219. }
  220. update(dt: number): void {
  221. this.scrollMap(dt)
  222. this.logicUpdate(dt)
  223. }
  224. protected logicUpdate(dt: number): void {
  225. if (this.isStop) return
  226. dt *= Data.game.gameSpeed
  227. this.gameTime += dt
  228. if (this.stageInfo?.type == GAME_WIN_TYPE.surviveTime && this.gameTime > 0 && !this.gameOver) {
  229. let dur = this.stageInfo.parameter - this.gameTime
  230. if (dur < 0) {
  231. this.zumaUI.endFightRound(true)
  232. dur = 0
  233. }
  234. ccUtils.setLabel(Date.Format('mm:ss', dur), this.tipTimeLb)
  235. }
  236. if (this.world) this.world.update(dt)
  237. if (this.roundFight) {
  238. this.roundTime += dt
  239. //时间轴刷怪
  240. if (
  241. this.roundNextRoleTime >= 0 &&
  242. this.roundTime >= this.roundNextRoleTime &&
  243. this.curRoundCreateIndex >= 0 &&
  244. (this.roundOutType == RoundOutType.time || this.roundOutType == RoundOutType.average)
  245. ) {
  246. let rolesTime = this.timeRolesTime
  247. let roles = this.timeRoles
  248. let rolesPos = this.timeRolesPos
  249. if (this.curRoundCreateIndex < roles.length) {
  250. let cfg = this.getRoleCfgByCfgID(roles[this.curRoundCreateIndex])
  251. this.createEnemyNum += 1
  252. this.world.createRoleEntity(
  253. cfg,
  254. true,
  255. rolesPos[this.curRoundCreateIndex],
  256. null,
  257. this.timeRolesDrop[this.curRoundCreateIndex],
  258. )
  259. this.curRoundCreateIndex += 1
  260. if (this.curRoundCreateIndex < rolesTime.length) {
  261. this.roundNextRoleTime = rolesTime[this.curRoundCreateIndex]
  262. }
  263. } else {
  264. let bigRoundTime = this.curRoundCfg.trigger
  265. if (bigRoundTime > 0) {
  266. this.roundFight = false
  267. this.scheduleOnce(this.readyNextRound, bigRoundTime)
  268. }
  269. let enemyNum = this.world.getFilter(FILTER_CAN_ATTACK_ENEMY).entities.size
  270. if (enemyNum <= 1 && !bigRoundTime) {
  271. this.roundFight = false
  272. this.readyNextRound()
  273. }
  274. }
  275. }
  276. }
  277. }
  278. protected onDisable() {
  279. this.unscheduleAllCallbacks()
  280. this.resetGameWorld()
  281. Mgr.event.removeAll(this)
  282. if (CC_DEV || ConstValue.DEBUG) {
  283. Mgr.ui.hide(UI.GameDevUI)
  284. }
  285. }
  286. onDestroy() {}
  287. //游戏逻辑=======================================
  288. resetGameWorld() {
  289. this._touchHandler.length = 0
  290. this.world.init()
  291. this.world.clear(false)
  292. this.roleEntityMap.clear()
  293. cc.find('Layers', this.node).children.forEach(value => value.removeAllChildren())
  294. cCollider.inst.clear()
  295. this.roundFight = false
  296. this.initSkillArea()
  297. this.unschedule(this.startNextSmallRound)
  298. this.unschedule(this.startNextRound)
  299. }
  300. getRoleCfgByCfgID(ID: number): IRoleConfig {
  301. let cfg: IRoleConfig
  302. if ([GAME_TYPE.normal, GAME_TYPE.none].includes(Data.game.gameType)) {
  303. cfg = (MonsterConfig[ID] as unknown) as IRoleConfig
  304. }
  305. return cfg
  306. }
  307. getRolePos(pos: number) {
  308. if (pos == 0) {
  309. return Math.randomRangeInt(1, 19)
  310. } else if (pos == 100) {
  311. return Math.randomRangeInt(101, 109)
  312. } else {
  313. return pos
  314. }
  315. }
  316. startStageGame() {
  317. this.startTime = 0
  318. this.gameTime = 0
  319. this.isStop = false
  320. this.createEnemyNum = 0
  321. this.curStage = Data.game.stageID
  322. this.curRoundIndex = 0
  323. this.allRoundNum = 0
  324. for (let i = 0; i < 100; i++) {
  325. if (!this.getRoundCfg(false, i)) {
  326. this.allRoundNum = i
  327. break
  328. }
  329. }
  330. this.initGameSpeed()
  331. cc.find('testEndGame', this.node).active = ConstValue.DEBUG
  332. this.testClickNum = 0
  333. ccUtils.setLabel('0', this.goods, 'lb')
  334. cc.find('stageLb', this.roundNode)
  335. .getComponent(i18nLabel)
  336. .setParamByIndex((this.curStage % 100) + '', 0)
  337. let cfg = this.getStageInfoCfg()
  338. this.stageInfo = cfg
  339. if (cfg) {
  340. this.tipKillNum.active = cfg.type == GAME_WIN_TYPE.killNum
  341. this.tipTime.active = cfg.type == GAME_WIN_TYPE.surviveTime
  342. let tipLbArr = []
  343. tipLbArr[GAME_WIN_TYPE.boss] = LANGUAGE_TYPE.bossTip
  344. ccUtils.setLabel(tipLbArr[cfg.type] ?? '', this.tipLb)
  345. }
  346. if (Data.game.gameType == GAME_TYPE.none) {
  347. } else if (Data.game.gameType == GAME_TYPE.normal || Data.game.gameType == GAME_TYPE.elite) {
  348. let stageName = ''
  349. if (Data.game.gameType == GAME_TYPE.normal) {
  350. if ('des' in cfg) {
  351. stageName = `${Mgr.i18n.getLabel(cfg.name, [])}-${cfg.des}`
  352. }
  353. } else if (Data.game.gameType == GAME_TYPE.elite) {
  354. if ('name' in cfg) {
  355. stageName = `${Mgr.i18n.getLabel(cfg.name, [])}-${cfg.ID % 10}`
  356. }
  357. }
  358. Mgr.net.add(msgCmd.cmd_adventure_layer_rsp, this, this.onRoundStartRsp)
  359. }
  360. this.initRoles()
  361. let roundCfg = this.getRoundCfg()
  362. if (this.curStage > 0 && roundCfg) {
  363. this.startTime = Data.main.serverTime
  364. this.resetRound()
  365. this.changeKillNum()
  366. } else {
  367. Mgr.ui.tip('没有当前关卡' + this.curStage)
  368. }
  369. }
  370. readyNextRound() {}
  371. startNextRound() {
  372. if (this.isTestScene) {
  373. Data.game.stageRound += 1
  374. this.curRoundIndex += 1
  375. this.resetRound()
  376. } else {
  377. if (Data.game.gameType == GAME_TYPE.normal || Data.game.gameType == GAME_TYPE.elite) {
  378. let data: adventureLayer = {
  379. eliteNum: 0,
  380. bossNum: 0,
  381. cost: 0,
  382. layer: Data.game.stageRound,
  383. monsterNum: 0,
  384. }
  385. Mgr.net.send(msgCmd.cmd_adventure_layer, data)
  386. }
  387. }
  388. }
  389. resetRound() {
  390. this.fightTip.opacity = 0
  391. this.bossHPNode.active = false
  392. this.bossNum = 0
  393. this.eliteNum = 0
  394. this.monsterNum = 0
  395. this.gameOver = false
  396. this.skillPop.active = false
  397. this.rightAreaFriend.length = 0
  398. this.curRoundCfg = this.getRoundCfg()
  399. this.showFightTip(this.curRoundCfg.tipType)
  400. this.roundTime = 0
  401. this.roundFight = true
  402. this.curRoundCreateIndex = 0
  403. this.roundOutType = this.curRoundCfg.summonType
  404. this.roundOutTime = this.curRoundCfg.time
  405. let cfgRolesTime = this.curRoundCfg.rolesTime
  406. let rolesTime = (Array.isArray(cfgRolesTime[0]) ? cfgRolesTime[0] : cfgRolesTime) as number[]
  407. this.timeRolesTime = rolesTime
  408. let cfgRoles = this.curRoundCfg.roles
  409. let roles = (Array.isArray(cfgRoles[0]) ? cfgRoles[0] : cfgRoles) as number[]
  410. this.timeRoles = roles
  411. let cfgRolesPos = this.curRoundCfg.rolesPos
  412. let rolesPos = (Array.isArray(cfgRolesPos[0]) ? cfgRolesPos[0] : cfgRolesPos) as number[]
  413. this.timeRolesPos = rolesPos
  414. let dropArr = []
  415. if ('ball' in this.curRoundCfg) {
  416. let ballCfg = this.curRoundCfg.ball
  417. dropArr.push(...new Array(ballCfg[1]).fill(ballCfg[0]))
  418. }
  419. let setDrop = (drops: number[], allRoles: number[]) => {
  420. let tmpIdNums = []
  421. let randomArr = []
  422. let dropRolesPos = []
  423. if (drops.length > 0) {
  424. //过滤掉boss,去头尾
  425. for (let i = 1; i < allRoles.length - 1; i++) {
  426. if (this.getRoleCfgByCfgID(allRoles[i]).type != MONSTER_TYPE.boss) dropRolesPos.push(i)
  427. }
  428. //N组随机
  429. let count = Math.ceil(dropRolesPos.length / drops.length)
  430. if (count <= 2) {
  431. randomArr = Math.randomRangeIntArr(
  432. 1,
  433. dropRolesPos.length - 2,
  434. Math.min(dropRolesPos.length - 2, drops.length),
  435. )
  436. } else {
  437. //每N个数量随机一个下标
  438. for (let i = 0; i < drops.length; i++) {
  439. if (i == 0) {
  440. randomArr.push(Math.randomRangeInt(1, Math.max(1, count - 1)))
  441. } else if (i == count - 1) {
  442. randomArr.push(Math.randomRangeInt(i * count, dropRolesPos.length - 2))
  443. } else {
  444. randomArr.push(Math.randomRangeInt(i * count, (i + 1) * count - 1))
  445. }
  446. }
  447. }
  448. }
  449. randomArr = randomArr.map(v => dropRolesPos[v])
  450. for (let i = 0; i < allRoles.length; i++) {
  451. let id = 0
  452. if (randomArr.includes(i)) {
  453. id = drops[randomArr.indexOf(i)]
  454. }
  455. tmpIdNums.push({id, num: 1})
  456. }
  457. return tmpIdNums
  458. }
  459. if (this.roundOutType == RoundOutType.time) {
  460. if (roles.length != rolesPos.length) {
  461. console.error('角色配置和位置配置数量不一致')
  462. }
  463. this.timeRolesDrop = setDrop(dropArr, roles)
  464. } else if (this.roundOutType == RoundOutType.dieOut) {
  465. let allTime = {}
  466. let timeRolesDrop = setDrop(dropArr, roles)
  467. for (let i = 0; i < rolesTime.length; i++) {
  468. let tmpTime = rolesTime[i]
  469. if (!allTime[tmpTime]) {
  470. allTime[tmpTime] = []
  471. }
  472. if (roles[i] && rolesPos[i]) {
  473. allTime[tmpTime].push({
  474. id: roles[i],
  475. pos: rolesPos[i],
  476. drop: timeRolesDrop[i],
  477. })
  478. }
  479. }
  480. this.smallRoundArr = Object.values(allTime)
  481. this.startNextSmallRound()
  482. } else if (this.roundOutType == RoundOutType.average) {
  483. let tmpObj: {id: number; pos: number; time: number}[] = []
  484. for (let i = 0; i < this.curRoundCfg.roles.length; i++) {
  485. let tmpRoles = this.curRoundCfg.roles[i]
  486. if (Array.isArray(tmpRoles)) {
  487. //'301':{ ID: 301, roles: [[60031, 60032], [60031, 60031, 60031]], rolesPos: [[0, 0], [0, 0, 0]], rolesTime: [[10, 20], [30, 40, 50]], time: 10},
  488. for (let k = 0; k < tmpRoles.length; k++) {
  489. let cfgPos = this.curRoundCfg.rolesPos[i][k]
  490. for (let j = 0; j < this.curRoundCfg.rolesTime[i][k]; j++) {
  491. let pos = this.getRolePos(cfgPos)
  492. tmpObj.push({
  493. id: tmpRoles[k],
  494. pos,
  495. time:
  496. this.curRoundCfg.time * i +
  497. (this.curRoundCfg.time / this.curRoundCfg.rolesTime[i][k]) * j,
  498. })
  499. }
  500. }
  501. }
  502. }
  503. tmpObj.sort((a, b) => a.time - b.time)
  504. this.timeRolesTime = []
  505. this.timeRoles = []
  506. this.timeRolesPos = []
  507. this.timeRolesDrop = []
  508. tmpObj.forEach(v => {
  509. this.timeRoles.push(v.id)
  510. this.timeRolesPos.push(v.pos)
  511. this.timeRolesTime.push(v.time)
  512. })
  513. this.timeRolesDrop = setDrop(dropArr, this.timeRoles)
  514. }
  515. this.roundNextRoleTime = this.timeRolesTime[this.curRoundCreateIndex]
  516. if ('additional' in this.curRoundCfg) {
  517. this.extraEnemyCreateArr = new Array(this.curRoundCfg.additional.map(v => v).length).fill(false)
  518. }
  519. //初始化每轮开始的BUFF和技能
  520. this.scheduleOnce(() => {
  521. this.zumaUI.activeBuff.forEach(v => {
  522. this.addTeamBuff(v)
  523. this.castTeamSkill(v)
  524. })
  525. }, 1)
  526. this.bagCardList.numItems = this.zumaUI.activeBuff.length
  527. ccUtils.setProgress((this.curRoundIndex + 1) / this.allRoundNum, this.roundNode, 'roundPb')
  528. ccUtils.setLabel(`${this.curRoundIndex + 1}/${this.allRoundNum}`, this.roundNode, 'roundPb/lb')
  529. if (this.curRoundIndex > 0) {
  530. this.isScrollMap = true
  531. this.changeTeamRoleRun(true)
  532. this.scheduleOnce(() => {
  533. this.isScrollMap = false
  534. this.isStop = false
  535. this.changeTeamRoleRun(false)
  536. }, this.zumaUI.fightReadyTime)
  537. } else {
  538. this.isStop = false
  539. }
  540. }
  541. startNextSmallRound() {
  542. let bigRoundTime = this.curRoundCfg.trigger
  543. if (!bigRoundTime && this.curRoundCreateIndex >= this.smallRoundArr.length) {
  544. this.roundFight = false
  545. this.readyNextRound()
  546. return
  547. }
  548. for (let roleItem of this.smallRoundArr[this.curRoundCreateIndex]) {
  549. let cfg = this.getRoleCfgByCfgID(roleItem.id)
  550. this.createEnemyNum += 1
  551. this.world.createRoleEntity(cfg, true, roleItem.pos, null, roleItem.drop)
  552. }
  553. //如果bigRoundTime>0 再最后一小波的时候直接开始下一大波
  554. if (this.curRoundCreateIndex == this.smallRoundArr.length - 1 && bigRoundTime > 0) {
  555. this.roundFight = false
  556. this.scheduleOnce(this.readyNextRound, bigRoundTime)
  557. }
  558. this.curRoundCreateIndex += 1
  559. }
  560. showFightTip(tip) {
  561. let tipStr = ''
  562. if (!tip) return
  563. switch (tip) {
  564. case FightTip.wave:
  565. tipStr = LANGUAGE_TYPE.waveFightTip
  566. break
  567. case FightTip.boss:
  568. tipStr = LANGUAGE_TYPE.bossFightTip
  569. break
  570. }
  571. this.fightTip.stopAllActions()
  572. this.fightTip.opacity = 255
  573. ccUtils.setLabel(tipStr, this.fightTip, 'label')
  574. cc.tween(this.fightTip)
  575. .to(0.5, {opacity: 0})
  576. .reverseTime()
  577. .repeat(3)
  578. .call(() => {
  579. this.fightTip.opacity = 0
  580. })
  581. .start()
  582. }
  583. initRoles() {
  584. this.teamEntity.length = 0
  585. Data.user.teamRole.length = 0
  586. Data.user.teamRole.push(Mgr.global.buildIRole({equip: [], lv: 1, sid: '', id: 12001}))
  587. Data.user.teamRole.push(Mgr.global.buildIRole({equip: [], lv: 1, sid: '', id: 10001}))
  588. Data.user.teamRole.push(Mgr.global.buildIRole({equip: [], lv: 1, sid: '', id: 11001}))
  589. let iRoles = Data.user.teamRole.filter(v => v)
  590. for (let i = 0; i < Data.game.friendNum; i++) {
  591. let iRole = iRoles[i]
  592. if (iRole) {
  593. //友军位置ID写死101-200
  594. let entity = this.world.createRoleEntity(iRole.cfg.ID, false, 101 + i, iRole)
  595. console.warn('创建队友', entity)
  596. this.teamEntity.push(entity)
  597. }
  598. }
  599. this.teamHP = 0
  600. this.changeTeamHp()
  601. }
  602. changeTeamRoleRun(isRun: boolean) {
  603. this.teamEntity.forEach(entity => {
  604. this.world.changeRoleRun(entity, isRun)
  605. })
  606. }
  607. addTeamBuff(buffID) {
  608. let cfg = ZumabuffConfig[buffID]
  609. cfg.buff.forEach(buffID => {
  610. let buffCfg = BuffConfig[buffID]
  611. if (buffCfg) {
  612. for (let i = 0; i < this.teamEntity.length; i++) {
  613. let entity = this.teamEntity[i]
  614. let comRole = this.world.getComponent(entity, ComRole)
  615. if (comRole && cfg.profession.includes(comRole.roleCfg.profession)) {
  616. this.world.addBuff(entity, this.world.createBuff(buffID, null), null)
  617. }
  618. }
  619. }
  620. })
  621. }
  622. castTeamSkill(buffID) {
  623. let cfg = ZumabuffConfig[buffID]
  624. cfg.skill.forEach(skillID => {
  625. let skillCfg = SkillConfig[skillID]
  626. if (skillCfg) {
  627. this.teamEntity.forEach(entity => {
  628. let comRole = this.world.getComponent(entity, ComRole)
  629. if (comRole) {
  630. this.world.createSkill(
  631. {buffs: [], entryMap: new Map<ENTRY, EntryObj>(), ...comRole},
  632. skillCfg,
  633. entity,
  634. null,
  635. skillCfg.isHurt ? Data.game.gFriendHurtSkill : Data.game.gFriendGainSkill,
  636. )
  637. }
  638. })
  639. }
  640. })
  641. }
  642. initSkillItem(node, index) {
  643. let buffID = this.zumaUI.activeBuff[index]
  644. this.zumaUI.initZumaBuffItem(buffID, cc.find('buff', node).children[0])
  645. let skillOptCell = node.getComponent(SkillOptCell)
  646. skillOptCell.init(buffID, this)
  647. }
  648. initSkillArea() {
  649. this.skillAreaCObject.init(Data.game.gSkillArea, -100)
  650. cCollider.inst.insert(this.skillAreaCObject.body)
  651. this.skillArea.active = false
  652. }
  653. resetSkillArea() {
  654. this.skillArea.active = false
  655. }
  656. showSkillPop(iCard: ICard) {
  657. this.skillPop.active = true
  658. let cfg = iCard.cfg
  659. ccUtils.setLabel(cfg.name, this.skillPop, 'tip/skillname')
  660. ccUtils.setRichLabel(cfg.tip, this.skillPop, 'tip/scrollView/view/content/rt')
  661. if (cfg.attrNum.length > 0) {
  662. let i18nLb = cc.find('tip/scrollView/view/content/rt', this.skillPop).getComponent(i18nLabel)
  663. i18nLb.init(
  664. cfg.tip,
  665. cfg.attrNum.map(v => v.toString()),
  666. )
  667. }
  668. this.skillArea.width = cfg.width
  669. this.skillArea.height = cfg.height
  670. let radiusAni = cc.find('radiusAni', this.skillArea)
  671. radiusAni.width = cfg.width
  672. radiusAni.height = cfg.height
  673. let rangeAni = cc.find('rectAni', this.skillArea)
  674. rangeAni.width = cfg.width
  675. rangeAni.height = cfg.height
  676. rangeAni.x = -cfg.width / 2
  677. this.skillAreaCObject.updateBoxShape(cfg.width, cfg.height)
  678. this.unschedule(this.resetSkillArea)
  679. this.curCardSkillCfg = cfg
  680. this.curCard = iCard
  681. }
  682. skillOptShow(skillOptCell: SkillOptCell) {
  683. let iCard = skillOptCell.zumabuffCfg
  684. if (!this.skillPop.active) {
  685. this.curSkillOptCell = skillOptCell
  686. }
  687. }
  688. castSkillByCard() {
  689. let friend = []
  690. let enemy = []
  691. let world = this.world
  692. let targetEntities: number[] = []
  693. let cardSkillCfg = this.curCard.cfg
  694. let iCard = this.curCard
  695. let skillCfg = SkillConfig[cardSkillCfg.skills[0]]
  696. //先找出所有目标
  697. if (cardSkillCfg.castType == CARD_CAST_AREA.fullScreen) {
  698. let filter = skillCfg.isHurt
  699. ? this.world.getFilter(FILTER_CAN_ATTACK_ENEMY)
  700. : this.world.getFilter(FILTER_CAN_ATTACK_FRIEND)
  701. filter.walk((entity: number) => {
  702. targetEntities.push(entity)
  703. return false
  704. })
  705. } else if (cardSkillCfg.castType == CARD_CAST_AREA.radius || cardSkillCfg.castType == CARD_CAST_AREA.rect) {
  706. //范围技能
  707. //this.skillAreaCObject.trigger = true
  708. cCollider.inst.update(0)
  709. this.skillAreaCObject.containsBody.forEach((body, key) => {
  710. let comRole = world.getComponent(key, ComRole)
  711. if (!world.isDie(comRole) && !world.isBase(comRole)) {
  712. if (world.getComponent(key, ComEnemy)) {
  713. enemy.push(key)
  714. } else {
  715. friend.push(key)
  716. }
  717. }
  718. })
  719. this.skillAreaCObject.setPosition(cc.v3(0, -200, 0))
  720. //this.skillAreaCObject.trigger = false
  721. targetEntities = skillCfg.isHurt ? enemy : friend
  722. }
  723. //技能子弹不能打到建筑
  724. if (cardSkillCfg.bullet > 0) {
  725. targetEntities = targetEntities.filter(v => {
  726. let comRole = world.getComponent(v, ComRole)
  727. return comRole.roleCfg.type != ROLE_TYPE.base
  728. })
  729. }
  730. targetEntities.outOrder()
  731. let startPos: cc.Vec2 = cc.Vec2.ZERO
  732. let startCfgType = cardSkillCfg.posType[0]
  733. let endPos: cc.Vec2 = cc.Vec2.ZERO
  734. let endCfgType = cardSkillCfg.posType[1]
  735. let endPosArr: cc.Vec2[] = []
  736. let areaWidth = this.skillArea.width
  737. let areaHeight = this.skillArea.height
  738. let leftAreaX = this.skillArea.x - areaWidth / 2
  739. let rightAreaX = this.skillArea.x + areaWidth / 2
  740. let belowAreaY = this.skillArea.y - areaHeight / 2
  741. let topAreaY = this.skillArea.y + areaHeight / 2
  742. let castDirType = cardSkillCfg.moreSkill[0]
  743. let castTimes = cardSkillCfg.moreSkill[1]
  744. let castInterval = cardSkillCfg.moreSkill[2] ? cardSkillCfg.moreSkill[2] : 0
  745. if (endCfgType == CARD_END_POS.rowCol) {
  746. let stepX = areaWidth / (cardSkillCfg.posType[3] + 1)
  747. let stepY = areaHeight / (cardSkillCfg.posType[2] + 1)
  748. for (let i = 1; i <= cardSkillCfg.posType[2]; i++) {
  749. for (let j = 1; j <= cardSkillCfg.posType[3]; j++) {
  750. let x = leftAreaX + j * stepX
  751. let y = topAreaY - i * stepY
  752. endPosArr.push(cc.v2(x, y))
  753. }
  754. }
  755. if (endPosArr.length != cardSkillCfg.moreSkill.length) {
  756. console.error('卡牌技能多行多列数量与moreSkill配置不一致')
  757. }
  758. }
  759. if (targetEntities.length > 0 && targetEntities.length < castTimes && castDirType == CARD_MORE_DIR.one2One) {
  760. //重复数组补齐
  761. let repeat = Math.ceil(castTimes / targetEntities.length)
  762. for (let j = 0; j < repeat; j++) {
  763. targetEntities = targetEntities.concat(targetEntities)
  764. }
  765. }
  766. for (let i = 0; i < castTimes; i++) {
  767. this.scheduleOnce(() => {
  768. if (!this.node.activeInHierarchy) return
  769. let comTransform = world.getComponent(targetEntities[i], ComTransform)
  770. let randomX = Math.randomRangeFloat(leftAreaX, rightAreaX)
  771. let randomY = Math.randomRangeFloat(belowAreaY, topAreaY)
  772. if (startCfgType == START_POS.straightFall || startCfgType == START_POS.obliqueFall) {
  773. startPos.y = ConstValue.CANVAS_HEIGHT / 2
  774. if (endCfgType == CARD_END_POS.random || (endCfgType == CARD_END_POS.role && !comTransform)) {
  775. startPos.x = randomX
  776. endPos.x = randomX
  777. endPos.y = randomY
  778. } else if (endCfgType == CARD_END_POS.rowCol) {
  779. startPos.x = randomX
  780. endPos = endPosArr[i]
  781. } else if (endCfgType == CARD_END_POS.role && comTransform) {
  782. startPos.x = comTransform.x
  783. if (startCfgType == START_POS.obliqueFall) startPos.x -= 200
  784. endPos.x = comTransform.x
  785. endPos.y = comTransform.y
  786. }
  787. } else if (startCfgType == START_POS.leftScreen) {
  788. startPos.x = -ConstValue.CANVAS_WIDTH / 2
  789. startPos.y = this.skillArea.y
  790. if (endCfgType == CARD_END_POS.rightScreen) {
  791. endPos.x = ConstValue.CANVAS_WIDTH
  792. endPos.y = startPos.y
  793. }
  794. } else if (startCfgType == START_POS.areaCenter) {
  795. startPos.x = this.skillArea.x
  796. startPos.y = this.skillArea.y
  797. } else if (startCfgType == START_POS.fightCenter) {
  798. startPos.x = (Data.game.fightSizeMaxX + Data.game.fightSizeMinX) / 2
  799. startPos.y = (Data.game.fightSizeMaxY + Data.game.fightSizeMinY) / 2
  800. }
  801. //子弹技能
  802. if (cardSkillCfg.bullet > 0 && castDirType == CARD_MORE_DIR.one2One) {
  803. this.world.createCardBulletEntity(iCard, startPos, endPos, targetEntities[i])
  804. } else if (!cardSkillCfg.bullet) {
  805. if (castDirType == CARD_MORE_DIR.noOne) {
  806. let skillEntity = world.createSkill(
  807. {buffs: [], entryMap: new Map<ENTRY, EntryObj>(), ...iCard},
  808. skillCfg,
  809. 0,
  810. cc.v3(startPos),
  811. skillCfg.isHurt ? Data.game.gFriendHurtSkill : Data.game.gFriendGainSkill,
  812. )
  813. if (cardSkillCfg.moveSpeed > 0 && skillCfg.type == SKILL_TYPE.attackBack) {
  814. let comMovable = world.addComponent(skillEntity, ComMovable)
  815. comMovable.pointIdx = 0
  816. comMovable.points.length = 0
  817. comMovable.speed = cardSkillCfg.moveSpeed
  818. comMovable.points.push(endPos)
  819. }
  820. } else if (castDirType == CARD_MORE_DIR.one2All) {
  821. if (skillCfg.dirType == SKILL_DIR_TYPE.minHpRole) {
  822. targetEntities.sort((a, b) => {
  823. let comA = world.getComponent(a, ComRole)
  824. let comB = world.getComponent(b, ComRole)
  825. return comA?.nowHP - comB?.nowHP
  826. })
  827. }
  828. for (let i = 0; i < Math.min(skillCfg.maxRole, targetEntities.length); i++) {
  829. world.createSkill(
  830. {buffs: [], entryMap: new Map<ENTRY, EntryObj>(), ...iCard},
  831. skillCfg,
  832. targetEntities[i],
  833. null,
  834. skillCfg.isHurt ? Data.game.gFriendHurtSkill : Data.game.gFriendGainSkill,
  835. )
  836. }
  837. }
  838. }
  839. }, castInterval * i)
  840. }
  841. this.curSkillOptCell?.startCD()
  842. }
  843. getGameInfo(): {roleNum: number; enemyNum: number; castCost: number} {
  844. let roleNum = 0
  845. let enemyNum = 0
  846. this.world?.getFilter(FILTER_ROLE_NODE)?.walk((entity: number) => {
  847. if (this.world.getComponent(entity, ComEnemy)) {
  848. enemyNum++
  849. } else {
  850. roleNum++
  851. }
  852. return false
  853. })
  854. return {roleNum, enemyNum, castCost: 0}
  855. }
  856. createDevEntity(ID: number, isEnemy?: boolean, posCfgID?: number, iRole?: IRole) {
  857. let roleCfg = RoleConfig[ID]
  858. if (!roleCfg) {
  859. roleCfg = (MonsterConfig[ID] as unknown) as IRoleConfig
  860. }
  861. this.world.createRoleEntity(roleCfg, isEnemy, posCfgID, iRole)
  862. }
  863. changeStageChange(stage: number) {
  864. this.curStage = stage
  865. Data.game.stageRound = stage * 100 + 1
  866. Data.game.gameType = GAME_TYPE.normal
  867. this.resetGameWorld()
  868. this.startStageGame()
  869. }
  870. changeTeamHp() {
  871. let nowHp = 0
  872. let nowShieldHp = 0
  873. for (let i = 0; i < this.teamEntity.length; i++) {
  874. let entity = this.teamEntity[i]
  875. let comRole = this.world.getComponent(entity, ComRole)
  876. nowHp += comRole ? comRole.nowHP : 0
  877. nowShieldHp += comRole ? comRole.shieldHP : 0
  878. }
  879. this.teamNowHP = nowHp
  880. this.teamNowShieldHP = nowShieldHp
  881. if (!this.teamHP) this.teamHP = nowHp
  882. let allHp = this.teamHP
  883. if (this.teamNowHP + this.teamNowShieldHP > allHp) allHp = this.teamNowHP + this.teamNowShieldHP
  884. this.teamPb.progress = this.teamNowHP / allHp
  885. this.teamShieldPb.progress = (this.teamNowHP + this.teamNowShieldHP) / allHp
  886. let hpCellNum = Math.ceil(allHp / 100)
  887. //修改为固定10格血
  888. if (hpCellNum > 10) hpCellNum = 10
  889. if (hpCellNum != this.teamHPS.children.length) {
  890. ccUtils.instantChildren(cc.find('hp', this.teamHPS), hpCellNum)
  891. }
  892. if (this.roundFight && this.teamNowHP <= 0 && this.teamNowShieldHP <= 0) {
  893. this.roundFight = false
  894. this.zumaUI.endFightRound(false)
  895. }
  896. }
  897. changeKillNum() {
  898. if (!this.stageInfo) return
  899. let enemyNum = this.world.getFilter(FILTER_CAN_ATTACK_ENEMY).entities.size
  900. if (this.stageInfo.type == GAME_WIN_TYPE.killNum || this.stageInfo.type == GAME_WIN_TYPE.boss) {
  901. let allNum = this.monsterNum + this.eliteNum + this.bossNum
  902. ccUtils.setLabel(`${Math.floor((allNum / this.timeRoles.length) * 100)}%`, this.tipKillNumLb)
  903. if (allNum >= this.timeRoles.length) {
  904. this.zumaUI.endFightRound(true)
  905. }
  906. } else if (this.stageInfo.type == GAME_WIN_TYPE.surviveTime) {
  907. //通关类型3 (存活指定时间 或 击杀配置中所有怪物,即判定胜利
  908. if (enemyNum <= 1 && !this.roundFight) {
  909. this.zumaUI.endFightRound(true)
  910. }
  911. }
  912. if (this.roundFight && this.roundOutType == RoundOutType.dieOut) {
  913. //1代表0血的敌人
  914. if (enemyNum <= 1) {
  915. this.scheduleOnce(this.startNextSmallRound, this.roundOutTime)
  916. }
  917. }
  918. }
  919. dropOutGoods(pos: cc.Vec3, idNum) {
  920. if (!idNum || !idNum.id) return
  921. let origin = cc.find('icon', this.goods)
  922. if (!this.dropPool.get(idNum.id)) this.dropPool.set(idNum.id, new cc.NodePool())
  923. let node: cc.Node = this.dropPool.get(idNum.id).get()
  924. if (!node) node = cc.instantiate(origin)
  925. node.stopAllActions()
  926. node.parent = this.goodsParent
  927. let endPos = ccUtils.convertNode2NodePosAR(this.goods, this.goodsParent)
  928. node.setPosition(pos)
  929. cc.tween(node)
  930. .then(cc.tween().to(1, {x: endPos.x, y: endPos.y}, {easing: 'quartOut'}))
  931. .call(() => {
  932. if (cc.isValid(node)) {
  933. if (idNum.id == GOODS.ball) {
  934. this.zumaUI.curBalls += idNum.num
  935. } else {
  936. let num = this.getDrop.get(idNum.id)
  937. num += idNum.num
  938. ccUtils.setLabel(num.toString(), this.goods, 'lb')
  939. this.getDrop.set(idNum.id, num)
  940. }
  941. this.dropPool.get(idNum.id).put(node)
  942. }
  943. })
  944. .start()
  945. }
  946. setBallNum(num: number) {
  947. ccUtils.setLabel(num.toString(), this.goods, 'lb')
  948. }
  949. handleDie(entity: EntityIndex) {
  950. let comRole = this.world.getComponent(entity, ComRole)
  951. if (!comRole) return
  952. let roleCfg = comRole.roleCfg
  953. let entities = this.roleEntityMap.get(roleCfg.ID)
  954. if (entities) {
  955. entities.indexOf(entity) >= 0 && entities.splice(entities.indexOf(entity), 1)
  956. let transCfgID = -1
  957. comRole.skills.forEach(skill => {
  958. if (skill.type == SKILL_TYPE.transRole) {
  959. transCfgID = skill.createRole[0]
  960. }
  961. })
  962. let transArr = this.roleEntityMap.get(transCfgID * 100 + (comRole.roleCfg.ID % 100)) || []
  963. let resetID = -1
  964. //唯一卡死亡后重新召唤(排除变身后还在场上)
  965. if (roleCfg.type == ROLE_TYPE.only && (transCfgID == -1 || (transCfgID > 0 && !transArr.length))) {
  966. resetID = roleCfg.ID
  967. }
  968. //唯一卡变身后死亡重启召唤
  969. let transOnly = comRole.transID && RoleConfig[comRole.transID].type == ROLE_TYPE.only
  970. if (transOnly && !this.roleEntityMap.get(comRole.transID)?.length) {
  971. resetID = comRole.transID
  972. }
  973. }
  974. if (comRole.drop && comRole.drop.num > 0) {
  975. let comTransform = this.world.getComponent(entity, ComTransform)
  976. this.dropOutGoods(cc.v3(comTransform.x, comTransform.y, 0), comRole.drop)
  977. }
  978. //移除右半场已经死亡的友军
  979. if (comRole.group == Data.game.gFriend) {
  980. let inRightIndex = this.rightAreaFriend.indexOf(entity)
  981. if (inRightIndex >= 0) this.rightAreaFriend.splice(inRightIndex, 1)
  982. }
  983. }
  984. initGameSpeed() {
  985. this.speed.active = true
  986. if (!Mgr.global.checkModOpen(MOD.speedGame)) return
  987. Mgr.net.add(msgCmd.cmd_speed_up_data_rsp, this, this.speedUpDataRsp)
  988. Mgr.net.send(msgCmd.cmd_speed_up_data)
  989. }
  990. showClickAni(pos: cc.Vec3) {
  991. let node = cc.find('clickAni', this.node)
  992. node.position = pos
  993. node.stopAllActions()
  994. node.scale = 0.5
  995. node.opacity = 255
  996. let t = cc.tween
  997. //node放大渐隐
  998. t(node)
  999. .then(t().parallel(t().to(0.5, {scale: 1.8}), t().delay(0.2).to(0.3, {opacity: 0})))
  1000. .start()
  1001. }
  1002. showBossHP(comRole: ComRole) {
  1003. this.bossHPNode.active = true
  1004. let maxBars = 6
  1005. let healthPerBar = Math.floor(comRole.HP / maxBars) // 每管血量
  1006. let currentBars =
  1007. comRole.nowHP > healthPerBar * (maxBars - 1) ? maxBars : Math.ceil(comRole.nowHP / healthPerBar)
  1008. let lastBars =
  1009. comRole.lastHP > healthPerBar * (maxBars - 1) ? maxBars : Math.ceil(comRole.lastHP / healthPerBar)
  1010. // 更新标签
  1011. ccUtils.setLabel(`x${currentBars}`, this.bossHPNode, 'label')
  1012. let getImageNum = index => {
  1013. if (index > 0) {
  1014. return index % 5 ? index % 5 : 5
  1015. }
  1016. return 0
  1017. }
  1018. if (currentBars != lastBars || comRole.nowHP == comRole.HP) {
  1019. if (currentBars > 1) {
  1020. this.zumaUI.loadTexImg(`GameUI/boss_blood_${getImageNum(currentBars - 1)}`, this.bossHPNode, 'bg')
  1021. } else {
  1022. ccUtils.setSpriteFrame(null, this.bossHPNode, 'bg')
  1023. }
  1024. this.zumaUI.loadTexImg(`GameUI/boss_blood_${getImageNum(currentBars)}`, this.bossHPNode, 'pb/bar')
  1025. }
  1026. ccUtils.setProgress(
  1027. currentBars == maxBars
  1028. ? (comRole.nowHP - healthPerBar * (maxBars - 1)) / (healthPerBar + (comRole.HP % healthPerBar))
  1029. : (comRole.nowHP % healthPerBar) / healthPerBar,
  1030. this.bossHPNode,
  1031. 'pb',
  1032. )
  1033. }
  1034. hideBossHP() {
  1035. this.bossHPNode.active = false
  1036. }
  1037. //我方右半区友军大于一定数量增加刷怪
  1038. addRightAreaFriendNum(entity) {
  1039. if (!this.curRoundCfg) return
  1040. //处理下容错,刚好这一帧死亡,下一次推入新的友军可以过滤掉
  1041. this.rightAreaFriend = this.rightAreaFriend.filter(v => !this.world.isDie(v))
  1042. this.rightAreaFriend.push(entity)
  1043. if ('extraRoles' in this.curRoundCfg) {
  1044. for (let i = 0; i < this.extraEnemyCreateArr.length; i++) {
  1045. if (!this.extraEnemyCreateArr[i] && this.rightAreaFriend.length >= this.curRoundCfg.additional[i]) {
  1046. for (let j = 0; j < this.curRoundCfg.addNum[i]; j++) {
  1047. this.world.createRoleEntity(
  1048. this.getRoleCfgByCfgID(this.curRoundCfg.extraRoles[i]),
  1049. true,
  1050. this.getRolePos(this.curRoundCfg.position[i]),
  1051. null,
  1052. null,
  1053. true,
  1054. )
  1055. }
  1056. this.extraEnemyCreateArr[i] = true
  1057. }
  1058. }
  1059. }
  1060. }
  1061. getStageInfoCfg() {
  1062. let cfg: IStageInfoConfig
  1063. if (Data.game.gameType == GAME_TYPE.normal || Data.game.gameType == GAME_TYPE.none) {
  1064. cfg = StageInfoConfig[this.curStage]
  1065. }
  1066. return cfg
  1067. }
  1068. getRoundCfg(isNext: boolean = false, roundIndex: number = 0) {
  1069. let cfg: IStageConfig
  1070. let baseRound = Data.game.stageRound
  1071. if (isNext) baseRound += 1
  1072. if (roundIndex) baseRound += roundIndex
  1073. if (Data.game.gameType == GAME_TYPE.normal || Data.game.gameType == GAME_TYPE.none) {
  1074. cfg = StageConfig[baseRound]
  1075. }
  1076. return cfg
  1077. }
  1078. scrollMap(dt: number) {
  1079. if (!this.isScrollMap) return
  1080. let children = this.bgRolls.children
  1081. children.forEach(node => {
  1082. node.x -= dt * 300
  1083. })
  1084. children.sort((a, b) => a.x - b.x)
  1085. if (children[0].x <= -children[0].width) {
  1086. children[0].x = children[1].x + children[0].width
  1087. }
  1088. }
  1089. changeBagShow(isShow: boolean) {
  1090. this.bag.stopAllActions()
  1091. let targetY = -830
  1092. this.bag.y = targetY + (isShow ? this.bag.height : 0)
  1093. cc.tween(this.bag)
  1094. .to(this.zumaUI.fightReadyTime, {y: targetY + (isShow ? 0 : this.bag.height)})
  1095. .start()
  1096. }
  1097. //---------------------点击事件--------------------------------
  1098. onCardSkillSureClick(e) {
  1099. let pos = ccUtils.convertWorldPosToNode(this.node, ccUtils.convertTouchPosToWorld(e))
  1100. let isHurt = SkillConfig[this.curCardSkillCfg.skills[0]].isHurt
  1101. if (this.curCardSkillCfg.castType == CARD_CAST_AREA.fullScreen) {
  1102. // let filterE = this.world.getFilter(FILTER_CAN_ATTACK_ENEMY)
  1103. // let filter = this.world.getFilter(FILTER_CAN_ATTACK_FRIEND)
  1104. // let isHurt = SkillConfig[this.curCardSkillCfg.skills[0]].isHurt
  1105. // if ((filterE.entities.size == 0 && isHurt) || (filter.entities.size == 0 && !isHurt)) {
  1106. // Mgr.ui.tip('没有目标可以施放卡牌技能')
  1107. // return
  1108. // }
  1109. this.castSkillByCard()
  1110. } else if (
  1111. this.curCardSkillCfg.castType == CARD_CAST_AREA.radius ||
  1112. this.curCardSkillCfg.castType == CARD_CAST_AREA.rect
  1113. ) {
  1114. let curNode = this.skillArea
  1115. this.zumaUI.loadTexImg(
  1116. `GameUI/skill_range_${this.curCardSkillCfg.castType}${isHurt ? '' : '_friend'}`,
  1117. curNode,
  1118. )
  1119. let radiusAni = cc.find('radiusAni', curNode)
  1120. radiusAni.active = this.curCardSkillCfg.castType == CARD_CAST_AREA.radius
  1121. if (radiusAni.active) {
  1122. this.zumaUI.loadTexImg(
  1123. `GameUI/skill_range_${this.curCardSkillCfg.castType}_ani${isHurt ? '' : '_friend'}`,
  1124. radiusAni,
  1125. )
  1126. radiusAni.stopAllActions()
  1127. cc.tween(radiusAni).to(0, {scale: 0.2}).to(0.5, {scale: 1}).union().repeatForever().start()
  1128. }
  1129. let rangeAni = cc.find('rectAni', curNode)
  1130. rangeAni.active = this.curCardSkillCfg.castType == CARD_CAST_AREA.rect
  1131. if (rangeAni.active) {
  1132. rangeAni.stopAllActions()
  1133. cc.tween(rangeAni).to(0, {scaleX: 0}).to(0.5, {scaleX: 1}).union().repeatForever().start()
  1134. }
  1135. if (this.curCardSkillCfg.castType == CARD_CAST_AREA.rect) {
  1136. if (pos.x - curNode.width / 2 < Data.game.fightSizeMinX)
  1137. pos.x = Data.game.fightSizeMinX + curNode.width / 2
  1138. if (pos.x + curNode.width / 2 > Data.game.fightSizeMaxX)
  1139. pos.x = Data.game.fightSizeMaxX - curNode.width / 2
  1140. if (pos.y - curNode.height / 2 < Data.game.fightSizeMinY)
  1141. pos.y = Data.game.fightSizeMinY + curNode.height / 2
  1142. if (pos.y + curNode.height / 2 > Data.game.fightSizeMaxY)
  1143. pos.y = Data.game.fightSizeMaxY - curNode.height / 2
  1144. }
  1145. curNode.setPosition(pos)
  1146. this.skillAreaCObject.setPosition(cc.v3(pos))
  1147. //cCollider.inst.update(0)
  1148. // if (this.skillAreaCObject.containsBody.size <= 0) {
  1149. // Mgr.ui.tip('没有目标可以施放卡牌技能')
  1150. // return
  1151. // }
  1152. this.scheduleOnce(this.castSkillByCard, 1)
  1153. this.scheduleOnce(this.resetSkillArea, 1)
  1154. }
  1155. this.skillArea.active = true
  1156. this.skillPop.active = false
  1157. }
  1158. onSkillPopCloseClick() {
  1159. this.skillPop.active = false
  1160. cc.find('popChoose', this.curSkillOptCell.node).active = false
  1161. }
  1162. onClickGameSpeed() {
  1163. if (Data.game.gameSpeed == 1) {
  1164. let isDouble = Data.game.speedUpTime > 0
  1165. if (isDouble || true) {
  1166. Data.game.gameSpeed = 2
  1167. } else {
  1168. this.isStop = true
  1169. Mgr.ui.show(UI.GameSpeedUI)
  1170. }
  1171. } else {
  1172. Data.game.gameSpeed = 1
  1173. }
  1174. }
  1175. onClickDrop(e) {
  1176. let node = e.currentTarget
  1177. let idNum = node['idNum']
  1178. let pool = this.dropPool.get(idNum.id)
  1179. if (!pool) {
  1180. pool = new cc.NodePool()
  1181. this.dropPool.set(idNum.id, pool)
  1182. }
  1183. pool.put(node)
  1184. let awardCfg = AwardConfig[GoodsConfig[idNum.id]?.award]
  1185. if (awardCfg) {
  1186. let addNum = Math.randomRangeInt(awardCfg.oddsMin[0], awardCfg.oddsMax[0])
  1187. }
  1188. }
  1189. onTestEndGameClick() {
  1190. this.testClickNum += 1
  1191. if (this.testClickNum == 5) {
  1192. this.zumaUI.endGame(true)
  1193. }
  1194. }
  1195. //网络事件=======================================
  1196. onRoundStartRsp(data: adventureLayerRsp) {
  1197. Data.game.stageRound += 1
  1198. this.curRoundIndex += 1
  1199. this.resetRound()
  1200. }
  1201. speedUpDataRsp(rsp: speedUpDataRsp) {
  1202. Data.game.speedUpTime = rsp.time
  1203. this.speed.active = true
  1204. let isDouble = rsp.time > 0
  1205. let tip = cc.find('tip', this.speed)
  1206. tip.active = !isDouble
  1207. if (tip.active) {
  1208. tip.y = -105
  1209. tip.stopAllActions()
  1210. cc.tween(tip)
  1211. .by(1, {position: cc.v3(0, 10)}, {easing: 'sineOut'}) // 缓慢上移10像素
  1212. .by(1, {position: cc.v3(0, -10)}, {easing: 'sineIn'}) // 缓慢下落10像素
  1213. .union()
  1214. .repeat(3)
  1215. .call(() => {
  1216. tip.active = false
  1217. })
  1218. .start()
  1219. }
  1220. }
  1221. //触发事件=======================================
  1222. @render
  1223. addTime() {
  1224. let time = Data.main.serverTime
  1225. if (this.speed.active) {
  1226. if (Data.game.speedUpTime > 0) {
  1227. Data.game.speedUpTime -= 1
  1228. if (Data.game.speedUpTime <= 0) Data.game.speedUpTime = 0
  1229. ccUtils.setLabel(Date.Format('hh:mm:ss', Data.game.speedUpTime, true), this.speed, 'time')
  1230. } else {
  1231. ccUtils.setLabel('', this.speed, 'time')
  1232. Data.game.gameSpeed = 1
  1233. }
  1234. }
  1235. }
  1236. @render
  1237. showSpeed() {
  1238. let speed = Data.game.gameSpeed
  1239. let tip = cc.find('tip', this.speed)
  1240. tip.active = speed > 1
  1241. //cc.find('tip', this.speed).active = speed > 1
  1242. // if (speedCircle.active) {
  1243. // speedCircle.runAction(cc.rotateBy(1, 360).repeatForever())
  1244. // }
  1245. }
  1246. public setGameTex(url: string, node?: cc.Node, childUrl?: string) {
  1247. if (childUrl) {
  1248. node = cc.find(childUrl, node)
  1249. }
  1250. let sprite = node.getComponent(cc.Sprite)
  1251. if (sprite) {
  1252. sprite.spriteFrame = Data.game.gameAssetMap.get(`texture/${url}`) as cc.SpriteFrame
  1253. }
  1254. }
  1255. private registerTouchEvent() {
  1256. this.touchNode.on(cc.Node.EventType.TOUCH_START, this._onTouchStart, this)
  1257. this.touchNode.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this)
  1258. this.touchNode.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this)
  1259. this.touchNode.on(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this)
  1260. }
  1261. private _onTouchStart(e: cc.Event.EventTouch) {
  1262. for (let i = 0; i < this._touchHandler.length; i++) {
  1263. this._touchHandler[i].onTouchStart(ccUtils.convertTouchPosToWorld(e), this.world)
  1264. }
  1265. }
  1266. private _onTouchMove(e: cc.Event.EventTouch) {
  1267. for (let i = 0; i < this._touchHandler.length; i++) {
  1268. this._touchHandler[i].onTouchMove(ccUtils.convertTouchPosToWorld(e), this.world)
  1269. }
  1270. }
  1271. private _onTouchEnd(e: cc.Event.EventTouch) {
  1272. for (let i = 0; i < this._touchHandler.length; i++) {
  1273. this._touchHandler[i].onTouchEnd(ccUtils.convertTouchPosToWorld(e), this.world)
  1274. }
  1275. }
  1276. private _onTouchCancel(e: cc.Event.EventTouch) {
  1277. for (let i = 0; i < this._touchHandler.length; i++) {
  1278. this._touchHandler[i].onTouchCancel(ccUtils.convertTouchPosToWorld(e), this.world)
  1279. }
  1280. }
  1281. public registerTouchHandler(handler: ITouchProcessor) {
  1282. this._touchHandler.push(handler)
  1283. }
  1284. public unRegisterTouchHandler(handler: ITouchProcessor) {
  1285. for (let i = this._touchHandler.length - 1; i >= 0; i--) {
  1286. if (this._touchHandler[i] == handler) {
  1287. this._touchHandler.splice(i, 1)
  1288. }
  1289. }
  1290. }
  1291. }