FightCore.ts 53 KB

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