FightCore.ts 53 KB

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