refactor(技能系统): 重构技能系统以使用s_uuid作为主键并优化技能施放逻辑
- 将HeroSkillsComp中的技能数组改为以s_uuid为键的对象存储 - 修改CSRequestComp使用s_uuid替代skillIndex - 优化SkillCastSystem和SACastSystem的施放逻辑 - 为SMoveDataComp添加rePos方法处理技能位置计算 - 移除未使用的SDataComSystem代码
This commit is contained in:
@@ -119,7 +119,7 @@ export class HeroLifecycleSystem extends ecs.ComblockSystem
|
|||||||
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
|
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
|
||||||
|
|
||||||
filter() {
|
filter() {
|
||||||
return ecs.allOf(HeroAttrsComp);
|
return ecs.allOf(HeroMoveComp);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityEnter(e: ecs.Entity): void {
|
entityEnter(e: ecs.Entity): void {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { SkillSet } from "../common/config/SkillSet";
|
|||||||
* 单个技能的运行时数据
|
* 单个技能的运行时数据
|
||||||
*/
|
*/
|
||||||
export interface SkillSlot {
|
export interface SkillSlot {
|
||||||
uuid: number; // 技能配置ID
|
s_uuid: number; // 技能配置ID
|
||||||
cd: number; // 当前CD时间(递减)
|
cd: number; // 当前CD时间(递减)
|
||||||
cd_max: number; // 最大CD时间
|
cd_max: number; // 最大CD时间
|
||||||
cost: number; // MP消耗
|
cost: number; // MP消耗
|
||||||
@@ -31,7 +31,7 @@ export class HeroSkillsComp extends ecs.Comp {
|
|||||||
|
|
||||||
// ==================== 技能槽位列表 ====================
|
// ==================== 技能槽位列表 ====================
|
||||||
/** 技能槽位数组(最多4个技能) */
|
/** 技能槽位数组(最多4个技能) */
|
||||||
skills: SkillSlot[] = [];
|
skills: Record<number, SkillSlot> = {};
|
||||||
|
|
||||||
// ==================== 辅助方法 ====================
|
// ==================== 辅助方法 ====================
|
||||||
|
|
||||||
@@ -47,14 +47,13 @@ export class HeroSkillsComp extends ecs.Comp {
|
|||||||
console.warn(`[HeroSkills] 技能配置不存在: ${s_uuid}`);
|
console.warn(`[HeroSkills] 技能配置不存在: ${s_uuid}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
this.skills[s_uuid]={
|
||||||
this.skills.push({
|
s_uuid: config.uuid,
|
||||||
uuid: config.uuid,
|
cd: 0,
|
||||||
cd: 0, // 初始CD为0,可立即施放
|
|
||||||
cd_max: config.cd,
|
cd_max: config.cd,
|
||||||
cost: config.cost,
|
cost: config.cost,
|
||||||
level: 1
|
level: 1,
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,30 +66,31 @@ export class HeroSkillsComp extends ecs.Comp {
|
|||||||
console.warn(`[HeroSkills] 技能配置不存在: ${s_uuid}`);
|
console.warn(`[HeroSkills] 技能配置不存在: ${s_uuid}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.skills[s_uuid] = {
|
||||||
this.skills.push({
|
s_uuid: config.uuid,
|
||||||
uuid: config.uuid,
|
|
||||||
cd: 0,
|
cd: 0,
|
||||||
cd_max: config.cd,
|
cd_max: config.cd,
|
||||||
cost: config.cost,
|
cost: config.cost,
|
||||||
level: 1
|
level: 1
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定索引的技能
|
* 获取指定s_uuid的技能
|
||||||
*/
|
*/
|
||||||
getSkill(index: number): SkillSlot | null {
|
getSkill(s_uuid: number): SkillSlot | null {
|
||||||
return this.skills[index] ?? null;
|
return this.skills[s_uuid] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查技能是否可施放
|
* 检查技能是否可施放(通过索引)
|
||||||
* @param index 技能索引
|
* @param index 技能索引
|
||||||
* @param currentMp 当前MP值
|
* @param currentMp 当前MP值
|
||||||
*/
|
*/
|
||||||
canCast(index: number, currentMp: number): boolean {
|
canCast(s_uuid: number, currentMp: number): boolean {
|
||||||
const skill = this.getSkill(index);
|
const skill = this.getSkill(s_uuid);
|
||||||
if (!skill) return false;
|
if (!skill) return false;
|
||||||
|
|
||||||
// 检查CD和MP
|
// 检查CD和MP
|
||||||
@@ -98,11 +98,35 @@ export class HeroSkillsComp extends ecs.Comp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置技能CD(开始冷却)
|
* 检查技能是否可施放(通过s_uuid)
|
||||||
|
* @param s_uuid 技能配置ID
|
||||||
|
* @param currentMp 当前MP值
|
||||||
|
*/
|
||||||
|
canCastByUuid(s_uuid: number, currentMp: number): boolean {
|
||||||
|
const skill = this.getSkill(s_uuid);
|
||||||
|
if (!skill) return false;
|
||||||
|
|
||||||
|
// 检查CD和MP
|
||||||
|
return skill.cd <= 0 && currentMp >= skill.cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置技能CD(开始冷却,通过索引)
|
||||||
* @param index 技能索引
|
* @param index 技能索引
|
||||||
*/
|
*/
|
||||||
resetCD(index: number) {
|
resetCD(s_uuid: number) {
|
||||||
const skill = this.getSkill(index);
|
const skill = this.getSkill(s_uuid);
|
||||||
|
if (skill) {
|
||||||
|
skill.cd = skill.cd_max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置技能CD(开始冷却,通过s_uuid)
|
||||||
|
* @param s_uuid 技能配置ID
|
||||||
|
*/
|
||||||
|
resetCDByUuid(s_uuid: number) {
|
||||||
|
const skill = this.getSkill(s_uuid);
|
||||||
if (skill) {
|
if (skill) {
|
||||||
skill.cd = skill.cd_max;
|
skill.cd = skill.cd_max;
|
||||||
}
|
}
|
||||||
@@ -113,7 +137,8 @@ export class HeroSkillsComp extends ecs.Comp {
|
|||||||
* @param dt 时间增量
|
* @param dt 时间增量
|
||||||
*/
|
*/
|
||||||
updateCDs(dt: number) {
|
updateCDs(dt: number) {
|
||||||
for (const skill of this.skills) {
|
for (const s_uuid in this.skills) {
|
||||||
|
const skill = this.skills[Number(s_uuid)];
|
||||||
if (skill.cd > 0) {
|
if (skill.cd > 0) {
|
||||||
skill.cd -= dt;
|
skill.cd -= dt;
|
||||||
if (skill.cd < 0) {
|
if (skill.cd < 0) {
|
||||||
@@ -128,15 +153,15 @@ export class HeroSkillsComp extends ecs.Comp {
|
|||||||
*/
|
*/
|
||||||
getReadySkills(currentMp: number): number[] {
|
getReadySkills(currentMp: number): number[] {
|
||||||
const ready: number[] = [];
|
const ready: number[] = [];
|
||||||
for (let i = 0; i < this.skills.length; i++) {
|
for (const s_uuid in this.skills) {
|
||||||
if (this.canCast(i, currentMp)) {
|
if (this.canCastByUuid(Number(s_uuid), currentMp)) {
|
||||||
ready.push(i);
|
ready.push(Number(s_uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.skills = [];
|
this.skills = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,6 @@ const { ccclass, property } = _decorator;
|
|||||||
|
|
||||||
/** 角色显示组件 */
|
/** 角色显示组件 */
|
||||||
export interface BuffInfo {
|
export interface BuffInfo {
|
||||||
attr: Attrs;
|
|
||||||
value: number;
|
value: number;
|
||||||
remainTime?: number;
|
remainTime?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export class MonLifecycleSystem extends ecs.ComblockSystem
|
|||||||
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
|
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
|
||||||
|
|
||||||
filter() {
|
filter() {
|
||||||
return ecs.allOf(HeroAttrsComp);
|
return ecs.allOf(MonMoveComp);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityEnter(e: ecs.Entity): void {
|
entityEnter(e: ecs.Entity): void {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { Vec3, v3 } from "cc";
|
|||||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||||
import { HeroViewComp } from "./HeroViewComp";
|
import { HeroViewComp } from "./HeroViewComp";
|
||||||
import { SkillSet, SType } from "../common/config/SkillSet";
|
import { SkillSet, SType } from "../common/config/SkillSet";
|
||||||
import { HeroSkillsComp } from "./HeroSkills";
|
import { HeroSkillsComp, SkillSlot } from "./HeroSkills";
|
||||||
import { CSRequestComp } from "../skill/STagComps";
|
import { Skill } from "../skill/Skill";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ==================== 自动施法系统 ====================
|
* ==================== 自动施法系统 ====================
|
||||||
@@ -30,38 +30,116 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
|
|
||||||
update(e: ecs.Entity): void {
|
update(e: ecs.Entity): void {
|
||||||
const skills = e.get(HeroSkillsComp);
|
const skills = e.get(HeroSkillsComp);
|
||||||
const heroModel = e.get(HeroAttrsComp);
|
const heroAttrs = e.get(HeroAttrsComp);
|
||||||
const heroView = e.get(HeroViewComp);
|
const heroView = e.get(HeroViewComp);
|
||||||
if (!skills || !heroModel || !heroView) return;
|
if (!skills || !heroAttrs || !heroView) return;
|
||||||
|
|
||||||
// 检查基本条件
|
// 检查基本条件
|
||||||
if (heroModel.is_dead || heroModel.isStun() || heroModel.isFrost()) return;
|
if (heroAttrs.is_dead || heroAttrs.isStun() || heroAttrs.isFrost()) return;
|
||||||
|
|
||||||
// 检查是否正在攻击(只有攻击时才释放技能)
|
// 检查是否正在攻击(只有攻击时才释放技能)
|
||||||
if (!heroModel.is_atking) return;
|
if (!heroAttrs.is_atking) return;
|
||||||
|
|
||||||
// 获取所有可施放的技能
|
// 获取所有可施放的技能
|
||||||
const readySkills = skills.getReadySkills(heroModel.mp);
|
const readySkills = skills.getReadySkills(heroAttrs.mp);
|
||||||
if (readySkills.length === 0) return;
|
if (readySkills.length === 0) return;
|
||||||
|
|
||||||
// 选择第一个可施放的伤害技能
|
// 选择第一个可施放的伤害技能
|
||||||
for (const skillIndex of readySkills) {
|
for (const s_uuid of readySkills) {
|
||||||
const skill = skills.getSkill(skillIndex);
|
const skill = skills.getSkill(s_uuid);
|
||||||
if (!skill) continue;
|
if (!skill) continue;
|
||||||
|
|
||||||
const config = SkillSet[skill.uuid];
|
const config = SkillSet[skill.s_uuid];
|
||||||
if (!config || config.SType !== SType.damage) continue;
|
if (!config || config.SType !== SType.damage) continue;
|
||||||
|
|
||||||
// ✅ 添加施法请求标记组件
|
// ✅ 开始执行施法
|
||||||
const request = e.add(CSRequestComp) as CSRequestComp;
|
this.startCast(e,skill);
|
||||||
request.skillIndex = skillIndex;
|
|
||||||
request.targets = this.sTargets(heroView);
|
|
||||||
|
|
||||||
// 一次只施放一个技能
|
// 一次只施放一个技能
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private startCast(e: ecs.Entity,skill:SkillSlot): void {
|
||||||
|
if (!skill||!e) return
|
||||||
|
const skills = e.get(HeroSkillsComp);
|
||||||
|
const heroAttrs = e.get(HeroAttrsComp);
|
||||||
|
const heroView = e.get(HeroViewComp);
|
||||||
|
// 3. 检查施法条件
|
||||||
|
if (!this.checkCastConditions(skills, heroAttrs, skill.s_uuid)) return
|
||||||
|
|
||||||
|
// 4. 执行施法
|
||||||
|
this.executeCast(e, skill.s_uuid, heroView);
|
||||||
|
// 5. 扣除资源和重置CD
|
||||||
|
heroAttrs.mp -= skill.cost;
|
||||||
|
skills.resetCD(skill.s_uuid);
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查施法条件
|
||||||
|
*/
|
||||||
|
private checkCastConditions(skills: HeroSkillsComp, heroAttrs: HeroAttrsComp, s_uuid: number): boolean {
|
||||||
|
// 检查角色状态
|
||||||
|
if (heroAttrs.is_dead) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查控制状态(眩晕、冰冻)
|
||||||
|
if (heroAttrs.isStun() || heroAttrs.isFrost()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查CD和MP
|
||||||
|
if (!skills.canCast(s_uuid, heroAttrs.mp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行施法
|
||||||
|
*/
|
||||||
|
private executeCast(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp) {
|
||||||
|
const config = SkillSet[s_uuid];
|
||||||
|
if (!config) {
|
||||||
|
console.error("[SkillCastSystem] 技能配置不存在:", s_uuid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 1. 播放施法动画
|
||||||
|
heroView.playSkillEffect(s_uuid);
|
||||||
|
|
||||||
|
// 2. 延迟创建技能实体(等待动画)
|
||||||
|
const delay = config.with ?? 0.3; // 施法前摇时间
|
||||||
|
heroView.scheduleOnce(() => {
|
||||||
|
this.createSkill(s_uuid, heroView);
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
const heroAttrs = casterEntity.get(HeroAttrsComp);
|
||||||
|
console.log(`[SkillCastSystem] ${heroAttrs?.hero_name ?? '未知'} 施放技能: ${config.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建技能实体
|
||||||
|
*/
|
||||||
|
private createSkill(s_uuid: number, caster: HeroViewComp) {
|
||||||
|
// 检查节点有效性
|
||||||
|
if (!caster.node || !caster.node.isValid) {
|
||||||
|
console.warn("[SkillCastSystem] 施法者节点无效");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取场景节点
|
||||||
|
const parent = caster.node.parent;
|
||||||
|
if (!parent) {
|
||||||
|
console.warn("[SkillCastSystem] 场景节点无效");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const targets=this.sTargets(caster);
|
||||||
|
// ✅ 使用Skill 创建技能
|
||||||
|
const skill = ecs.getEntity<Skill>(Skill);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 选择目标位置
|
* 选择目标位置
|
||||||
*/
|
*/
|
||||||
@@ -71,8 +149,8 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
|
|
||||||
// 这里可以调用 SkillConComp 的目标选择逻辑
|
// 这里可以调用 SkillConComp 的目标选择逻辑
|
||||||
// 暂时返回默认位置
|
// 暂时返回默认位置
|
||||||
const heroModel = caster.ent.get(HeroAttrsComp);
|
const heroAttrs = caster.ent.get(HeroAttrsComp);
|
||||||
const fac = heroModel?.fac ?? 0;
|
const fac = heroAttrs?.fac ?? 0;
|
||||||
const defaultX = fac === 0 ? 400 : -400;
|
const defaultX = fac === 0 ? 400 : -400;
|
||||||
targets.push(v3(defaultX, 0, 0));
|
targets.push(v3(defaultX, 0, 0));
|
||||||
|
|
||||||
@@ -84,11 +162,11 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
*/
|
*/
|
||||||
private sDamageTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] {
|
private sDamageTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] {
|
||||||
const targets: Vec3[] = [];
|
const targets: Vec3[] = [];
|
||||||
const heroModel = caster.ent.get(HeroAttrsComp);
|
const heroAttrs = caster.ent.get(HeroAttrsComp);
|
||||||
if (!heroModel) return targets;
|
if (!heroAttrs) return targets;
|
||||||
|
|
||||||
// 寻找最近的敌人
|
// 寻找最近的敌人
|
||||||
const enemyPositions = this.findNearbyEnemies(caster, heroModel.fac, config.range || 300);
|
const enemyPositions = this.findNearbyEnemies(caster, heroAttrs.fac, config.range || 300);
|
||||||
|
|
||||||
// 选择最多maxTargets个目标
|
// 选择最多maxTargets个目标
|
||||||
for (let i = 0; i < Math.min(maxTargets, enemyPositions.length); i++) {
|
for (let i = 0; i < Math.min(maxTargets, enemyPositions.length); i++) {
|
||||||
@@ -97,7 +175,7 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
|
|
||||||
// 如果没有找到敌人,使用默认位置
|
// 如果没有找到敌人,使用默认位置
|
||||||
if (targets.length === 0) {
|
if (targets.length === 0) {
|
||||||
targets.push(...this.sDefaultTargets(caster, heroModel.fac));
|
targets.push(...this.sDefaultTargets(caster, heroAttrs.fac));
|
||||||
}
|
}
|
||||||
|
|
||||||
return targets;
|
return targets;
|
||||||
@@ -108,11 +186,11 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
*/
|
*/
|
||||||
private sHealTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] {
|
private sHealTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] {
|
||||||
const targets: Vec3[] = [];
|
const targets: Vec3[] = [];
|
||||||
const heroModel = caster.ent.get(HeroAttrsComp);
|
const heroAttrs = caster.ent.get(HeroAttrsComp);
|
||||||
if (!heroModel) return targets;
|
if (!heroAttrs) return targets;
|
||||||
|
|
||||||
// 寻找血量最低的友军
|
// 寻找血量最低的友军
|
||||||
const allyPositions = this.findLowHealthAllies(caster, heroModel.fac, config.range || 200);
|
const allyPositions = this.findLowHealthAllies(caster, heroAttrs.fac, config.range || 200);
|
||||||
|
|
||||||
for (let i = 0; i < Math.min(maxTargets, allyPositions.length); i++) {
|
for (let i = 0; i < Math.min(maxTargets, allyPositions.length); i++) {
|
||||||
targets.push(allyPositions[i]);
|
targets.push(allyPositions[i]);
|
||||||
@@ -179,5 +257,6 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
|
|
||||||
return allies;
|
return allies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ import { CSRequestComp } from "../skill/STagComps";
|
|||||||
* - 施法检查与执行分离
|
* - 施法检查与执行分离
|
||||||
* - 自动处理资源消耗和CD重置
|
* - 自动处理资源消耗和CD重置
|
||||||
*/
|
*/
|
||||||
@ecs.register('SkillCastSystem')
|
// @ecs.register('SkillCastSystem')
|
||||||
export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
|
export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,28 +38,28 @@ export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEn
|
|||||||
* 实体进入时触发(即请求施法时)
|
* 实体进入时触发(即请求施法时)
|
||||||
*/
|
*/
|
||||||
entityEnter(e: ecs.Entity): void {
|
entityEnter(e: ecs.Entity): void {
|
||||||
const skills = e.get(HeroSkillsComp);
|
const skillsComp = e.get(HeroSkillsComp);
|
||||||
const heroModel = e.get(HeroAttrsComp);
|
const heroAttrs = e.get(HeroAttrsComp);
|
||||||
const request = e.get(CSRequestComp);
|
const request = e.get(CSRequestComp);
|
||||||
const heroView = e.get(HeroViewComp);
|
const heroView = e.get(HeroViewComp);
|
||||||
|
|
||||||
// 1. 验证数据完整性
|
// 1. 验证数据完整性
|
||||||
if (!skills || !heroModel || !request || !heroView) {
|
if (!skillsComp || !heroAttrs || !request || !heroView) {
|
||||||
console.warn("[SkillCastSystem] 数据不完整,取消施法");
|
console.warn("[SkillCastSystem] 数据不完整,取消施法");
|
||||||
e.remove(CSRequestComp);
|
e.remove(CSRequestComp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 获取技能数据
|
// 2. 获取技能数据
|
||||||
const skill = skills.getSkill(request.skillIndex);
|
const skill = skillsComp.getSkill(request.s_uuid);
|
||||||
if (!skill) {
|
if (!skill) {
|
||||||
console.warn(`[SkillCastSystem] 技能索引无效: ${request.skillIndex}`);
|
console.warn(`[SkillCastSystem] 技能索引无效: ${request.s_uuid }`);
|
||||||
e.remove(CSRequestComp);
|
e.remove(CSRequestComp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 检查施法条件
|
// 3. 检查施法条件
|
||||||
if (!this.checkCastConditions(skills, heroModel, request.skillIndex)) {
|
if (!this.checkCastConditions(skillsComp, heroAttrs, request.s_uuid)) {
|
||||||
e.remove(CSRequestComp);
|
e.remove(CSRequestComp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -68,8 +68,8 @@ export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEn
|
|||||||
this.executeCast(e, skill, request.targets, heroView);
|
this.executeCast(e, skill, request.targets, heroView);
|
||||||
|
|
||||||
// 5. 扣除资源和重置CD
|
// 5. 扣除资源和重置CD
|
||||||
heroModel.mp -= skill.cost;
|
heroAttrs.mp -= skill.cost;
|
||||||
skills.resetCD(request.skillIndex);
|
skillsComp.resetCD(request.s_uuid);
|
||||||
|
|
||||||
// 6. 移除请求标记
|
// 6. 移除请求标记
|
||||||
e.remove(CSRequestComp);
|
e.remove(CSRequestComp);
|
||||||
@@ -78,19 +78,19 @@ export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEn
|
|||||||
/**
|
/**
|
||||||
* 检查施法条件
|
* 检查施法条件
|
||||||
*/
|
*/
|
||||||
private checkCastConditions(skills: HeroSkillsComp, heroModel: HeroAttrsComp, skillIndex: number): boolean {
|
private checkCastConditions(skillsComp: HeroSkillsComp, heroAttrs: HeroAttrsComp, skillIndex: number): boolean {
|
||||||
// 检查角色状态
|
// 检查角色状态
|
||||||
if (heroModel.is_dead) {
|
if (heroAttrs.is_dead) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查控制状态(眩晕、冰冻)
|
// 检查控制状态(眩晕、冰冻)
|
||||||
if (heroModel.isStun() || heroModel.isFrost()) {
|
if (heroAttrs.isStun() || heroAttrs.isFrost()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查CD和MP
|
// 检查CD和MP
|
||||||
if (!skills.canCast(skillIndex, heroModel.mp)) {
|
if (!skillsComp.canCast(skillIndex, heroAttrs.mp)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,8 +116,8 @@ export class SkillCastSystem extends ecs.ComblockSystem implements ecs.IEntityEn
|
|||||||
this.createSkill(skill.uuid, heroView, targets);
|
this.createSkill(skill.uuid, heroView, targets);
|
||||||
}, delay);
|
}, delay);
|
||||||
|
|
||||||
const heroModel = casterEntity.get(HeroAttrsComp);
|
const heroAttrs = casterEntity.get(HeroAttrsComp);
|
||||||
console.log(`[SkillCastSystem] ${heroModel?.hero_name ?? '未知'} 施放技能: ${config.name}`);
|
console.log(`[SkillCastSystem] ${heroAttrs?.hero_name ?? '未知'} 施放技能: ${config.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,16 +18,16 @@ export class SDataCom extends ecs.Comp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 业务层业务逻辑处理对象 */
|
// /** 业务层业务逻辑处理对象 */
|
||||||
export class SDataComSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
|
// export class SDataComSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
|
||||||
filter(): ecs.IMatcher {
|
// filter(): ecs.IMatcher {
|
||||||
return ecs.allOf(SDataCom);
|
// return ecs.allOf(SDataCom);
|
||||||
}
|
// }
|
||||||
|
|
||||||
entityEnter(e: ecs.Entity): void {
|
// entityEnter(e: ecs.Entity): void {
|
||||||
// 注:自定义业务逻辑
|
// // 注:自定义业务逻辑
|
||||||
|
|
||||||
|
|
||||||
e.remove(SDataCom);
|
// e.remove(SDataCom);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
@@ -2,6 +2,7 @@ import { Vec3, v3 } 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 { BezierMove } from "../BezierMove/BezierMove";
|
import { BezierMove } from "../BezierMove/BezierMove";
|
||||||
import { RType, SkillSet } from "../common/config/SkillSet";
|
import { RType, SkillSet } from "../common/config/SkillSet";
|
||||||
|
import { BoxSet } from "../common/config/BoxSet";
|
||||||
/**
|
/**
|
||||||
* 技能移动数据组件
|
* 技能移动数据组件
|
||||||
* 存储技能实体的移动相关数据
|
* 存储技能实体的移动相关数据
|
||||||
@@ -29,6 +30,21 @@ export class SMoveDataComp extends ecs.Comp {
|
|||||||
this.direction.set(0, 0, 0);
|
this.direction.set(0, 0, 0);
|
||||||
this.autoDestroy = true;
|
this.autoDestroy = true;
|
||||||
}
|
}
|
||||||
|
rePos(originalStart:Vec3){
|
||||||
|
if(!originalStart){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 计算延长后的目标点坐标
|
||||||
|
const originalTarget = v3(this.targetPos.x, this.targetPos.y + BoxSet.ATK_Y);
|
||||||
|
const direction = new Vec3();
|
||||||
|
Vec3.subtract(direction, originalTarget, originalStart);
|
||||||
|
const distance = direction.length();
|
||||||
|
direction.normalize();
|
||||||
|
const extendedTarget = new Vec3();
|
||||||
|
Vec3.scaleAndAdd(extendedTarget, originalTarget, direction, 720);
|
||||||
|
this.startPos.set(originalStart);
|
||||||
|
this.targetPos.set(extendedTarget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /** 业务层业务逻辑处理对象 */
|
// /** 业务层业务逻辑处理对象 */
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ import { Vec3 } from "cc";
|
|||||||
@ecs.register('CSRequest')
|
@ecs.register('CSRequest')
|
||||||
export class CSRequestComp extends ecs.Comp {
|
export class CSRequestComp extends ecs.Comp {
|
||||||
/** 技能索引(在 HeroSkillsComp.skills 中的位置) */
|
/** 技能索引(在 HeroSkillsComp.skills 中的位置) */
|
||||||
skillIndex: number = 0;
|
s_uuid: number = 0;
|
||||||
|
|
||||||
/** 目标位置数组(由请求者提供) */
|
/** 目标位置数组(由请求者提供) */
|
||||||
targets: Vec3[] = [];
|
targets: Vec3[] = [];
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.skillIndex = 0;
|
this.s_uuid = 0;
|
||||||
this.targets = [];
|
this.targets = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { SkillView } from "./SkillView";
|
|||||||
import { SDataCom } from "./SDataCom";
|
import { SDataCom } from "./SDataCom";
|
||||||
import { Attrs } from "../common/config/HeroAttrs";
|
import { Attrs } from "../common/config/HeroAttrs";
|
||||||
import { SMoveDataComp } from "../skill/SMoveComp";
|
import { SMoveDataComp } from "../skill/SMoveComp";
|
||||||
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
|
|
||||||
/** Skill 模块 */
|
/** Skill 模块 */
|
||||||
@ecs.register(`Skill`)
|
@ecs.register(`Skill`)
|
||||||
@@ -32,10 +33,12 @@ export class Skill extends ecs.Entity {
|
|||||||
this.addComponents<SDataCom>();
|
this.addComponents<SDataCom>();
|
||||||
this.addComponents<SMoveDataComp>();
|
this.addComponents<SMoveDataComp>();
|
||||||
}
|
}
|
||||||
load(startPos: Vec3, parent: Node, uuid: number, targetPos: Vec3,casterAttrs:Attrs[]=[],scale:number=1,fac:FacSet=FacSet.MON,type:HType=HType.warrior,box_group:BoxSet=BoxSet.HERO) {
|
load(startPos: Vec3, parent: Node, s_uuid: number, targetPos: Vec3,
|
||||||
const config = SkillSet[uuid];
|
caster:HeroViewComp) {
|
||||||
|
const config = SkillSet[s_uuid];
|
||||||
|
let casterAttrs=caster.ent.get(HeroAttrsComp).Attrs
|
||||||
if (!config) {
|
if (!config) {
|
||||||
console.error("[Skill] 技能配置不存在:", uuid);
|
console.error("[Skill] 技能配置不存在:", s_uuid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,32 +56,35 @@ export class Skill extends ecs.Entity {
|
|||||||
// 设置节点属性
|
// 设置节点属性
|
||||||
node.setPosition(startPos);
|
node.setPosition(startPos);
|
||||||
|
|
||||||
if(fac==FacSet.MON){
|
if(casterAttrs.fac==FacSet.MON){
|
||||||
node.scale=v3(node.scale.x*-1,1,1)
|
node.scale=v3(node.scale.x*-1,1,1)
|
||||||
}else{
|
}else{
|
||||||
if(type==HType.warrior){
|
if(casterAttrs.type==HType.warrior){
|
||||||
if(scale<0){
|
if(casterAttrs.node.scale<0){
|
||||||
node.scale=v3(node.scale.x*-1,node.scale.y,1)
|
node.scale=v3(node.scale.x*-1,node.scale.y,1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 添加技能组件
|
// 初始视图
|
||||||
const SView = node.getComponent(SkillView); // 初始化技能参数
|
const SView = node.getComponent(SkillView);
|
||||||
// 只设置必要的运行时属性,配置信息通过 SkillSet[uuid] 访问
|
// 只设置必要的运行时属性,配置信息通过 SkillSet[uuid] 访问
|
||||||
// 核心标识
|
// 核心标识
|
||||||
SView.s_uuid= uuid
|
SView.s_uuid= s_uuid
|
||||||
SView.group= box_group
|
SView.group= caster.box_group
|
||||||
|
|
||||||
this.add(SView);
|
this.add(SView);
|
||||||
|
// 初始化移动组件
|
||||||
|
|
||||||
const sDataCom = this.get(SDataCom);
|
|
||||||
const sMoveCom = this.get(SMoveDataComp);
|
const sMoveCom = this.get(SMoveDataComp);
|
||||||
sMoveCom.startPos=startPos
|
sMoveCom.startPos=startPos
|
||||||
sMoveCom.targetPos=targetPos
|
sMoveCom.targetPos=targetPos
|
||||||
sMoveCom.s_uuid=uuid
|
sMoveCom.s_uuid=s_uuid
|
||||||
sDataCom.group=box_group
|
|
||||||
|
// 初始化数据组件
|
||||||
|
const sDataCom = this.get(SDataCom);
|
||||||
|
sDataCom.group=caster.box_group
|
||||||
|
sDataCom.caster=caster
|
||||||
sDataCom.attrs=casterAttrs
|
sDataCom.attrs=casterAttrs
|
||||||
sDataCom.s_uuid=uuid
|
sDataCom.s_uuid=s_uuid
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { _decorator, Animation, Collider2D, Contact2DType, Vec3 } from "cc";
|
import { _decorator, Animation, CCInteger, Collider2D, Contact2DType, v3, Vec3 } 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 { HeroViewComp } from "../hero/HeroViewComp";
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
@@ -15,6 +15,11 @@ const { ccclass, property } = _decorator;
|
|||||||
@ecs.register('SkillView', false)
|
@ecs.register('SkillView', false)
|
||||||
export class SkillView extends CCComp {
|
export class SkillView extends CCComp {
|
||||||
/** 视图层逻辑代码分离演示 */
|
/** 视图层逻辑代码分离演示 */
|
||||||
|
@property({ type: CCInteger })
|
||||||
|
atk_x: number = 0
|
||||||
|
@property({ type: CCInteger })
|
||||||
|
|
||||||
|
atk_y: number = 0
|
||||||
anim:Animation=null;
|
anim:Animation=null;
|
||||||
group:number=0;
|
group:number=0;
|
||||||
SConf:any=null;
|
SConf:any=null;
|
||||||
@@ -29,6 +34,9 @@ export class SkillView extends CCComp {
|
|||||||
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||||||
}
|
}
|
||||||
const SMove=this.ent.get(SMoveDataComp)
|
const SMove=this.ent.get(SMoveDataComp)
|
||||||
|
// 计算延长后的目标点坐标
|
||||||
|
SMove.rePos(v3(this.node.position.x + this.atk_x, this.node.position.y + this.atk_y))
|
||||||
|
|
||||||
switch(this.SConf.RType){
|
switch(this.SConf.RType){
|
||||||
case RType.linear:
|
case RType.linear:
|
||||||
this.do_linear(SMove.startPos,SMove.targetPos)
|
this.do_linear(SMove.startPos,SMove.targetPos)
|
||||||
@@ -54,6 +62,7 @@ export class SkillView extends CCComp {
|
|||||||
if (!this.SConf) return;
|
if (!this.SConf) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_bezier(startPos:Vec3,targetPos:Vec3){
|
do_bezier(startPos:Vec3,targetPos:Vec3){
|
||||||
let bm=this.node.getComponent(BezierMove)
|
let bm=this.node.getComponent(BezierMove)
|
||||||
this.node.angle +=10
|
this.node.angle +=10
|
||||||
|
|||||||
Reference in New Issue
Block a user