feat(技能): 新增触发技能机制并调整死亡特效颜色
- 在 GameEvent 枚举中添加 TriggerSkill 事件用于技能触发 - 为 Hero 和 Monster 实体添加召唤入场时的 call 技能触发 - 在 HeroAtkSystem 中实现死亡时的 dead 技能触发 - 扩展 SCastSystem 支持强制触发技能(忽略CD和动画前摇) - 将死亡技能特效颜色从灰色调整为白色以提升视觉效果
This commit is contained in:
@@ -158,9 +158,9 @@
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 173,
|
||||
"g": 170,
|
||||
"b": 170,
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
|
||||
@@ -73,4 +73,5 @@ export enum GameEvent {
|
||||
UpdateMissionGet = "UpdateMissionGet",
|
||||
GlobalAttrChange = "GlobalAttrChange",
|
||||
CoinAdd = "CoinAdd",
|
||||
TriggerSkill = "TriggerSkill", // 瞬间触发施法事件
|
||||
}
|
||||
@@ -143,6 +143,15 @@ export class Hero extends ecs.Entity {
|
||||
move.moving = false;
|
||||
hv.as.idle();
|
||||
|
||||
// 触发 call 技能
|
||||
if (hero.call) {
|
||||
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
||||
s_uuid: hero.call,
|
||||
heroAttrs: model,
|
||||
heroView: hv
|
||||
});
|
||||
}
|
||||
|
||||
// 依据下落距离自适应入场时长,保证手感稳定
|
||||
const dropDistance = Math.abs(pos.y - dropToY);
|
||||
const dropDuration = Math.max(0.18, Math.min(0.38, dropDistance / 1200));
|
||||
|
||||
@@ -7,7 +7,9 @@ import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { DamageQueueComp, DamageEvent } from "./DamageQueueComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
|
||||
import { mLogger } from "../common/Logger";
|
||||
|
||||
@@ -250,6 +252,19 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
if (!TAttrsComp || TAttrsComp.is_dead) return;
|
||||
|
||||
TAttrsComp.is_dead = true;
|
||||
|
||||
// 触发死亡技能
|
||||
const heroInfo = HeroInfo[TAttrsComp.hero_uuid];
|
||||
if (heroInfo && heroInfo.dead) {
|
||||
const view = entity.get(HeroViewComp);
|
||||
if (view) {
|
||||
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
||||
s_uuid: heroInfo.dead,
|
||||
heroAttrs: TAttrsComp,
|
||||
heroView: view
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 触发死亡事件
|
||||
this.onDeath(entity);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { HeroInfo } from "../common/config/heroSet";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { MoveComp } from "./MoveComp";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
/** 怪物实体:负责怪物对象池复用、属性初始化、入场动画与回收 */
|
||||
@ecs.register(`Monster`)
|
||||
export class Monster extends ecs.Entity {
|
||||
@@ -193,6 +194,15 @@ export class Monster extends ecs.Entity {
|
||||
move.baseY = dropToY;
|
||||
move.moving = false;
|
||||
|
||||
// 触发 call 技能
|
||||
if (hero.call) {
|
||||
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
||||
s_uuid: hero.call,
|
||||
heroAttrs: model,
|
||||
heroView: view
|
||||
});
|
||||
}
|
||||
|
||||
// 依据下落距离自适应入场时长,确保观感一致
|
||||
const dropDistance = Math.abs(pos.y - dropToY);
|
||||
const dropDuration = Math.max(0.18, Math.min(0.38, dropDistance / 1200));
|
||||
|
||||
@@ -8,6 +8,8 @@ import { smc } from "../common/SingletonModuleComp";
|
||||
import { HType } from "../common/config/heroSet";
|
||||
import { Attrs } from "../common/config/HeroAttrs";
|
||||
import { BoxSet, FightSet } from "../common/config/GameSet";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
|
||||
/**
|
||||
* ==================== 自动施法系统 ====================
|
||||
@@ -23,7 +25,20 @@ import { BoxSet, FightSet } from "../common/config/GameSet";
|
||||
*/
|
||||
@ecs.register('SCastSystem')
|
||||
export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
static instance: SCastSystem | null = null;
|
||||
debugMode: boolean = false; // 是否启用调试模式
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
SCastSystem.instance = this;
|
||||
// 监听触发技能事件
|
||||
oops.message.on(GameEvent.TriggerSkill, this.onTriggerSkill, this);
|
||||
}
|
||||
|
||||
private onTriggerSkill(event: string, args: { s_uuid: number, heroAttrs: HeroAttrsComp, heroView: HeroViewComp }) {
|
||||
if (!args || !args.s_uuid || !args.heroAttrs || !args.heroView) return;
|
||||
this.forceCastTriggerSkill(args.s_uuid, args.heroAttrs, args.heroView);
|
||||
}
|
||||
/** 空施法计划:用于“当前无可施法技能”时的统一返回 */
|
||||
private readonly emptyCastPlan = { skillId: 0, skillLv: 1, isFriendly: false, targetPos: null as Vec3 | null, targetEids: [] as number[] };
|
||||
/** 近战英雄默认施法射程 */
|
||||
@@ -71,6 +86,56 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
this.castSkill(castPlan, heroAttrs, heroView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制执行触发技能(召唤/死亡触发)
|
||||
* 忽略CD、状态、动画前摇,直接生效
|
||||
*/
|
||||
public forceCastTriggerSkill(s_uuid: number, heroAttrs: HeroAttrsComp, heroView: HeroViewComp) {
|
||||
if (!smc.mission.in_fight) return;
|
||||
const config = SkillSet[s_uuid];
|
||||
if (!config) return;
|
||||
|
||||
const skillLv = heroAttrs.getSkillLevel(s_uuid) || 1;
|
||||
|
||||
let isFriendly = false;
|
||||
let targetPos: Vec3 | null = null;
|
||||
let targetEids: number[] = [];
|
||||
|
||||
const selfEid = heroView.ent?.eid;
|
||||
const type = heroAttrs.type as HType;
|
||||
const maxRange = this.resolveMaxCastRange(heroAttrs, type);
|
||||
|
||||
if (this.isSelfSkill(config.TGroup)) {
|
||||
isFriendly = true;
|
||||
if (typeof selfEid === "number") targetEids = [selfEid];
|
||||
} else if (this.isFriendlySkill(config.TGroup)) {
|
||||
isFriendly = true;
|
||||
const includeSelf = config.TGroup === TGroup.Ally;
|
||||
targetEids = this.collectFriendlyTargetEids(heroAttrs.fac, selfEid, includeSelf);
|
||||
} else {
|
||||
const target = this.findNearestEnemyInRange(heroAttrs, heroView, maxRange);
|
||||
if (target && target.node) {
|
||||
targetPos = this.resolveEnemyCastTargetPos(config, heroAttrs, heroView, target, maxRange);
|
||||
}
|
||||
}
|
||||
|
||||
const sUp = SkillUpList[s_uuid] ? SkillUpList[s_uuid] : SkillUpList[1001];
|
||||
const cNum = Math.min(2, Math.max(0, Math.floor(sUp.num ?? 0)));
|
||||
const castTimes = 1 + cNum;
|
||||
|
||||
for (let i = 0; i < castTimes; i++) {
|
||||
if (!heroView.node || !heroView.node.isValid) return;
|
||||
if (isFriendly) {
|
||||
const friendlyTargets = this.resolveFriendlyTargets(targetEids, heroAttrs.fac);
|
||||
if (friendlyTargets.length === 0) continue;
|
||||
this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null);
|
||||
} else {
|
||||
const enemyTargetPos = this.resolveRepeatCastTargetPos(targetPos, i);
|
||||
this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择当前应释放的技能。
|
||||
* 选择顺序:技能候选列表顺序 + 条件过滤(CD、目标可达、目标类型匹配)。
|
||||
|
||||
Reference in New Issue
Block a user