FightCore.ts 53 KB

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