FightCore.ts 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  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('round')
  116. private roundNode: cc.Node
  117. @node('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. //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.zumaUI.activeBuff.forEach(v => this.addTeamBuff(v))
  521. this.bagCardList.numItems = this.zumaUI.activeBuff.length
  522. ccUtils.setProgress((this.curRoundIndex + 1) / this.allRoundNum, this.roundNode, 'roundPb')
  523. ccUtils.setLabel(`${this.curRoundIndex + 1}/${this.allRoundNum}`, this.roundNode, 'roundPb/lb')
  524. if (this.curRoundIndex > 0) {
  525. this.isScrollMap = true
  526. this.changeTeamRoleRun(true)
  527. this.scheduleOnce(() => {
  528. this.isScrollMap = false
  529. this.isStop = false
  530. this.changeTeamRoleRun(false)
  531. }, this.zumaUI.fightReadyTime)
  532. } else {
  533. this.isStop = false
  534. }
  535. }
  536. startNextSmallRound() {
  537. let bigRoundTime = this.curRoundCfg.trigger
  538. if (!bigRoundTime && this.curRoundCreateIndex >= this.smallRoundArr.length) {
  539. this.roundFight = false
  540. this.readyNextRound()
  541. return
  542. }
  543. for (let roleItem of this.smallRoundArr[this.curRoundCreateIndex]) {
  544. let cfg = this.getRoleCfgByCfgID(roleItem.id)
  545. this.createEnemyNum += 1
  546. this.world.createRoleEntity(cfg, true, roleItem.pos, null, roleItem.drop)
  547. }
  548. //如果bigRoundTime>0 再最后一小波的时候直接开始下一大波
  549. if (this.curRoundCreateIndex == this.smallRoundArr.length - 1 && bigRoundTime > 0) {
  550. this.roundFight = false
  551. this.scheduleOnce(this.readyNextRound, bigRoundTime)
  552. }
  553. this.curRoundCreateIndex += 1
  554. }
  555. showFightTip(tip) {
  556. let tipStr = ''
  557. if (!tip) return
  558. switch (tip) {
  559. case FightTip.wave:
  560. tipStr = LANGUAGE_TYPE.waveFightTip
  561. break
  562. case FightTip.boss:
  563. tipStr = LANGUAGE_TYPE.bossFightTip
  564. break
  565. }
  566. this.fightTip.stopAllActions()
  567. this.fightTip.opacity = 255
  568. ccUtils.setLabel(tipStr, this.fightTip, 'label')
  569. cc.tween(this.fightTip)
  570. .to(0.5, {opacity: 0})
  571. .reverseTime()
  572. .repeat(3)
  573. .call(() => {
  574. this.fightTip.opacity = 0
  575. })
  576. .start()
  577. }
  578. initRoles() {
  579. this.teamEntity.length = 0
  580. Data.user.teamRole.length = 0
  581. Data.user.teamRole.push(Mgr.global.buildIRole({equip: [], lv: 1, sid: '', id: 12501}))
  582. Data.user.teamRole.push(Mgr.global.buildIRole({equip: [], lv: 1, sid: '', id: 10401}))
  583. Data.user.teamRole.push(Mgr.global.buildIRole({equip: [], lv: 1, sid: '', id: 11001}))
  584. let iRoles = Data.user.teamRole.filter(v => v)
  585. for (let i = 0; i < Data.game.friendNum; i++) {
  586. let iRole = iRoles[i]
  587. if (iRole) {
  588. //友军位置ID写死101-200
  589. let entity = this.world.createRoleEntity(iRole.cfg.ID, false, 101 + i, iRole)
  590. console.warn('创建队友', entity)
  591. this.teamEntity.push(entity)
  592. }
  593. }
  594. this.teamHP = 0
  595. this.changeTeamHp()
  596. }
  597. changeTeamRoleRun(isRun: boolean) {
  598. this.teamEntity.forEach(entity => {
  599. this.world.changeRoleRun(entity, isRun)
  600. })
  601. }
  602. addTeamBuff(buffID) {
  603. let cfg = ZumabuffConfig[buffID]
  604. cfg.buff.forEach(buffID => {
  605. let buffCfg = BuffConfig[buffID]
  606. if (buffCfg) {
  607. for (let i = 0; i < this.teamEntity.length; i++) {
  608. let entity = this.teamEntity[i]
  609. let comRole = this.world.getComponent(entity, ComRole)
  610. if (comRole && cfg.profession.includes(comRole.roleCfg.profession)) {
  611. this.world.addBuff(entity, this.world.createBuff(buffID, null), null)
  612. }
  613. }
  614. }
  615. })
  616. }
  617. initSkillItem(node, index) {
  618. let buffID = this.zumaUI.activeBuff[index]
  619. this.zumaUI.initZumaBuffItem(buffID, cc.find('buff', node).children[0])
  620. let skillOptCell = node.getComponent(SkillOptCell)
  621. skillOptCell.init(buffID, this)
  622. }
  623. initSkillArea() {
  624. this.skillAreaCObject.init(Data.game.gSkillArea, -100)
  625. cCollider.inst.insert(this.skillAreaCObject.body)
  626. this.skillArea.active = false
  627. }
  628. resetSkillArea() {
  629. this.skillArea.active = false
  630. }
  631. showSkillPop(iCard: ICard) {
  632. this.skillPop.active = true
  633. let cfg = iCard.cfg
  634. ccUtils.setLabel(cfg.name, this.skillPop, 'tip/skillname')
  635. ccUtils.setRichLabel(cfg.tip, this.skillPop, 'tip/scrollView/view/content/rt')
  636. if (cfg.attrNum.length > 0) {
  637. let i18nLb = cc.find('tip/scrollView/view/content/rt', this.skillPop).getComponent(i18nLabel)
  638. i18nLb.init(
  639. cfg.tip,
  640. cfg.attrNum.map(v => v.toString()),
  641. )
  642. }
  643. this.skillArea.width = cfg.width
  644. this.skillArea.height = cfg.height
  645. let radiusAni = cc.find('radiusAni', this.skillArea)
  646. radiusAni.width = cfg.width
  647. radiusAni.height = cfg.height
  648. let rangeAni = cc.find('rectAni', this.skillArea)
  649. rangeAni.width = cfg.width
  650. rangeAni.height = cfg.height
  651. rangeAni.x = -cfg.width / 2
  652. this.skillAreaCObject.updateBoxShape(cfg.width, cfg.height)
  653. this.unschedule(this.resetSkillArea)
  654. this.curCardSkillCfg = cfg
  655. this.curCard = iCard
  656. }
  657. skillOptShow(skillOptCell: SkillOptCell) {
  658. let iCard = skillOptCell.zumabuffCfg
  659. if (!this.skillPop.active) {
  660. this.curSkillOptCell = skillOptCell
  661. }
  662. }
  663. castSkillByCard() {
  664. let friend = []
  665. let enemy = []
  666. let world = this.world
  667. let targetEntities: number[] = []
  668. let cardSkillCfg = this.curCard.cfg
  669. let iCard = this.curCard
  670. let skillCfg = SkillConfig[cardSkillCfg.skills[0]]
  671. //先找出所有目标
  672. if (cardSkillCfg.castType == CARD_CAST_AREA.fullScreen) {
  673. let filter = skillCfg.isHurt
  674. ? this.world.getFilter(FILTER_CAN_ATTACK_ENEMY)
  675. : this.world.getFilter(FILTER_CAN_ATTACK_FRIEND)
  676. filter.walk((entity: number) => {
  677. targetEntities.push(entity)
  678. return false
  679. })
  680. } else if (cardSkillCfg.castType == CARD_CAST_AREA.radius || cardSkillCfg.castType == CARD_CAST_AREA.rect) {
  681. //范围技能
  682. //this.skillAreaCObject.trigger = true
  683. cCollider.inst.update(0)
  684. this.skillAreaCObject.containsBody.forEach((body, key) => {
  685. let comRole = world.getComponent(key, ComRole)
  686. if (!world.isDie(comRole) && !world.isBase(comRole)) {
  687. if (world.getComponent(key, ComEnemy)) {
  688. enemy.push(key)
  689. } else {
  690. friend.push(key)
  691. }
  692. }
  693. })
  694. this.skillAreaCObject.setPosition(cc.v3(0, -200, 0))
  695. //this.skillAreaCObject.trigger = false
  696. targetEntities = skillCfg.isHurt ? enemy : friend
  697. }
  698. //技能子弹不能打到建筑
  699. if (cardSkillCfg.bullet > 0) {
  700. targetEntities = targetEntities.filter(v => {
  701. let comRole = world.getComponent(v, ComRole)
  702. return comRole.roleCfg.type != ROLE_TYPE.base
  703. })
  704. }
  705. targetEntities.outOrder()
  706. let startPos: cc.Vec2 = cc.Vec2.ZERO
  707. let startCfgType = cardSkillCfg.posType[0]
  708. let endPos: cc.Vec2 = cc.Vec2.ZERO
  709. let endCfgType = cardSkillCfg.posType[1]
  710. let endPosArr: cc.Vec2[] = []
  711. let areaWidth = this.skillArea.width
  712. let areaHeight = this.skillArea.height
  713. let leftAreaX = this.skillArea.x - areaWidth / 2
  714. let rightAreaX = this.skillArea.x + areaWidth / 2
  715. let belowAreaY = this.skillArea.y - areaHeight / 2
  716. let topAreaY = this.skillArea.y + areaHeight / 2
  717. let castDirType = cardSkillCfg.moreSkill[0]
  718. let castTimes = cardSkillCfg.moreSkill[1]
  719. let castInterval = cardSkillCfg.moreSkill[2] ? cardSkillCfg.moreSkill[2] : 0
  720. if (endCfgType == CARD_END_POS.rowCol) {
  721. let stepX = areaWidth / (cardSkillCfg.posType[3] + 1)
  722. let stepY = areaHeight / (cardSkillCfg.posType[2] + 1)
  723. for (let i = 1; i <= cardSkillCfg.posType[2]; i++) {
  724. for (let j = 1; j <= cardSkillCfg.posType[3]; j++) {
  725. let x = leftAreaX + j * stepX
  726. let y = topAreaY - i * stepY
  727. endPosArr.push(cc.v2(x, y))
  728. }
  729. }
  730. if (endPosArr.length != cardSkillCfg.moreSkill.length) {
  731. console.error('卡牌技能多行多列数量与moreSkill配置不一致')
  732. }
  733. }
  734. if (targetEntities.length > 0 && targetEntities.length < castTimes && castDirType == CARD_MORE_DIR.one2One) {
  735. //重复数组补齐
  736. let repeat = Math.ceil(castTimes / targetEntities.length)
  737. for (let j = 0; j < repeat; j++) {
  738. targetEntities = targetEntities.concat(targetEntities)
  739. }
  740. }
  741. for (let i = 0; i < castTimes; i++) {
  742. this.scheduleOnce(() => {
  743. if (!this.node.activeInHierarchy) return
  744. let comTransform = world.getComponent(targetEntities[i], ComTransform)
  745. let randomX = Math.randomRangeFloat(leftAreaX, rightAreaX)
  746. let randomY = Math.randomRangeFloat(belowAreaY, topAreaY)
  747. if (startCfgType == START_POS.straightFall || startCfgType == START_POS.obliqueFall) {
  748. startPos.y = ConstValue.CANVAS_HEIGHT / 2
  749. if (endCfgType == CARD_END_POS.random || (endCfgType == CARD_END_POS.role && !comTransform)) {
  750. startPos.x = randomX
  751. endPos.x = randomX
  752. endPos.y = randomY
  753. } else if (endCfgType == CARD_END_POS.rowCol) {
  754. startPos.x = randomX
  755. endPos = endPosArr[i]
  756. } else if (endCfgType == CARD_END_POS.role && comTransform) {
  757. startPos.x = comTransform.x
  758. if (startCfgType == START_POS.obliqueFall) startPos.x -= 200
  759. endPos.x = comTransform.x
  760. endPos.y = comTransform.y
  761. }
  762. } else if (startCfgType == START_POS.leftScreen) {
  763. startPos.x = -ConstValue.CANVAS_WIDTH / 2
  764. startPos.y = this.skillArea.y
  765. if (endCfgType == CARD_END_POS.rightScreen) {
  766. endPos.x = ConstValue.CANVAS_WIDTH
  767. endPos.y = startPos.y
  768. }
  769. } else if (startCfgType == START_POS.areaCenter) {
  770. startPos.x = this.skillArea.x
  771. startPos.y = this.skillArea.y
  772. } else if (startCfgType == START_POS.fightCenter) {
  773. startPos.x = (Data.game.fightSizeMaxX + Data.game.fightSizeMinX) / 2
  774. startPos.y = (Data.game.fightSizeMaxY + Data.game.fightSizeMinY) / 2
  775. }
  776. //子弹技能
  777. if (cardSkillCfg.bullet > 0 && castDirType == CARD_MORE_DIR.one2One) {
  778. this.world.createCardBulletEntity(iCard, startPos, endPos, targetEntities[i])
  779. } else if (!cardSkillCfg.bullet) {
  780. if (castDirType == CARD_MORE_DIR.noOne) {
  781. let skillEntity = world.createSkill(
  782. {buffs: [], entryMap: new Map<ENTRY, EntryObj>(), ...iCard},
  783. skillCfg,
  784. 0,
  785. cc.v3(startPos),
  786. skillCfg.isHurt ? Data.game.gFriendHurtSkill : Data.game.gFriendGainSkill,
  787. )
  788. if (cardSkillCfg.moveSpeed > 0 && skillCfg.type == SKILL_TYPE.attackBack) {
  789. let comMovable = world.addComponent(skillEntity, ComMovable)
  790. comMovable.pointIdx = 0
  791. comMovable.points.length = 0
  792. comMovable.speed = cardSkillCfg.moveSpeed
  793. comMovable.points.push(endPos)
  794. }
  795. } else if (castDirType == CARD_MORE_DIR.one2All) {
  796. if (skillCfg.dirType == SKILL_DIR_TYPE.minHpRole) {
  797. targetEntities.sort((a, b) => {
  798. let comA = world.getComponent(a, ComRole)
  799. let comB = world.getComponent(b, ComRole)
  800. return comA?.nowHP - comB?.nowHP
  801. })
  802. }
  803. for (let i = 0; i < Math.min(skillCfg.maxRole, targetEntities.length); i++) {
  804. world.createSkill(
  805. {buffs: [], entryMap: new Map<ENTRY, EntryObj>(), ...iCard},
  806. skillCfg,
  807. targetEntities[i],
  808. null,
  809. skillCfg.isHurt ? Data.game.gFriendHurtSkill : Data.game.gFriendGainSkill,
  810. )
  811. }
  812. }
  813. }
  814. }, castInterval * i)
  815. }
  816. this.curSkillOptCell?.startCD()
  817. }
  818. getGameInfo(): {roleNum: number; enemyNum: number; castCost: number} {
  819. let roleNum = 0
  820. let enemyNum = 0
  821. this.world?.getFilter(FILTER_ROLE_NODE)?.walk((entity: number) => {
  822. if (this.world.getComponent(entity, ComEnemy)) {
  823. enemyNum++
  824. } else {
  825. roleNum++
  826. }
  827. return false
  828. })
  829. return {roleNum, enemyNum, castCost: 0}
  830. }
  831. createDevEntity(ID: number, isEnemy?: boolean, posCfgID?: number, iRole?: IRole) {
  832. let roleCfg = RoleConfig[ID]
  833. if (!roleCfg) {
  834. roleCfg = (MonsterConfig[ID] as unknown) as IRoleConfig
  835. }
  836. this.world.createRoleEntity(roleCfg, isEnemy, posCfgID, iRole)
  837. }
  838. changeStageChange(stage: number) {
  839. this.curStage = stage
  840. Data.game.stageRound = stage * 100 + 1
  841. Data.game.gameType = GAME_TYPE.normal
  842. this.resetGameWorld()
  843. this.startStageGame()
  844. }
  845. changeTeamHp() {
  846. let nowHp = 0
  847. let nowShieldHp = 0
  848. for (let i = 0; i < this.teamEntity.length; i++) {
  849. let entity = this.teamEntity[i]
  850. let comRole = this.world.getComponent(entity, ComRole)
  851. nowHp += comRole ? comRole.nowHP : 0
  852. nowShieldHp += comRole ? comRole.shieldHP : 0
  853. }
  854. this.teamNowHP = nowHp
  855. this.teamNowShieldHP = nowShieldHp
  856. if (!this.teamHP) this.teamHP = nowHp
  857. let allHp = this.teamHP
  858. if (this.teamNowHP + this.teamNowShieldHP > allHp) allHp = this.teamNowHP + this.teamNowShieldHP
  859. this.teamPb.progress = this.teamNowHP / allHp
  860. this.teamShieldPb.progress = (this.teamNowHP + this.teamNowShieldHP) / allHp
  861. let hpCellNum = Math.ceil(allHp / 100)
  862. //修改为固定10格血
  863. if (hpCellNum > 10) hpCellNum = 10
  864. if (hpCellNum != this.teamHPS.children.length) {
  865. ccUtils.instantChildren(cc.find('hp', this.teamHPS), hpCellNum)
  866. }
  867. if (this.roundFight && this.teamNowHP <= 0 && this.teamNowShieldHP <= 0) {
  868. this.roundFight = false
  869. this.zumaUI.endFightRound(false)
  870. }
  871. }
  872. changeKillNum() {
  873. let enemyNum = this.world.getFilter(FILTER_CAN_ATTACK_ENEMY).entities.size
  874. if (this.stageInfo.type == GAME_WIN_TYPE.killNum || this.stageInfo.type == GAME_WIN_TYPE.boss) {
  875. let allNum = this.monsterNum + this.eliteNum + this.bossNum
  876. ccUtils.setLabel(`${Math.floor((allNum / this.timeRoles.length) * 100)}%`, this.tipKillNumLb)
  877. if (allNum >= this.timeRoles.length) {
  878. this.zumaUI.endFightRound(true)
  879. }
  880. } else if (this.stageInfo.type == GAME_WIN_TYPE.surviveTime) {
  881. //通关类型3 (存活指定时间 或 击杀配置中所有怪物,即判定胜利
  882. if (enemyNum <= 1 && !this.roundFight) {
  883. this.zumaUI.endFightRound(true)
  884. }
  885. }
  886. if (this.roundFight && this.roundOutType == RoundOutType.dieOut) {
  887. //1代表0血的敌人
  888. if (enemyNum <= 1) {
  889. this.scheduleOnce(this.startNextSmallRound, this.roundOutTime)
  890. }
  891. }
  892. }
  893. dropOutGoods(pos: cc.Vec3, idNum) {
  894. if (!idNum || !idNum.id) return
  895. let origin = cc.find('icon', this.goods)
  896. if (!this.dropPool.get(idNum.id)) this.dropPool.set(idNum.id, new cc.NodePool())
  897. let node: cc.Node = this.dropPool.get(idNum.id).get()
  898. if (!node) node = cc.instantiate(origin)
  899. node.stopAllActions()
  900. node.parent = this.goodsParent
  901. node.setPosition(pos)
  902. cc.tween(node)
  903. .then(cc.tween().to(1, {x: this.goods.x, y: this.goods.y}, {easing: 'quartOut'}))
  904. .call(() => {
  905. if (cc.isValid(node)) {
  906. if (idNum.id == GOODS.ball) {
  907. this.zumaUI.curBalls += idNum.num
  908. } else {
  909. let num = this.getDrop.get(idNum.id)
  910. num += idNum.num
  911. ccUtils.setLabel(num.toString(), this.goods, 'lb')
  912. this.getDrop.set(idNum.id, num)
  913. }
  914. this.dropPool.get(idNum.id).put(node)
  915. }
  916. })
  917. .start()
  918. }
  919. setBallNum(num: number) {
  920. ccUtils.setLabel(num.toString(), this.goods, 'lb')
  921. }
  922. handleDie(entity: EntityIndex) {
  923. let comRole = this.world.getComponent(entity, ComRole)
  924. if (!comRole) return
  925. let roleCfg = comRole.roleCfg
  926. let entities = this.roleEntityMap.get(roleCfg.ID)
  927. if (entities) {
  928. entities.indexOf(entity) >= 0 && entities.splice(entities.indexOf(entity), 1)
  929. let transCfgID = -1
  930. comRole.skills.forEach(skill => {
  931. if (skill.type == SKILL_TYPE.transRole) {
  932. transCfgID = skill.createRole[0]
  933. }
  934. })
  935. let transArr = this.roleEntityMap.get(transCfgID * 100 + (comRole.roleCfg.ID % 100)) || []
  936. let resetID = -1
  937. //唯一卡死亡后重新召唤(排除变身后还在场上)
  938. if (roleCfg.type == ROLE_TYPE.only && (transCfgID == -1 || (transCfgID > 0 && !transArr.length))) {
  939. resetID = roleCfg.ID
  940. }
  941. //唯一卡变身后死亡重启召唤
  942. let transOnly = comRole.transID && RoleConfig[comRole.transID].type == ROLE_TYPE.only
  943. if (transOnly && !this.roleEntityMap.get(comRole.transID)?.length) {
  944. resetID = comRole.transID
  945. }
  946. }
  947. if (comRole.drop && comRole.drop.num > 0) {
  948. let comTransform = this.world.getComponent(entity, ComTransform)
  949. this.dropOutGoods(cc.v3(comTransform.x, comTransform.y, 0), comRole.drop)
  950. }
  951. //移除右半场已经死亡的友军
  952. if (comRole.group == Data.game.gFriend) {
  953. let inRightIndex = this.rightAreaFriend.indexOf(entity)
  954. if (inRightIndex >= 0) this.rightAreaFriend.splice(inRightIndex, 1)
  955. }
  956. }
  957. initGameSpeed() {
  958. this.speed.active = true
  959. if (!Mgr.global.checkModOpen(MOD.speedGame)) return
  960. Mgr.net.add(msgCmd.cmd_speed_up_data_rsp, this, this.speedUpDataRsp)
  961. Mgr.net.send(msgCmd.cmd_speed_up_data)
  962. }
  963. showClickAni(pos: cc.Vec3) {
  964. let node = cc.find('clickAni', this.node)
  965. node.position = pos
  966. node.stopAllActions()
  967. node.scale = 0.5
  968. node.opacity = 255
  969. let t = cc.tween
  970. //node放大渐隐
  971. t(node)
  972. .then(t().parallel(t().to(0.5, {scale: 1.8}), t().delay(0.2).to(0.3, {opacity: 0})))
  973. .start()
  974. }
  975. showBossHP(comRole: ComRole) {
  976. this.bossHPNode.active = true
  977. let maxBars = 6
  978. let healthPerBar = Math.floor(comRole.HP / maxBars) // 每管血量
  979. let currentBars =
  980. comRole.nowHP > healthPerBar * (maxBars - 1) ? maxBars : Math.ceil(comRole.nowHP / healthPerBar)
  981. let lastBars =
  982. comRole.lastHP > healthPerBar * (maxBars - 1) ? maxBars : Math.ceil(comRole.lastHP / healthPerBar)
  983. // 更新标签
  984. ccUtils.setLabel(`x${currentBars}`, this.bossHPNode, 'label')
  985. let getImageNum = index => {
  986. if (index > 0) {
  987. return index % 5 ? index % 5 : 5
  988. }
  989. return 0
  990. }
  991. if (currentBars != lastBars || comRole.nowHP == comRole.HP) {
  992. if (currentBars > 1) {
  993. this.zumaUI.loadTexImg(`GameUI/boss_blood_${getImageNum(currentBars - 1)}`, this.bossHPNode, 'bg')
  994. } else {
  995. ccUtils.setSpriteFrame(null, this.bossHPNode, 'bg')
  996. }
  997. this.zumaUI.loadTexImg(`GameUI/boss_blood_${getImageNum(currentBars)}`, this.bossHPNode, 'pb/bar')
  998. }
  999. ccUtils.setProgress(
  1000. currentBars == maxBars
  1001. ? (comRole.nowHP - healthPerBar * (maxBars - 1)) / (healthPerBar + (comRole.HP % healthPerBar))
  1002. : (comRole.nowHP % healthPerBar) / healthPerBar,
  1003. this.bossHPNode,
  1004. 'pb',
  1005. )
  1006. }
  1007. hideBossHP() {
  1008. this.bossHPNode.active = false
  1009. }
  1010. //我方右半区友军大于一定数量增加刷怪
  1011. addRightAreaFriendNum(entity) {
  1012. if (!this.curRoundCfg) return
  1013. //处理下容错,刚好这一帧死亡,下一次推入新的友军可以过滤掉
  1014. this.rightAreaFriend = this.rightAreaFriend.filter(v => !this.world.isDie(v))
  1015. this.rightAreaFriend.push(entity)
  1016. if ('extraRoles' in this.curRoundCfg) {
  1017. for (let i = 0; i < this.extraEnemyCreateArr.length; i++) {
  1018. if (!this.extraEnemyCreateArr[i] && this.rightAreaFriend.length >= this.curRoundCfg.additional[i]) {
  1019. for (let j = 0; j < this.curRoundCfg.addNum[i]; j++) {
  1020. this.world.createRoleEntity(
  1021. this.getRoleCfgByCfgID(this.curRoundCfg.extraRoles[i]),
  1022. true,
  1023. this.getRolePos(this.curRoundCfg.position[i]),
  1024. null,
  1025. null,
  1026. true,
  1027. )
  1028. }
  1029. this.extraEnemyCreateArr[i] = true
  1030. }
  1031. }
  1032. }
  1033. }
  1034. getStageInfoCfg() {
  1035. let cfg: IStageInfoConfig
  1036. if (Data.game.gameType == GAME_TYPE.normal || Data.game.gameType == GAME_TYPE.none) {
  1037. cfg = StageInfoConfig[this.curStage]
  1038. }
  1039. return cfg
  1040. }
  1041. getRoundCfg(isNext: boolean = false, roundIndex: number = 0) {
  1042. let cfg: IStageConfig
  1043. let baseRound = Data.game.stageRound
  1044. if (isNext) baseRound += 1
  1045. if (roundIndex) baseRound += roundIndex
  1046. if (Data.game.gameType == GAME_TYPE.normal || Data.game.gameType == GAME_TYPE.none) {
  1047. cfg = StageConfig[baseRound]
  1048. }
  1049. return cfg
  1050. }
  1051. scrollMap(dt: number) {
  1052. if (!this.isScrollMap) return
  1053. let children = this.bgRolls.children
  1054. children.forEach(node => {
  1055. node.x -= dt * 300
  1056. })
  1057. children.sort((a, b) => a.x - b.x)
  1058. if (children[0].x <= -children[0].width) {
  1059. children[0].x = children[1].x + children[0].width
  1060. }
  1061. }
  1062. changeBagShow(isShow: boolean) {
  1063. this.bag.stopAllActions()
  1064. let targetY = -830
  1065. this.bag.y = targetY + (isShow ? this.bag.height : 0)
  1066. cc.tween(this.bag)
  1067. .to(this.zumaUI.fightReadyTime, {y: targetY + (isShow ? 0 : this.bag.height)})
  1068. .start()
  1069. }
  1070. //---------------------点击事件--------------------------------
  1071. onCardSkillSureClick(e) {
  1072. let pos = ccUtils.convertWorldPosToNode(this.node, ccUtils.convertTouchPosToWorld(e))
  1073. let isHurt = SkillConfig[this.curCardSkillCfg.skills[0]].isHurt
  1074. if (this.curCardSkillCfg.castType == CARD_CAST_AREA.fullScreen) {
  1075. // let filterE = this.world.getFilter(FILTER_CAN_ATTACK_ENEMY)
  1076. // let filter = this.world.getFilter(FILTER_CAN_ATTACK_FRIEND)
  1077. // let isHurt = SkillConfig[this.curCardSkillCfg.skills[0]].isHurt
  1078. // if ((filterE.entities.size == 0 && isHurt) || (filter.entities.size == 0 && !isHurt)) {
  1079. // Mgr.ui.tip('没有目标可以施放卡牌技能')
  1080. // return
  1081. // }
  1082. this.castSkillByCard()
  1083. } else if (
  1084. this.curCardSkillCfg.castType == CARD_CAST_AREA.radius ||
  1085. this.curCardSkillCfg.castType == CARD_CAST_AREA.rect
  1086. ) {
  1087. let curNode = this.skillArea
  1088. this.zumaUI.loadTexImg(
  1089. `GameUI/skill_range_${this.curCardSkillCfg.castType}${isHurt ? '' : '_friend'}`,
  1090. curNode,
  1091. )
  1092. let radiusAni = cc.find('radiusAni', curNode)
  1093. radiusAni.active = this.curCardSkillCfg.castType == CARD_CAST_AREA.radius
  1094. if (radiusAni.active) {
  1095. this.zumaUI.loadTexImg(
  1096. `GameUI/skill_range_${this.curCardSkillCfg.castType}_ani${isHurt ? '' : '_friend'}`,
  1097. radiusAni,
  1098. )
  1099. radiusAni.stopAllActions()
  1100. cc.tween(radiusAni).to(0, {scale: 0.2}).to(0.5, {scale: 1}).union().repeatForever().start()
  1101. }
  1102. let rangeAni = cc.find('rectAni', curNode)
  1103. rangeAni.active = this.curCardSkillCfg.castType == CARD_CAST_AREA.rect
  1104. if (rangeAni.active) {
  1105. rangeAni.stopAllActions()
  1106. cc.tween(rangeAni).to(0, {scaleX: 0}).to(0.5, {scaleX: 1}).union().repeatForever().start()
  1107. }
  1108. if (this.curCardSkillCfg.castType == CARD_CAST_AREA.rect) {
  1109. if (pos.x - curNode.width / 2 < Data.game.fightSizeMinX)
  1110. pos.x = Data.game.fightSizeMinX + curNode.width / 2
  1111. if (pos.x + curNode.width / 2 > Data.game.fightSizeMaxX)
  1112. pos.x = Data.game.fightSizeMaxX - curNode.width / 2
  1113. if (pos.y - curNode.height / 2 < Data.game.fightSizeMinY)
  1114. pos.y = Data.game.fightSizeMinY + curNode.height / 2
  1115. if (pos.y + curNode.height / 2 > Data.game.fightSizeMaxY)
  1116. pos.y = Data.game.fightSizeMaxY - curNode.height / 2
  1117. }
  1118. curNode.setPosition(pos)
  1119. this.skillAreaCObject.setPosition(cc.v3(pos))
  1120. //cCollider.inst.update(0)
  1121. // if (this.skillAreaCObject.containsBody.size <= 0) {
  1122. // Mgr.ui.tip('没有目标可以施放卡牌技能')
  1123. // return
  1124. // }
  1125. this.scheduleOnce(this.castSkillByCard, 1)
  1126. this.scheduleOnce(this.resetSkillArea, 1)
  1127. }
  1128. this.skillArea.active = true
  1129. this.skillPop.active = false
  1130. }
  1131. onSkillPopCloseClick() {
  1132. this.skillPop.active = false
  1133. cc.find('popChoose', this.curSkillOptCell.node).active = false
  1134. }
  1135. onClickGameSpeed() {
  1136. if (Data.game.gameSpeed == 1) {
  1137. let isDouble = Data.game.speedUpTime > 0
  1138. if (isDouble || true) {
  1139. Data.game.gameSpeed = 2
  1140. } else {
  1141. this.isStop = true
  1142. Mgr.ui.show(UI.GameSpeedUI)
  1143. }
  1144. } else {
  1145. Data.game.gameSpeed = 1
  1146. }
  1147. }
  1148. onClickDrop(e) {
  1149. let node = e.currentTarget
  1150. let idNum = node['idNum']
  1151. let pool = this.dropPool.get(idNum.id)
  1152. if (!pool) {
  1153. pool = new cc.NodePool()
  1154. this.dropPool.set(idNum.id, pool)
  1155. }
  1156. pool.put(node)
  1157. let awardCfg = AwardConfig[GoodsConfig[idNum.id]?.award]
  1158. if (awardCfg) {
  1159. let addNum = Math.randomRangeInt(awardCfg.oddsMin[0], awardCfg.oddsMax[0])
  1160. }
  1161. }
  1162. onTestEndGameClick() {
  1163. this.testClickNum += 1
  1164. if (this.testClickNum == 5) {
  1165. this.zumaUI.endGame(true)
  1166. }
  1167. }
  1168. //网络事件=======================================
  1169. onRoundStartRsp(data: adventureLayerRsp) {
  1170. Data.game.stageRound += 1
  1171. this.curRoundIndex += 1
  1172. this.resetRound()
  1173. }
  1174. speedUpDataRsp(rsp: speedUpDataRsp) {
  1175. Data.game.speedUpTime = rsp.time
  1176. this.speed.active = true
  1177. let isDouble = rsp.time > 0
  1178. let tip = cc.find('tip', this.speed)
  1179. tip.active = !isDouble
  1180. if (tip.active) {
  1181. tip.y = -105
  1182. tip.stopAllActions()
  1183. cc.tween(tip)
  1184. .by(1, {position: cc.v3(0, 10)}, {easing: 'sineOut'}) // 缓慢上移10像素
  1185. .by(1, {position: cc.v3(0, -10)}, {easing: 'sineIn'}) // 缓慢下落10像素
  1186. .union()
  1187. .repeat(3)
  1188. .call(() => {
  1189. tip.active = false
  1190. })
  1191. .start()
  1192. }
  1193. }
  1194. //触发事件=======================================
  1195. @render
  1196. addTime() {
  1197. let time = Data.main.serverTime
  1198. if (this.speed.active) {
  1199. if (Data.game.speedUpTime > 0) {
  1200. Data.game.speedUpTime -= 1
  1201. if (Data.game.speedUpTime <= 0) Data.game.speedUpTime = 0
  1202. ccUtils.setLabel(Date.Format('hh:mm:ss', Data.game.speedUpTime, true), this.speed, 'time')
  1203. } else {
  1204. ccUtils.setLabel('', this.speed, 'time')
  1205. Data.game.gameSpeed = 1
  1206. }
  1207. }
  1208. }
  1209. @render
  1210. showSpeed() {
  1211. let speed = Data.game.gameSpeed
  1212. let tip = cc.find('tip', this.speed)
  1213. tip.active = speed > 1
  1214. //cc.find('tip', this.speed).active = speed > 1
  1215. // if (speedCircle.active) {
  1216. // speedCircle.runAction(cc.rotateBy(1, 360).repeatForever())
  1217. // }
  1218. }
  1219. public setGameTex(url: string, node?: cc.Node, childUrl?: string) {
  1220. if (childUrl) {
  1221. node = cc.find(childUrl, node)
  1222. }
  1223. let sprite = node.getComponent(cc.Sprite)
  1224. if (sprite) {
  1225. sprite.spriteFrame = Data.game.gameAssetMap.get(`texture/${url}`) as cc.SpriteFrame
  1226. }
  1227. }
  1228. private registerTouchEvent() {
  1229. this.touchNode.on(cc.Node.EventType.TOUCH_START, this._onTouchStart, this)
  1230. this.touchNode.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this)
  1231. this.touchNode.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this)
  1232. this.touchNode.on(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this)
  1233. }
  1234. private _onTouchStart(e: cc.Event.EventTouch) {
  1235. for (let i = 0; i < this._touchHandler.length; i++) {
  1236. this._touchHandler[i].onTouchStart(ccUtils.convertTouchPosToWorld(e), this.world)
  1237. }
  1238. }
  1239. private _onTouchMove(e: cc.Event.EventTouch) {
  1240. for (let i = 0; i < this._touchHandler.length; i++) {
  1241. this._touchHandler[i].onTouchMove(ccUtils.convertTouchPosToWorld(e), this.world)
  1242. }
  1243. }
  1244. private _onTouchEnd(e: cc.Event.EventTouch) {
  1245. for (let i = 0; i < this._touchHandler.length; i++) {
  1246. this._touchHandler[i].onTouchEnd(ccUtils.convertTouchPosToWorld(e), this.world)
  1247. }
  1248. }
  1249. private _onTouchCancel(e: cc.Event.EventTouch) {
  1250. for (let i = 0; i < this._touchHandler.length; i++) {
  1251. this._touchHandler[i].onTouchCancel(ccUtils.convertTouchPosToWorld(e), this.world)
  1252. }
  1253. }
  1254. public registerTouchHandler(handler: ITouchProcessor) {
  1255. this._touchHandler.push(handler)
  1256. }
  1257. public unRegisterTouchHandler(handler: ITouchProcessor) {
  1258. for (let i = this._touchHandler.length - 1; i >= 0; i--) {
  1259. if (this._touchHandler[i] == handler) {
  1260. this._touchHandler.splice(i, 1)
  1261. }
  1262. }
  1263. }
  1264. }