Files
pixelheros/assets/script/game/map/SkillBoxComp.ts
walkpan d3126df601 refactor(game): 将技能触发逻辑从回合制改为全局次数制
移除技能卡的持续回合数(d_rds)和当前回合计数(current_round),改为仅使用全局触发次数(current_trigger_times)控制技能生命周期
更新UI显示从剩余回合改为剩余触发次数,技能在达到总触发次数后立即销毁而非等待回合结束
2026-04-07 09:47:59 +08:00

179 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { mLogger } from "../common/Logger";
import { _decorator, Node, Prefab, Sprite, Label, Vec3, resources, SpriteAtlas } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { CardPoolList } from "../common/config/CardSet";
import { SkillSet } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp";
const { ccclass, property } = _decorator;
/** 视图层对象 */
@ccclass('SkillBoxComp')
@ecs.register('SkillBoxComp', false)
export class SkillBoxComp extends CCComp {
private debugMode: boolean = true;
@property({type: Node})
private icon_node:Node= null;
@property(Label)
private info_label: Label = null;
private s_uuid: number = 0;
private card_lv: number = 1;
private is_instant: boolean = true;
private trigger_times: number = 1;
private trigger_interval: number = 0;
private current_trigger_times: number = 0;
private timer: number = 0;
private in_combat: boolean = false;
private initialized: boolean = false;
onLoad() {
oops.message.on(GameEvent.FightStart, this.onFightStart, this);
oops.message.on(GameEvent.MissionEnd, this.onMissionEnd, this);
this.node.on(GameEvent.NewWave, this.onNewWave, this);
oops.message.on(GameEvent.NewWave, this.onNewWaveGlobal, this);
}
onDestroy() {
oops.message.off(GameEvent.FightStart, this.onFightStart, this);
oops.message.off(GameEvent.MissionEnd, this.onMissionEnd, this);
this.node.off(GameEvent.NewWave, this.onNewWave, this);
oops.message.off(GameEvent.NewWave, this.onNewWaveGlobal, this);
}
init(uuid: number, card_lv: number) {
// this.node.parent=smc.map.MapView.scene.entityLayer!.node!
this.s_uuid = uuid;
this.card_lv = card_lv;
const config = CardPoolList.find(c => c.uuid === uuid);
if (config) {
this.is_instant = config.is_inst ?? true;
this.trigger_times = config.t_times ?? 1;
this.trigger_interval = config.t_inv ?? 0;
}
this.current_trigger_times = 0;
this.timer = 0;
this.initialized = true;
this.updateUI();
if (this.is_instant) {
// 即时起效:立即触发
this.triggerSkill();
this.current_trigger_times++;
if (this.current_trigger_times >= this.trigger_times) {
this.scheduleOnce(() => {
this.node.destroy();
}, 1.0); // 稍微延迟销毁,保证表现
}
}
}
updateUI() {
if (this.icon_node) {
const iconId = SkillSet[this.s_uuid]?.icon || `${this.s_uuid}`;
resources.load("gui/uicons", SpriteAtlas, (err, atlas) => {
if (err || !atlas) return;
const frame = atlas.getSpriteFrame(iconId);
if (frame && this.icon_node && this.icon_node.isValid) {
const sprite = this.icon_node.getComponent(Sprite) || this.icon_node.addComponent(Sprite);
sprite.spriteFrame = frame;
}
});
}
if (this.info_label) {
if (!this.is_instant) {
const remain = Math.max(0, this.trigger_times - this.current_trigger_times);
this.info_label.string = `${remain}`;
} else {
this.info_label.string = "";
}
}
}
private onFightStart() {
if (!this.initialized) return;
this.in_combat = true;
if (!this.is_instant) {
// 战斗开始时计时归0重新计时
this.timer = 0;
}
}
private onNewWave() {
this.handleNewWave();
}
private onNewWaveGlobal() {
this.handleNewWave();
}
private handleNewWave() {
if (!this.initialized) return;
this.in_combat = false;
if (!this.is_instant) {
// 每回合不再重置次数,由全局次数进行控制
if (this.current_trigger_times >= this.trigger_times) {
this.node.destroy();
}
}
}
private onMissionEnd() {
this.node.destroy();
}
update(dt: number) {
if (!this.initialized || !this.in_combat || this.is_instant) return;
if (!smc.mission.play || smc.mission.pause) return;
if (this.current_trigger_times < this.trigger_times) {
this.timer += dt;
if (this.timer >= this.trigger_interval) {
this.timer = 0; // 触发后重新计时
this.triggerSkill();
this.current_trigger_times++;
this.updateUI(); // 触发后更新界面显示的剩余次数
// 如果在战斗中就达到触发次数上限,则可以在此回合战斗结束或者立即销毁
if (this.current_trigger_times >= this.trigger_times) {
// 可以选择直接销毁,不等到下一回合
this.scheduleOnce(() => {
if (this.node.isValid) this.node.destroy();
}, 0.5);
}
}
}
}
private triggerSkill() {
// 获取自身在父节点下的局部坐标
// UI 的局部坐标在 2D 相机中和实际的游戏逻辑坐标存在偏移关系,
// 可以结合自身局部坐标做一次偏移,此处直接读取自身的 localPosition 加上父节点的偏移
let targetPos = new Vec3();
const localPos = this.node.position;
const parentPos = this.node.parent ? this.node.parent.position : new Vec3(0, 0, 0);
targetPos.set(parentPos.x + localPos.x, parentPos.y + localPos.y, 0);
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
s_uuid: this.s_uuid,
isCardSkill: true,
card_lv: this.card_lv,
targetPos: targetPos
});
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.node.destroy();
}
}