消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

737 lines
30 KiB

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<number, WeaponState> = new Map();
/**特殊武器发射塔数量 */
private specialWeaponLaunchCount = {};
/** 各武器第一次触发狂暴射击(removeCD)时必定生效 */
private furiousShootFirstTriggeredWeapons = new Set<number>();
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<Node | null> {
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<Node[]> {
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
}
}
});
}
}