From fa629d71d94f138607fb195d33cfc51a3cb0637d Mon Sep 17 00:00:00 2001 From: walkpan Date: Mon, 6 Apr 2026 19:18:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8A=80=E8=83=BD):=20=E5=B0=86=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E5=8D=A1=E9=87=8A=E6=94=BE=E9=80=BB=E8=BE=91=E7=A7=BB?= =?UTF-8?q?=E8=87=B3=E7=8B=AC=E7=AB=8B=E7=BB=84=E4=BB=B6=E5=B9=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0UI=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 MissSkillsComp 组件,用于管理场景中释放的技能卡 - 将技能卡释放监听从 MissionHeroComp 移至 MissSkillsComp - 新增 SkillBoxComp 组件,负责单个技能卡的表现和触发逻辑 - 在 role_controller.prefab 中添加 miss_skill_node 节点引用 - 技能卡现在会在场景中显示图标和剩余回合信息 - 支持即时技能和持续多回合技能的不同触发机制 --- assets/resources/gui/role_controller.prefab | 3 + assets/script/game/map/MissSkillsComp.ts | 27 +++- assets/script/game/map/MissionCardComp.ts | 2 + assets/script/game/map/MissionHeroComp.ts | 18 --- assets/script/game/map/SkillBoxComp.ts | 147 +++++++++++++++++++- 5 files changed, 169 insertions(+), 28 deletions(-) diff --git a/assets/resources/gui/role_controller.prefab b/assets/resources/gui/role_controller.prefab index f9c0d70f..bf39bfdb 100644 --- a/assets/resources/gui/role_controller.prefab +++ b/assets/resources/gui/role_controller.prefab @@ -12878,6 +12878,9 @@ "hero_num_node": { "__id__": 65 }, + "miss_skill_node": { + "__id__": 598 + }, "_id": "" }, { diff --git a/assets/script/game/map/MissSkillsComp.ts b/assets/script/game/map/MissSkillsComp.ts index d8eb09af..bfb07ff1 100644 --- a/assets/script/game/map/MissSkillsComp.ts +++ b/assets/script/game/map/MissSkillsComp.ts @@ -1,8 +1,8 @@ import { mLogger } from "../common/Logger"; -import { _decorator, Node, Prefab } from "cc"; +import { _decorator, Node, Prefab, instantiate } 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 { CardType } from "../common/config/CardSet"; +import { SkillBoxComp } from "./SkillBoxComp"; import { oops } from "db://oops-framework/core/Oops"; import { GameEvent } from "../common/config/GameEvent"; const { ccclass, property } = _decorator; @@ -18,14 +18,35 @@ export class MissSkillsComp extends CCComp { private skill_box: Prefab = null; onLoad() { + oops.message.on(GameEvent.UseSkillCard, this.onUseSkillCard, this); + } + onDestroy() { + oops.message.off(GameEvent.UseSkillCard, this.onUseSkillCard, this); + } + + private onUseSkillCard(event: string, args: any) { + const payload = args ?? event; + const uuid = Number(payload?.uuid ?? 0); + const card_lv = Math.max(1, Math.floor(Number(payload?.card_lv ?? 1))); + if (!uuid) return; + this.addSkill(uuid, card_lv); } start() { } - + addSkill(uuid: number, card_lv: number) { + if (!this.skill_box) { + mLogger.error(this.debugMode, "MissSkillsComp", "skill_box prefab not set"); + return; + } + const node = instantiate(this.skill_box); + node.parent = this.node; + const comp = node.getComponent(SkillBoxComp) || node.addComponent(SkillBoxComp); + comp.init(uuid, card_lv); + } /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { diff --git a/assets/script/game/map/MissionCardComp.ts b/assets/script/game/map/MissionCardComp.ts index 344b9a04..f1536b57 100644 --- a/assets/script/game/map/MissionCardComp.ts +++ b/assets/script/game/map/MissionCardComp.ts @@ -55,6 +55,8 @@ export class MissionCardComp extends CCComp { hero_info_prefab:Prefab=null! //场上英雄信息面板Prefab @property(Node) hero_num_node:Node=null! + @property(Node) + miss_skill_node:Node=null! /** 预留图集缓存(后续接入按钮/卡面图标时复用) */ private uiconsAtlas: SpriteAtlas | null = null; diff --git a/assets/script/game/map/MissionHeroComp.ts b/assets/script/game/map/MissionHeroComp.ts index b3db3d93..30392c63 100644 --- a/assets/script/game/map/MissionHeroComp.ts +++ b/assets/script/game/map/MissionHeroComp.ts @@ -49,34 +49,16 @@ export class MissionHeroCompComp extends CCComp { this.on(GameEvent.MissionEnd,this.clear_heros,this) /** 全局消息监听 */ oops.message.on(GameEvent.CallHero,this.call_hero,this) - oops.message.on(GameEvent.UseSkillCard,this.onUseSkillCard,this) } onDestroy(){ /** 清理监听,避免节点销毁后仍响应消息 */ oops.message.off(GameEvent.CallHero,this.call_hero,this) - oops.message.off(GameEvent.UseSkillCard,this.onUseSkillCard,this) oops.message.off(GameEvent.FightReady,this.fight_ready,this) oops.message.off(GameEvent.Zhaohuan,this.zhao_huan,this) oops.message.off(GameEvent.MissionEnd,this.clear_heros,this) } - /** 响应卡牌释放技能 */ - private onUseSkillCard(event: string, args: any) { - const payload = args ?? event; - const uuid = Number(payload?.uuid ?? 0); - const card_lv = Math.max(1, Math.floor(Number(payload?.card_lv ?? 1))); - if (!uuid) return; - - // 分发给 SCastSystem 处理(使用特定的坐标 x=-340, y=30) - oops.message.dispatchEvent(GameEvent.TriggerSkill, { - s_uuid: uuid, - isCardSkill: true, - card_lv: card_lv, - targetPos: v3(-340, 30, 0) - }); - } - start() { // this.test_call() } diff --git a/assets/script/game/map/SkillBoxComp.ts b/assets/script/game/map/SkillBoxComp.ts index 35201e95..79545eef 100644 --- a/assets/script/game/map/SkillBoxComp.ts +++ b/assets/script/game/map/SkillBoxComp.ts @@ -1,14 +1,14 @@ import { mLogger } from "../common/Logger"; -import { _decorator, Node, Prefab } from "cc"; +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 { CardType } from "../common/config/CardSet"; +import { SkillCardList } 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) @@ -16,16 +16,149 @@ 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); } - start() { + 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.s_uuid = uuid; + this.card_lv = card_lv; + const config = SkillCardList[uuid]; + if (config) { + this.is_instant = config.is_instant ?? true; + this.trigger_times = config.trigger_times ?? 1; + this.trigger_interval = config.trigger_interval ?? 0; + this.duration_rounds = config.duration_rounds ?? 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) { + this.timer = this.trigger_interval; // 确保第一次能立即或按间隔触发 + 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() { + // 使用固定的全局坐标 + const targetPos = new Vec3(-340, 30, 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() {