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 duration_rounds: number = 1; private current_round: 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.duration_rounds = config.d_rds ?? 1; } this.current_round = 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) { this.info_label.string = `${this.duration_rounds - this.current_round}回`; } else { this.info_label.string = ""; } } } private onFightStart() { if (!this.initialized) return; this.in_combat = true; if (!this.is_instant) { // 战斗开始时,计时归0,重新计时 this.timer = 0; // 如果这个技能每回合都可以触发 t_times 次,则在每回合开始时重置当前回合触发次数 this.current_trigger_times = 0; } } private onNewWave() { this.handleNewWave(); } private onNewWaveGlobal() { this.handleNewWave(); } private handleNewWave() { if (!this.initialized) return; this.in_combat = false; if (!this.is_instant) { this.current_round++; this.updateUI(); if (this.current_round >= this.duration_rounds) { 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++; } } } 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(); } }