- 新增 RemoveSkillBox 事件用于技能盒销毁时通知 - 在 SkillBoxComp 销毁时触发 RemoveSkillBox 事件 - 为 MissSkillsComp 实现技能盒槽位管理系统 - 技能盒添加时会自动分配到可用槽位 - 技能盒销毁后会自动重新排列剩余技能盒 - 调整技能盒预制体尺寸和位置以优化显示效果
180 lines
6.4 KiB
TypeScript
180 lines
6.4 KiB
TypeScript
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);
|
||
oops.message.dispatchEvent(GameEvent.RemoveSkillBox, this.node);
|
||
}
|
||
|
||
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();
|
||
}
|
||
}
|