feat(技能): 将技能卡释放逻辑移至独立组件并添加UI显示
- 新增 MissSkillsComp 组件,用于管理场景中释放的技能卡 - 将技能卡释放监听从 MissionHeroComp 移至 MissSkillsComp - 新增 SkillBoxComp 组件,负责单个技能卡的表现和触发逻辑 - 在 role_controller.prefab 中添加 miss_skill_node 节点引用 - 技能卡现在会在场景中显示图标和剩余回合信息 - 支持即时技能和持续多回合技能的不同触发机制
This commit is contained in:
@@ -12878,6 +12878,9 @@
|
|||||||
"hero_num_node": {
|
"hero_num_node": {
|
||||||
"__id__": 65
|
"__id__": 65
|
||||||
},
|
},
|
||||||
|
"miss_skill_node": {
|
||||||
|
"__id__": 598
|
||||||
|
},
|
||||||
"_id": ""
|
"_id": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { mLogger } from "../common/Logger";
|
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 { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
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 { oops } from "db://oops-framework/core/Oops";
|
||||||
import { GameEvent } from "../common/config/GameEvent";
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
@@ -18,14 +18,35 @@ export class MissSkillsComp extends CCComp {
|
|||||||
private skill_box: Prefab = null;
|
private skill_box: Prefab = null;
|
||||||
|
|
||||||
onLoad() {
|
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() {
|
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) 删除组件是触发组件处理自定义释放逻辑 */
|
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||||
reset() {
|
reset() {
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ export class MissionCardComp extends CCComp {
|
|||||||
hero_info_prefab:Prefab=null! //场上英雄信息面板Prefab
|
hero_info_prefab:Prefab=null! //场上英雄信息面板Prefab
|
||||||
@property(Node)
|
@property(Node)
|
||||||
hero_num_node:Node=null!
|
hero_num_node:Node=null!
|
||||||
|
@property(Node)
|
||||||
|
miss_skill_node:Node=null!
|
||||||
|
|
||||||
/** 预留图集缓存(后续接入按钮/卡面图标时复用) */
|
/** 预留图集缓存(后续接入按钮/卡面图标时复用) */
|
||||||
private uiconsAtlas: SpriteAtlas | null = null;
|
private uiconsAtlas: SpriteAtlas | null = null;
|
||||||
|
|||||||
@@ -49,34 +49,16 @@ export class MissionHeroCompComp extends CCComp {
|
|||||||
this.on(GameEvent.MissionEnd,this.clear_heros,this)
|
this.on(GameEvent.MissionEnd,this.clear_heros,this)
|
||||||
/** 全局消息监听 */
|
/** 全局消息监听 */
|
||||||
oops.message.on(GameEvent.CallHero,this.call_hero,this)
|
oops.message.on(GameEvent.CallHero,this.call_hero,this)
|
||||||
oops.message.on(GameEvent.UseSkillCard,this.onUseSkillCard,this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(){
|
onDestroy(){
|
||||||
/** 清理监听,避免节点销毁后仍响应消息 */
|
/** 清理监听,避免节点销毁后仍响应消息 */
|
||||||
oops.message.off(GameEvent.CallHero,this.call_hero,this)
|
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.FightReady,this.fight_ready,this)
|
||||||
oops.message.off(GameEvent.Zhaohuan,this.zhao_huan,this)
|
oops.message.off(GameEvent.Zhaohuan,this.zhao_huan,this)
|
||||||
oops.message.off(GameEvent.MissionEnd,this.clear_heros,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() {
|
start() {
|
||||||
// this.test_call()
|
// this.test_call()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { mLogger } from "../common/Logger";
|
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 { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
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 { oops } from "db://oops-framework/core/Oops";
|
||||||
import { GameEvent } from "../common/config/GameEvent";
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 视图层对象 */
|
/** 视图层对象 */
|
||||||
@ccclass('SkillBoxComp')
|
@ccclass('SkillBoxComp')
|
||||||
@ecs.register('SkillBoxComp', false)
|
@ecs.register('SkillBoxComp', false)
|
||||||
@@ -16,16 +16,149 @@ export class SkillBoxComp extends CCComp {
|
|||||||
private debugMode: boolean = true;
|
private debugMode: boolean = true;
|
||||||
@property({type: Node})
|
@property({type: Node})
|
||||||
private icon_node:Node= null;
|
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() {
|
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) 删除组件是触发组件处理自定义释放逻辑 */
|
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||||
reset() {
|
reset() {
|
||||||
|
|||||||
Reference in New Issue
Block a user