From ef0798264537a570effbef2f529bbdcc0f861839 Mon Sep 17 00:00:00 2001 From: walkpan Date: Sun, 5 Apr 2026 22:09:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8A=80=E8=83=BD):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E6=8A=80=E8=83=BD=E6=9C=BA=E5=88=B6=E5=B9=B6?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=AD=BB=E4=BA=A1=E7=89=B9=E6=95=88=E9=A2=9C?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 GameEvent 枚举中添加 TriggerSkill 事件用于技能触发 - 为 Hero 和 Monster 实体添加召唤入场时的 call 技能触发 - 在 HeroAtkSystem 中实现死亡时的 dead 技能触发 - 扩展 SCastSystem 支持强制触发技能(忽略CD和动画前摇) - 将死亡技能特效颜色从灰色调整为白色以提升视觉效果 --- assets/resources/game/skill/ready/dead.prefab | 6 +- assets/script/game/common/config/GameEvent.ts | 1 + assets/script/game/hero/Hero.ts | 9 +++ assets/script/game/hero/HeroAtkSystem.ts | 17 ++++- assets/script/game/hero/Mon.ts | 10 +++ assets/script/game/hero/SCastSystem.ts | 65 +++++++++++++++++++ 6 files changed, 104 insertions(+), 4 deletions(-) diff --git a/assets/resources/game/skill/ready/dead.prefab b/assets/resources/game/skill/ready/dead.prefab index 77a01535..dfaad0f9 100644 --- a/assets/resources/game/skill/ready/dead.prefab +++ b/assets/resources/game/skill/ready/dead.prefab @@ -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": { diff --git a/assets/script/game/common/config/GameEvent.ts b/assets/script/game/common/config/GameEvent.ts index a38305fa..031ffd73 100644 --- a/assets/script/game/common/config/GameEvent.ts +++ b/assets/script/game/common/config/GameEvent.ts @@ -73,4 +73,5 @@ export enum GameEvent { UpdateMissionGet = "UpdateMissionGet", GlobalAttrChange = "GlobalAttrChange", CoinAdd = "CoinAdd", + TriggerSkill = "TriggerSkill", // 瞬间触发施法事件 } \ No newline at end of file diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts index 5daaf664..435e8850 100644 --- a/assets/script/game/hero/Hero.ts +++ b/assets/script/game/hero/Hero.ts @@ -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)); diff --git a/assets/script/game/hero/HeroAtkSystem.ts b/assets/script/game/hero/HeroAtkSystem.ts index b5cfe0b0..0f86a629 100644 --- a/assets/script/game/hero/HeroAtkSystem.ts +++ b/assets/script/game/hero/HeroAtkSystem.ts @@ -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); diff --git a/assets/script/game/hero/Mon.ts b/assets/script/game/hero/Mon.ts index fa9f5d6d..f8d1098f 100644 --- a/assets/script/game/hero/Mon.ts +++ b/assets/script/game/hero/Mon.ts @@ -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)); diff --git a/assets/script/game/hero/SCastSystem.ts b/assets/script/game/hero/SCastSystem.ts index 100e0115..9b94722e 100644 --- a/assets/script/game/hero/SCastSystem.ts +++ b/assets/script/game/hero/SCastSystem.ts @@ -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、目标可达、目标类型匹配)。