- 删除SkillEnt.ts及其meta文件,简化技能实体管理 - 将SDataCom重命名为更清晰的DmgDataCom和SDataCom - 重构伤害计算系统,增加命中检测和伤害类型处理 - 优化技能碰撞检测逻辑,支持范围伤害和数量限制
143 lines
4.4 KiB
TypeScript
143 lines
4.4 KiB
TypeScript
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||
import { Vec3, v3 } from "cc";
|
||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||
import { HeroViewComp } from "./HeroViewComp";
|
||
import { SkillSet, SType } from "../common/config/SkillSet";
|
||
import { HeroSkillsComp } from "./HeroSkills";
|
||
import { Skill } from "../skill/Skill";
|
||
import { CSRequestComp } from "../skill/STagComps";
|
||
|
||
/**
|
||
* ==================== 技能施法系统 手动施法====================
|
||
*
|
||
* 职责:
|
||
* 1. 监听 CSRequestComp 标记组件
|
||
* 2. 检查施法条件(CD、MP、状态)
|
||
* 3. 扣除资源(MP)
|
||
* 4. 创建技能实体
|
||
* 5. 触发施法动画
|
||
* 6. 移除请求标记
|
||
*
|
||
* 设计理念:
|
||
* - 使用标记组件驱动,符合 ECS 理念
|
||
* - 施法检查与执行分离
|
||
* - 自动处理资源消耗和CD重置
|
||
*/
|
||
// @ecs.register('SCastSystem')
|
||
export class SCastSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
|
||
|
||
/**
|
||
* 过滤器:拥有技能数据 + 施法请求的实体
|
||
*/
|
||
filter(): ecs.IMatcher {
|
||
return ecs.allOf(HeroSkillsComp, HeroAttrsComp, CSRequestComp);
|
||
}
|
||
|
||
/**
|
||
* 实体进入时触发(即请求施法时)
|
||
*/
|
||
entityEnter(e: ecs.Entity): void {
|
||
const skillsComp = e.get(HeroSkillsComp);
|
||
const heroAttrs = e.get(HeroAttrsComp);
|
||
const request = e.get(CSRequestComp);
|
||
const heroView = e.get(HeroViewComp);
|
||
|
||
// 1. 验证数据完整性
|
||
if (!skillsComp || !heroAttrs || !request || !heroView) {
|
||
console.warn("[SCastSystem] 数据不完整,取消施法");
|
||
e.remove(CSRequestComp);
|
||
return;
|
||
}
|
||
|
||
// 2. 获取技能数据
|
||
const skill = skillsComp.getSkill(request.s_uuid);
|
||
if (!skill) {
|
||
console.warn(`[SCastSystem] 技能索引无效: ${request.s_uuid }`);
|
||
e.remove(CSRequestComp);
|
||
return;
|
||
}
|
||
|
||
// 3. 检查施法条件
|
||
if (!this.checkCastConditions(skillsComp, heroAttrs, request.s_uuid)) {
|
||
e.remove(CSRequestComp);
|
||
return;
|
||
}
|
||
|
||
// 4. 执行施法
|
||
this.executeCast(e, skill, request.targets, heroView);
|
||
|
||
// 5. 扣除资源和重置CD
|
||
heroAttrs.mp -= skill.cost;
|
||
skillsComp.resetCD(request.s_uuid);
|
||
|
||
// 6. 移除请求标记
|
||
e.remove(CSRequestComp);
|
||
}
|
||
|
||
/**
|
||
* 检查施法条件
|
||
*/
|
||
private checkCastConditions(skillsComp: HeroSkillsComp, heroAttrs: HeroAttrsComp, skillIndex: number): boolean {
|
||
// 检查角色状态
|
||
if (heroAttrs.is_dead) {
|
||
return false;
|
||
}
|
||
|
||
// 检查控制状态(眩晕、冰冻)
|
||
if (heroAttrs.isStun() || heroAttrs.isFrost()) {
|
||
return false;
|
||
}
|
||
|
||
// 检查CD和MP
|
||
if (!skillsComp.canCast(skillIndex, heroAttrs.mp)) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 执行施法
|
||
*/
|
||
private executeCast(casterEntity: ecs.Entity, skill: any, targets: Vec3[], heroView: HeroViewComp) {
|
||
const config = SkillSet[skill.uuid];
|
||
if (!config) {
|
||
console.error("[SCastSystem] 技能配置不存在:", skill.uuid);
|
||
return;
|
||
}
|
||
|
||
// 1. 播放施法动画
|
||
heroView.playSkillEffect(skill.uuid);
|
||
|
||
// 2. 延迟创建技能实体(等待动画)
|
||
const delay = config.with ?? 0.3; // 施法前摇时间
|
||
heroView.scheduleOnce(() => {
|
||
this.createSkill(skill.uuid, heroView, targets);
|
||
}, delay);
|
||
|
||
const heroAttrs = casterEntity.get(HeroAttrsComp);
|
||
console.log(`[SCastSystem] ${heroAttrs?.hero_name ?? '未知'} 施放技能: ${config.name}`);
|
||
}
|
||
|
||
/**
|
||
* 创建技能实体
|
||
*/
|
||
private createSkill(skillId: number, caster: HeroViewComp, targets: Vec3[]) {
|
||
// 检查节点有效性
|
||
if (!caster.node || !caster.node.isValid) {
|
||
console.warn("[SCastSystem] 施法者节点无效");
|
||
return;
|
||
}
|
||
|
||
// 获取场景节点
|
||
const parent = caster.node.parent;
|
||
if (!parent) {
|
||
console.warn("[SCastSystem] 场景节点无效");
|
||
return;
|
||
}
|
||
|
||
// ✅ 使用现有的 SkillEnt 创建技能
|
||
// const skill = ecs.getEntity<Skill>(Skill);
|
||
|
||
}
|
||
} |