import { _decorator, Component, director, ERigidBody2DType, instantiate, isValid, Node, Prefab, RigidBody2D, sp, Tween, v2, v3, Vec3 } from "cc"; import { LaserContinueSchedule } from "./LaserContinueSchedule"; import { GBundle } from "../../../game/ConfigRes"; import { WeaponType } from "../../../manager/WeaponDataManager"; import { BattleDataManager, SpecialSkillType } from "../BattleDataManager"; import { SkillType, Skill } from "./Skill"; import { TornadoContinueSchedule } from "./TornadoContinueSchedule"; import { TreasureSkill } from "./TreasureSkill"; import { iceWeaponSchedule } from "./iceWeaponSchedule"; import { FlashlightSchedule } from "./FlashlightSchedule"; import { GEvent } from "db://assets/mx/module/event/GEvent"; import { BubbleSchedule } from "./BubbleSchedule"; import { DroneBullet } from "./DroneBullet"; import { MapAgent } from "../MapAgent"; import { LaserLine } from "./LaserLine"; import { ThunderboltSchedule } from "./ThunderboltSchedule"; import { TetriStackDiagnostics } from "../../../tetriMap/TetriStackDiagnostics"; import { BattlePerformance } from "../BattlePerformance"; import MTools from "db://assets/mx/tools/MTools"; const { ccclass, property } = _decorator; export class WeaponState { public id: number; public config: ITableWeapon2; public isReady: boolean = true; // 是否可用 public remainingCD: number = 0; // 剩余冷却时间 public cd: number = 0; // 冷却总时长(用于 UI 展示) public timer: number = 0; // 定时器ID constructor(id: number, config: ITableWeapon2) { this.id = id; this.config = config; } } /** * 技能控制器 */ @ccclass('SkillController') export class SkillController extends Component { // 可用武器ID数组 private availableWeapons: number[] = []; // 武器状态表 public weaponStates: Map = new Map(); /**特殊武器发射塔数量 */ private specialWeaponLaunchCount = {}; /** 各武器第一次触发狂暴射击(removeCD)时必定生效 */ private furiousShootFirstTriggeredWeapons = new Set(); private _lasers1: Node[] = [] private _lasers2: Node[] = [] dt: number = 0.05 //冰棍转转转 initAll() { this.specialWeaponLaunchCount = {}; this.furiousShootFirstTriggeredWeapons.clear() } /** 结算/退出战斗时回收 ui_skilllayer 下仍挂着的直线弹等(避免 tween/碰撞漏删导致节点泄漏) */ public recycleSkillLayerBullets(): void { const layer = this.node.getChildByName('ui_skilllayer'); if (!layer?.isValid) return; const list = layer.children.slice(); for (let i = 0; i < list.length; i++) { const c = list[i]; if (!c?.isValid) continue; const sk = c.getComponent(Skill); if (!sk || sk.getIsDead()) continue; Tween.stopAllByTarget(c); sk.removeBullet(); } } /**刷新武器状态 */ freshDamageStaWeaponList() { this.availableWeapons = [] let curUseWeaponArr = gg.game.CurentBattle.CurUseWeaponArr.map(item => item.weaponid); //设置可用武器数组 this.availableWeapons = [...curUseWeaponArr]; } onDestroy() { this.unscheduleAllCallbacks(); // 使用组件自己的方法取消定时器 } /** * 初始化武器状态 */ public initWeaponStates(): void { this.weaponStates.clear(); this.freshDamageStaWeaponList(); this.availableWeapons.forEach((weaponId, index) => { const config = gg.data.project.getWeaponData(weaponId); if (config) { let weapon = BattleDataManager.getWeaponAddProperty(weaponId) let statusData = new WeaponState(weaponId, config); statusData.remainingCD = weapon.cd * BattlePerformance.weaponCdMul(); statusData.cd = weapon.cd * BattlePerformance.weaponCdMul(); this.weaponStates.set(weaponId, statusData); if (index == 0) { statusData.isReady = true; } } }); // // 激光/无人机发射塔在开局就应与“已拥有武器”状态保持一致,避免必须先发射一次才显示 this.refreshDroneOrLaserLaunch(); } /** * 释放武器技能 * @param weaponId 武器ID * @returns 是否释放成功 */ public useWeaponSkill(weaponId: number): boolean { const weaponState = this.weaponStates.get(weaponId); if (!weaponState) { console.warn(`武器ID ${weaponId} 不存在或不可用`); return false; } if (!weaponState.isReady) { // console.warn(`武器ID ${weaponId} 技能冷却中,剩余时间: ${weaponState.remainingCD}秒`); return false; } // 执行技能释放逻辑 this.executeWeaponSkill(weaponId); // 开始冷却 this.startCooldown(weaponId); return true; } /** * 执行武器技能逻辑(宝箱武器) * @param weaponId 武器ID * @param startPos 起始位置 * @param isFuel 是否是燃油弹 */ executeTreasureWeaponSkill(weaponId: number) { let posY = 25//间距 let xTime = 0.1//间隔 //单次发射数量 let launchCount = 5 //连发数量 let burstCount = 1 for (let i = 0; i < launchCount; i++) { let addPos = v3(0, i * posY - (launchCount - 1) * posY / 2, 0) for (let j = 0; j < burstCount; j++) { this.scheduleOnce(() => { void (async () => { let weaponNode = await this.instantiateSingleWeapon(weaponId, 1, addPos) if (!weaponNode?.isValid) return; let skillComp = weaponNode.getComponent(TreasureSkill); skillComp.startAtk(); })(); }, xTime * j) } } } /** * 执行武器技能逻辑(无人机) * @param weaponId 武器ID * @param startPos 起始位置 * @param isFuel 是否是燃油弹 */ async executeDroneWeaponSkill(weaponId: number, startPos: Vec3, targetPos: Vec3, isFuel: boolean) { const weaponState = this.weaponStates.get(weaponId); if (!weaponState) return; let weaponProperty = BattleDataManager.getWeaponAddProperty(weaponId) let weaponNode = await this.instantiateSingleWeapon(weaponId, weaponProperty.volume) if (!weaponNode || !weaponNode.isValid) return; weaponNode.worldPosition = startPos let skillComp = weaponNode.getComponent(Skill); skillComp.setData(weaponState.config, targetPos, false, isFuel); } /** * 执行武器技能逻辑 * @param weaponId 武器ID */ executeWeaponSkill(weaponId: number) { const weaponState = this.weaponStates.get(weaponId); if (!weaponState) return; // console.log(`释放武器 ${weaponId} 技能,伤害: ${weaponState.config.hp}`); // 这里添加实际的技能效果逻辑 // 例如:播放特效、造成伤害等 let weaponProperty = BattleDataManager.getWeaponAddProperty(weaponId) if (weaponState.config.flight == SkillType.直线弹幕) { //解锁了特殊技能移除cd let isRemoveCD = false let removeCDTime = 0 for (let i = 0; i < weaponProperty.specialSkillInfo.length; i++) { let buffInfo = weaponProperty.specialSkillInfo[i] let arr = buffInfo.split(',') let buffType = Number(arr[0]) if (buffType == SpecialSkillType.removeCD) { //移除cd let rateNum = Number(arr[1]) / 10000//移除cd的概率 removeCDTime = Number(arr[2])//持续时间 isRemoveCD = Math.random() < rateNum if (!this.furiousShootFirstTriggeredWeapons.has(weaponId)) { this.furiousShootFirstTriggeredWeapons.add(weaponId) isRemoveCD = true } this.forceChangeWeaponCD(weaponId, removeCDTime) } } let posX = weaponState.config.bullet_distance //y轴间距 let xTime = weaponState.config.bullet_column//间隔 //单次发射数量 let launchCount = weaponProperty.launchCount //连发数量 let burstCount = isRemoveCD ? Math.floor(removeCDTime / xTime) : weaponProperty.burstCount; GEvent.Ins.emit(GEvent.StraightWeaponShoot, weaponProperty, posX, xTime, launchCount, burstCount) } else if (weaponState.config.flight == SkillType.直线弹射) { //击中目标,再次弹射一下,重新生成一个武器再次寻找一个目标,这个武器不能继续分裂 let isRemoveCD = false let removeCDTime = 0 for (let i = 0; i < weaponProperty.specialSkillInfo.length; i++) { let buffInfo = weaponProperty.specialSkillInfo[i] let arr = buffInfo.split(',') let buffType = Number(arr[0]) if (buffType == SpecialSkillType.removeCD) { //移除cd let rateNum = Number(arr[1]) / 10000//移除cd的概率 removeCDTime = Number(arr[2])//持续时间 isRemoveCD = Math.random() < rateNum if (!this.furiousShootFirstTriggeredWeapons.has(weaponId)) { this.furiousShootFirstTriggeredWeapons.add(weaponId) isRemoveCD = true } this.forceChangeWeaponCD(weaponId, removeCDTime) } } let posX = weaponState.config.bullet_distance //y轴间距 let xTime = weaponState.config.bullet_column//间隔 //单次发射数量 let launchCount = weaponProperty.launchCount //连发数量 let burstCount = isRemoveCD ? Math.floor(removeCDTime / xTime) : weaponProperty.burstCount; GEvent.Ins.emit(GEvent.StraightWeaponLaunch, weaponProperty, posX, xTime, launchCount, burstCount) } else if (weaponState.config.flight == SkillType.直线数量 || weaponState.config.flight == SkillType.直线分裂 || weaponState.config.flight == SkillType.直线穿透) { //默认一发子弹加上配置的数量 let isRemoveCD = false let removeCDTime = 0 for (let i = 0; i < weaponProperty.specialSkillInfo.length; i++) { let buffInfo = weaponProperty.specialSkillInfo[i] let arr = buffInfo.split(',') let buffType = Number(arr[0]) if (buffType == SpecialSkillType.removeCD) { //移除cd let rateNum = Number(arr[1]) / 10000//移除cd的概率 removeCDTime = Number(arr[2])//持续时间 isRemoveCD = Math.random() < rateNum if (!this.furiousShootFirstTriggeredWeapons.has(weaponId)) { this.furiousShootFirstTriggeredWeapons.add(weaponId) isRemoveCD = true } this.forceChangeWeaponCD(weaponId, removeCDTime) } } let posX = weaponState.config.bullet_distance //y轴间距 let xTime = weaponState.config.bullet_column//间隔 //单次发射数量 let launchCount = weaponProperty.launchCount //连发数量 let burstCount = isRemoveCD ? Math.floor(removeCDTime / xTime) : weaponProperty.burstCount; if(weaponState.config.flight == SkillType.直线数量){ GEvent.Ins.emit(GEvent.StraightWeaponShootNum, weaponProperty, burstCount, xTime, launchCount, posX) } else if(weaponState.config.flight == SkillType.直线分裂){ GEvent.Ins.emit(GEvent.StraightWeaponSplit, weaponProperty, burstCount, xTime, launchCount, posX) } else if(weaponState.config.flight == SkillType.直线穿透){ GEvent.Ins.emit(GEvent.StraightWeaponPierce, weaponProperty, burstCount, xTime, launchCount, posX) } }else if (weaponState.config.flight == SkillType.抛物线碰撞) { let xTime = weaponState.config.bullet_column//间隔 let launchCount = weaponProperty.launchCount GEvent.Ins.emit(GEvent.ParabolaCollide, weaponProperty, xTime, launchCount) } else if (weaponState.config.flight == SkillType.抛物线没有碰撞) { let xTime = weaponState.config.bullet_column//间隔 let launchCount = weaponProperty.launchCount GEvent.Ins.emit(GEvent.ParabolaNoCollide, weaponProperty, xTime, launchCount) } else if (weaponState.config.flight == SkillType.单点激光) { //连发数量 let burstCount = weaponProperty.burstCount //单次发射数量 let launchCount = weaponProperty.launchCount GEvent.Ins.emit(GEvent.SinglePointLaser, weaponProperty, burstCount, launchCount) } else if (weaponState.config.flight == SkillType.直线目标持续伤害) { let posY = weaponState.config.bullet_distance //y轴间距 let xTime = weaponState.config.bullet_column//间隔 //单次发射数量 let launchCount = weaponProperty.launchCount GEvent.Ins.emit(GEvent.StraightTargetDamage, weaponProperty, launchCount, xTime, posY, 1) }else if (weaponState.config.flight == SkillType.无弹道单体) { //雷电电击攻击单体 let posX = weaponState.config.bullet_distance //y轴间距 let xTime = weaponState.config.bullet_column//间隔 //单次发射数量 let launchCount = weaponProperty.launchCount //连发数量 let burstCount = weaponProperty.burstCount; GEvent.Ins.emit(GEvent.LightningElectricity, weaponProperty, posX, xTime, launchCount, burstCount) } } /** * 实例化单个武器 * @param weaponId 武器ID * @param volume 武器缩放比例 * @param addPos 武器位置偏移 * @param index 第几个位置 */ async instantiateSingleWeapon(weaponId: number, volume: number, addPos?: Vec3, index?: number, launchNodeSnap?: Node): Promise { const curMap = gg.game.CurentBattle?.curMap; if (!curMap) { console.log('curMap 不存在') return null }; const add = addPos ?? v3(0, 0, 0); let worldPos: Vec3; // 优先使用外部已捕获的发射点,避免重复查 carrier/idx if (launchNodeSnap && isValid(launchNodeSnap)) { worldPos = launchNodeSnap.worldPosition.clone().add(add); } else { const carriers = gg.game.CurentBattle?.curMap.getTetriWeaponCarrier(weaponId) ?? []; console.log('launchNodeSnap 不存在',carriers.length) if (carriers.length > 0) { const ci = ((index ?? 0) % carriers.length + carriers.length) % carriers.length; const launchNode = carriers[ci].getWeaponLaunchNode(); worldPos = launchNode.worldPosition.clone().add(add); } else { console.log('carriers 不存在', carriers.length) TetriStackDiagnostics.onLaunchOriginFallback(weaponId, carriers.length); worldPos = v3(0, 0, 0) // const launch = gg.game.CurentBattle.PlayerController.playerNode.getChildByName('weaponLaunchNode'); // if (!launch) { // console.log('weaponLaunchNode 不存在'); // return null; // } // worldPos = launch.worldPosition.clone().add(add); } } let weaponNode = await gg.res.getNodeAsync(`prefab/武器/`, `weapon${weaponId}`, GBundle.BattleGameWeapon); if (!weaponNode || !weaponNode.isValid) return null; // 节点池复用:可能残留 tween/物理速度/透明度/active,导致“从屏幕外飞入”等异常 // 注意:不要递归停止子节点 tween(很多武器预制体内部用子节点 tween 做表现/淡入) Tween.stopAllByTarget(weaponNode); weaponNode.active = true; weaponNode.opacity = 255; const rb2d = weaponNode.getComponent(RigidBody2D); if (rb2d) { rb2d.linearVelocity = v2(0, 0); rb2d.angularVelocity = 0; rb2d.fixedRotation = true; rb2d.type = ERigidBody2DType.Kinematic; } weaponNode.setParent(this.node, true); weaponNode.scale = v3(volume, volume, 1); weaponNode.worldPosition = worldPos; if (this.node?.isValid) { gg.game.CurentBattle?.setLayerMask(weaponNode, this.node.layer); } return weaponNode; } /** * 多块落稳且带同武器时多个发射点:从第 2 个起每帧创建一个,全部创建完成后 resolve 所有武器节点。 * 武器挂在 this.node 下;仅 0/1 个发射点时与 {@link instantiateSingleWeapon} 等价(立即完成)。 */ instantiateWeaponsFromTetriCarriersStaggered(weaponId: number, volume: number, addPos?: Vec3): Promise { const curMap = gg.game.CurentBattle?.curMap; if (!curMap) { console.log('curMap 不存在'); return Promise.resolve([]); } const carriers = gg.game.CurentBattle?.curMap.getTetriWeaponCarrier(weaponId) ?? []; if (carriers.length <= 1) { return this.instantiateSingleWeapon(weaponId, volume, addPos, 0).then((one) => (one ? [one] : [])); } return new Promise((resolve) => { const out: Node[] = []; void (async () => { const first = await this.instantiateSingleWeapon(weaponId, volume, addPos, 0); if (first) { out.push(first); } let i = 1; const tick = async () => { if (i >= carriers.length) { this.unschedule(tick); resolve(out); return; } const n = await this.instantiateSingleWeapon(weaponId, volume, addPos, i); if (n) { out.push(n); } i++; }; this.schedule(tick); })(); }); } /**直线弹幕/窜天猴类武器分裂为3个 */ splitBullet( weaponId: number, originPos: Vec3, splitCount: number = 3, stayTime: number = 0, damageRate: number = 0, damageRadius: number = 0, tetriLevel: number = 1, ) { const weaponState = this.weaponStates.get(weaponId); if (!weaponState) return; let weaponData = weaponState.config let weaponProperty = BattleDataManager.getWeaponAddProperty(weaponId, undefined, tetriLevel) if (weaponId == WeaponType.FeiJian || weaponId == WeaponType.FaZhen || weaponId == WeaponType.LiSanDaoDan) { let targetPos = v3(0, 0, 0) // console.log('分裂子弹分裂 splitBullet ++++',splitCount) // splitBullet 通常在物理碰撞回调栈内触发;在该栈内 setParent/active 可能导致 RigidBody2D m_world=null。 // 处理方式:把“创建节点 + setParent + 启用物理组件”整体延后一帧执行。 const spawnWp = originPos.clone(); this.scheduleOnce(() => { void (async () => { for (let i = 0; i < splitCount; i++) { const weaponNode = await gg.res.getNodeAsync(`prefab/武器/`, `weapon${weaponId}`, GBundle.BattleGameWeapon); if (!weaponNode || !weaponNode.isValid) continue; weaponNode.active = true; weaponNode.opacity = 255; // 先禁用物理组件,等节点稳定后再启用 const rb2d = weaponNode.getComponent('RigidBody2D' as any) as any; if (rb2d) rb2d.enabled = false; const col2d = weaponNode.getComponent('Collider2D' as any) as any; if (col2d) col2d.enabled = false; weaponNode.setParent(this.node, true); weaponNode.worldPosition = spawnWp.clone().add(v3(0, 35, 0)); weaponNode.scale = v3(weaponProperty.volume, weaponProperty.volume, 1); const skillComp = weaponNode.getComponent(Skill); skillComp?.setData(weaponData, targetPos, true, false, i, 0, 0); this.scheduleOnce(() => { if (!weaponNode || !weaponNode.isValid) return; const rb2d2 = weaponNode.getComponent('RigidBody2D' as any) as any; if (rb2d2) rb2d2.enabled = true; const col2d2 = weaponNode.getComponent('Collider2D' as any) as any; if (col2d2) col2d2.enabled = true; }, 0); } })(); }, 0); } else if (weaponId == WeaponType.LeiShenZhiChui) { const spawnWp = originPos.clone(); const wpProp = BattleDataManager.getWeaponAddProperty(weaponId, undefined, tetriLevel); this.scheduleOnce(() => { void (async () => { const mapRoot = gg.game.CurentBattle?.curMap?.node; if (!mapRoot?.isValid) return; for (let i = 0; i < splitCount; i++) { const ball = await gg.res.getNodeAsync(`prefab/爆炸/`, '雷电球', GBundle.BattleGameWeapon); if (!ball?.isValid) continue; ball.active = true; ball.opacity = 255; ball.setParent(mapRoot, true); ball.worldPosition = spawnWp.clone(); const vol = wpProp.volume > 0 ? wpProp.volume : 1; ball.scale = v3(vol, vol, 1); let thunder = ball.getComponent(ThunderboltSchedule); if (!thunder) thunder = ball.addComponent(ThunderboltSchedule); const speed = Math.max(1, wpProp.speed > 0 ? wpProp.speed : 400); const radius = damageRadius > 0 ? damageRadius : Math.max(1, wpProp.explodeRadius || 80); const interval = Math.max(0.05, wpProp.damageInterval > 0 ? wpProp.damageInterval : 0.2); const continueT = stayTime > 0 ? stayTime : Math.max(interval, wpProp.weaponContinueTime > 0 ? wpProp.weaponContinueTime : 2); const atkScale = damageRate > 0 ? damageRate / 10000 : 1; thunder.resetThunderboltSchedule( spawnWp.clone(), radius, atkScale, weaponId, interval, Math.max(1, Math.floor(continueT / interval)), continueT, tetriLevel, i, speed, ); } })(); }, 0); } } /** * 获得攻击点位置(抛物线) * @param weaponData * @param index 第几个位置 * @returns */ getAtkPos(weaponData: ITableWeapon2, index: number = 0) { if (weaponData.flight == SkillType.直线弹幕) { return v3(0, 0, 0) } else if (weaponData.flight == SkillType.抛物线碰撞 || weaponData.flight == SkillType.抛物线没有碰撞) { let targetPos = gg.game.CurentBattle.MonsterSpawner.getMonsterParabolaPos(Math.max(1, index), this.node) return targetPos } } /**强制改变武器冷却时间 */ forceChangeWeaponCD(weaponId: number, cd: number) { const weaponState = this.weaponStates.get(weaponId); if (!weaponState) return; weaponState.remainingCD = cd weaponState.cd = cd } /** * 开始武器冷却 * @param weaponId 武器ID */ private startCooldown(weaponId: number): void { const weaponState = this.weaponStates.get(weaponId); if (!weaponState) return; // 设置为冷却状态 weaponState.isReady = false; let weaponProperty = BattleDataManager.getWeaponAddProperty(weaponId) const cdMul = BattlePerformance.weaponCdMul(); weaponState.remainingCD = weaponProperty.cd * cdMul; weaponState.cd = weaponProperty.cd * cdMul; // 清理之前的定时器(如果有) //this.clearWeaponTimer(weaponId); // // 启动新的冷却定时器 // const timerId = setInterval(() => { // // BattleManager.Instance.audio_timeStampADD += this.dt*1000 // // BattleManager.Instance._beAtkTimeStampTimeAdd += this.dt*1000 // // BattleManager.Instance._hurtScoreTimeStampTimeAdd += this.dt*1000 // // BattleManager.Instance._hurtColorTimeStamp += this.dt*1000 // this.updateCooldown(weaponId, weaponProperty.cd); // }, this.dt * 1000); // 每0.1秒更新一次 // this.timers.set(weaponId, timerId); // weaponState.timer = timerId; // console.log(`武器 ${weaponId} 开始冷却,CD: ${weaponState.config.cd}秒`); } protected update(dt: number): void { if (!gg.game.isBattleContextActive()) return; if (gg.game.IsPlayingGuideStory) { //开启攻击 const curUseArr = gg.game.CurentBattle.CurUseWeaponArr; for (let i = 0; i < curUseArr.length; i++) { const weaponId = curUseArr[i].weaponid; const weaponState = this.weaponStates.get(weaponId); if (!weaponState) continue; weaponState.remainingCD -= dt * gg.game.CurentBattle.TimeScale; if (weaponState.remainingCD <= 0) { // 冷却完成 this.finishCooldown(weaponId); } else { } } return } if (!gg.game.CurentBattle.canUpdateFrame()) { return } const curUseArr = gg.game.CurentBattle.CurUseWeaponArr; for (let i = 0; i < curUseArr.length; i++) { const weaponId = curUseArr[i].weaponid; const weaponState = this.weaponStates.get(weaponId); if (!weaponState) continue; weaponState.remainingCD -= dt * gg.game.CurentBattle.TimeScale; if (weaponState.remainingCD <= 0) { // 冷却完成 this.finishCooldown(weaponId); } else { } } } /** * 完成冷却 * @param weaponId 武器ID */ private finishCooldown(weaponId: number): void { //没有怪物不在发射武器 if (gg.game.CurentBattle.MonsterSpawner.node.children.length == 0) { //console.log('没有怪物不在发射武器') return }; const weaponState = this.weaponStates.get(weaponId); if (!weaponState) return; weaponState.isReady = true; weaponState.remainingCD = 0; // 触发冷却完成事件 this.onWeaponCooldownComplete(weaponId); } /** * 获取可用武器列表 * @returns 可用武器ID数组 */ public getAvailableWeapons(): number[] { return this.availableWeapons.filter(weaponId => { const state = this.weaponStates.get(weaponId); return state && state.isReady; }); } /** * 获取武器状态 * @param weaponId 武器ID * @returns 武器状态 */ public getWeaponState(weaponId: number): WeaponState | undefined { return this.weaponStates.get(weaponId); } // === 以下方法需要根据实际游戏逻辑实现 === // /** // * 播放武器特效 // * @param weaponId 武器ID // */ // private playWeaponEffect(weaponId: number): void { // // 实现武器特效播放逻辑 // // 例如:播放动画、音效等 // } /** * 更新冷却时间UI显示 * @param weaponId 武器ID * @param remainingTime 剩余时间 */ private updateCooldownUI(weaponId: number, cd: number, remainingTime: number): void { // 更新UI显示,比如技能按钮上的倒计时 gg.game.CurentBattle.DamageStatistics.freshWeaponCD(weaponId, cd, remainingTime) } /** * 武器冷却完成回调 * @param weaponId 武器ID */ private onWeaponCooldownComplete(weaponId: number): void { //如果没有怪物不需要发射武器 if (gg.game.CurentBattle.MonsterSpawner.node.children.length == 0) { return }; const minMs = BattlePerformance.weaponFireMinIntervalMs(); // beforeTimes:冷却窗口内返回 true(应推迟发射);勿取反 if (minMs > 0 && MTools.beforeTimes(minMs, `weapon_fire_${weaponId}`)) { const weaponState = this.weaponStates.get(weaponId); if (weaponState) { weaponState.remainingCD = Math.max(weaponState.remainingCD, minMs / 1000); weaponState.isReady = false; } return; } this.useWeaponSkill(weaponId) } /**刷新无人机和激光武器发射塔 */ public refreshDroneOrLaserLaunch() { this.availableWeapons.forEach(weaponId => { const weaponState = this.weaponStates.get(weaponId); if (weaponState && weaponState.config.flight == SkillType.单点激光) { let weaponProperty = BattleDataManager.getWeaponAddProperty(weaponId) //连发数量(激光塔数量) let burstCount = weaponProperty.burstCount let curCount = this.specialWeaponLaunchCount['weapon' + weaponId] || 0 if (curCount < burstCount) { this.specialWeaponLaunchCount['weapon' + weaponId] = burstCount } } }); } }