15 Commits

Author SHA1 Message Date
1c49649c00 refactor(hero): 重构英雄攻击系统并重命名文件 2025-11-20 16:48:23 +08:00
51f32b1d29 refactor(战斗系统): 重构攻击处理逻辑并优化击退机制
- 将闪避、暴击和击退的概率检查统一为checkChance方法
- 移除HeroAtkComp类并清理无用代码
- 新增clearTalBuffByAttr方法用于清除特定属性的天赋buff
- 修改HeroViewComp.do_atked方法支持可选击退参数
- 移除Attrs.BACK属性及相关配置
2025-11-20 16:48:14 +08:00
b4fd807ddc feat(天赋系统): 添加天赋执行次数功能并实现必暴效果
为天赋系统添加count字段控制执行次数,并实现C_ATK、C_SKILL、C_MSKILL三种必暴效果类型
2025-11-20 16:22:36 +08:00
ff4ce76482 fix: 修复技能属性引用问题并移除无用代码
- 在Skill.ts中修改Attrs为浅拷贝避免引用问题
- 移除HeroAtk.ts中未使用的casterModel变量
2025-11-20 15:19:27 +08:00
8113ec671f refactor(技能系统): 统一额外伤害参数命名从exr_dmg改为ext_dmg
修改Skill.ts和SACastSystem.ts中的参数命名,保持代码一致性
2025-11-20 15:11:59 +08:00
5a81704379 refactor(hero): 重构天赋系统使用统一管理方式
- 将分散的天赋属性管理改为统一的Talents记录
- 添加addTalent和consumeTalent方法来管理天赋状态
- 修改技能系统使用新的天赋管理接口
2025-11-20 14:51:26 +08:00
f2ec48bd2b feat(天赋系统): 重构天赋buff处理逻辑并添加vType支持
- 在TalSlot接口和talConf配置中添加vType字段区分数值型和百分比型buff
- 重构HeroAttrsComp中BUFFS_TAL数据结构,改为以天赋uuid为key的映射
- 实现新的addTalBuff和clearTalBuff方法处理天赋buff
- 在TalComp中添加BUFF类型天赋的触发处理
2025-11-20 14:35:29 +08:00
94d5aa8920 refactor(hero): 重构天赋触发机制和属性类型
将天赋触发值从布尔类型改为数值类型以支持更灵活的触发条件
修改天赋配置描述和数值以更准确反映效果
优化天赋触发逻辑,支持同时检查多个天赋
添加天赋触发后的具体效果处理
2025-11-19 16:51:36 +08:00
bcaa377cf6 refactor(英雄技能): 重构天赋触发逻辑和技能施放系统
- 将HeroAttrsComp中的isDSill和isWFuny改为talTrigger结构体
- 移除TalComp中不再使用的checkTriggers和checkIsTrigger方法
- 优化SACastSystem中的技能施放逻辑,分离天赋处理代码块
- 为Skill.load方法添加damage参数
- 重命名executeCast返回变量为castSucess以提高可读性
2025-11-19 16:03:19 +08:00
e577ed976c feat(技能系统): 添加目标数量配置并优化目标选择逻辑
- 在SkillSet枚举中添加t_num字段用于配置技能目标数量
- 修改sTargets方法,根据技能配置中的t_num确定最大目标数量
- 重构findNearbyEnemies方法,实现基于距离和位置偏差的目标排序
- 添加对技能范围配置的灵活处理,支持range和dis字段
2025-11-19 15:39:57 +08:00
209d550e87 fix(SACastSystem): 修复技能目标选择逻辑并添加默认值
当sDamageTargets未找到目标时,回退到使用sDefaultTargets获取默认目标
同时为createSkill方法的isWFuny参数添加默认值false
2025-11-19 15:37:34 +08:00
5935b20094 refactor(game): 统一游戏地平线高度并优化技能目标选择
将GameSet中的GAME_LINE从0调整为120,并在英雄和怪物位置配置中使用该常量
简化SACastSystem中的目标选择逻辑,移除未使用的治疗和BUFF目标选择方法
使用BoxSet.GAME_LINE作为技能目标的默认Y坐标
2025-11-19 14:59:50 +08:00
78ac2e949f feat(英雄系统): 优化天赋触发机制和技能施放逻辑
重构HeroAttrsComp组件结构,新增天赋触发相关属性
调整SACastSystem技能施放逻辑,支持风怒和双施天赋效果
删除无用的SCastSystem.ts.meta文件
2025-11-19 11:18:11 +08:00
9f809b1ffa feat(技能系统): 添加最大技能自动施放开关并重构施法逻辑
- 在HeroSkillsComp中添加max_auto字段控制最大技能自动施放
- 重构SACastSystem的施法逻辑,增加返回值判断
- 新增manualCast和manualCastMax方法支持手动施法
- 删除废弃的SCastSystem文件
2025-11-19 10:34:37 +08:00
e42bdbb671 refactor(天赋系统): 优化天赋触发逻辑和代码结构
重构 TalComp 类的触发检查方法,将 checkIsTrigger 拆分为 getTriggers 和 checkIsTrigger
简化 SACastSystem 中的天赋触发判断逻辑,使用新的 checkIsTrigger 返回值
2025-11-19 10:34:15 +08:00
14 changed files with 332 additions and 493 deletions

View File

@@ -14,19 +14,11 @@ export enum BoxSet {
DEFAULT = 1, DEFAULT = 1,
MONSTER = 2, MONSTER = 2,
HERO = 4, HERO = 4,
// MONSTER_SKILL = 8,
// HERO_SKILL = 16,
// PLAYER=32,
// BOSS=64,
// BOX_WIDTH = 64,
// BOX_HEIGHT = 64,
//地图边界 //地图边界
LETF_END = -420, LETF_END = -420,
RIGHT_END = 420, RIGHT_END = 420,
//游戏地平线 //游戏地平线
GAME_LINE = 0, GAME_LINE = 120,
//攻击距离 //攻击距离
} }

View File

@@ -108,7 +108,6 @@ export enum Attrs {
// ========== 武器进化相关 (70-79) ========== // ========== 武器进化相关 (70-79) ==========
PUNCTURE = 70, // 穿刺次数 PUNCTURE = 70, // 穿刺次数
PUNCTURE_DMG = 71, // 穿刺伤害 PUNCTURE_DMG = 71, // 穿刺伤害
BACK = 73, // 被击退概率(兼容旧代码)
MOVE_SPEED = 74, // 移动速度 MOVE_SPEED = 74, // 移动速度
BURN = 75, // 易伤效果 BURN = 75, // 易伤效果
WFUNY = 77, // 风怒 WFUNY = 77, // 风怒
@@ -220,7 +219,6 @@ export const AttrsType: Record<Attrs, BType> = {
// ========== 武器进化相关(混合类型) ========== // ========== 武器进化相关(混合类型) ==========
[Attrs.PUNCTURE]: BType.VALUE, // 穿刺次数 - 数值型 [Attrs.PUNCTURE]: BType.VALUE, // 穿刺次数 - 数值型
[Attrs.PUNCTURE_DMG]: BType.RATIO, // 穿刺伤害 - 百分比型 [Attrs.PUNCTURE_DMG]: BType.RATIO, // 穿刺伤害 - 百分比型
[Attrs.BACK]: BType.RATIO, // 被击退概率(兼容)- 百分比型
[Attrs.MOVE_SPEED]: BType.VALUE, // 移动速度 - 数值型 [Attrs.MOVE_SPEED]: BType.VALUE, // 移动速度 - 数值型
[Attrs.BURN]: BType.RATIO, // 易伤效果 - 百分比型 [Attrs.BURN]: BType.RATIO, // 易伤效果 - 百分比型
[Attrs.WFUNY]: BType.RATIO, // 未知特殊属性 - 百分比型 [Attrs.WFUNY]: BType.RATIO, // 未知特殊属性 - 百分比型

View File

@@ -107,6 +107,7 @@ export enum EType {
- ap: 攻击力百分比 - ap: 攻击力百分比
- cd: 冷却时间 - cd: 冷却时间
- hit_num: 范围攻击 伤害敌人数量 - hit_num: 范围攻击 伤害敌人数量
- t_num: 目标数量
- hit: 穿刺个数 - hit: 穿刺个数
- hitcd: 持续伤害的伤害间隔 - hitcd: 持续伤害的伤害间隔
- speed: 移动速度 - speed: 移动速度

View File

@@ -1,5 +1,5 @@
import { count } from "console"; import { count } from "console";
import { Attrs } from "./HeroAttrs"; import { Attrs, BType } from "./HeroAttrs";
/** /**
* 天赋类型枚举,也是触发条件 * 天赋类型枚举,也是触发条件
@@ -28,6 +28,9 @@ export enum TalEffet {
D_SKILL=8, //两次技能 D_SKILL=8, //两次技能
SHIELD=9, // 护盾 SHIELD=9, // 护盾
LDMG=10, // 减伤 LDMG=10, // 减伤
C_ATK=11, // 普工必爆
C_SKILL=12, // 一般技能必暴
C_MSKILL=13, // 必杀技能必暴
} }
export enum TalTarget { export enum TalTarget {
@@ -56,10 +59,12 @@ export interface ItalConf {
triType: TriType; triType: TriType;
target: TalTarget; target: TalTarget;
effet: TalEffet; effet: TalEffet;
vType:BType; //数值型还是百分比型
value: number; // 触发的效果值如增加10%攻击力, 触发的技能uuid,增加1个技能uuid value: number; // 触发的效果值如增加10%攻击力, 触发的技能uuid,增加1个技能uuid
attrs?:TalAttrs //触发的attrs效果的对应attrs attrs?:TalAttrs //触发的attrs效果的对应attrs
Trigger:number //触发值 Trigger:number //触发值
desc: string; // 天赋描述(说明触发条件和效果) desc: string; // 天赋描述(说明触发条件和效果)
count:number //执行次数,及可以触发的次数
} }
// ========== 天赋配置表 ========== // ========== 天赋配置表 ==========
@@ -80,42 +85,42 @@ export interface ItalConf {
*/ */
export const talConf: Record<number, ItalConf> = { export const talConf: Record<number, ItalConf> = {
/*** 普通攻击触发 ***/ /*** 普通攻击触发 ***/
7001:{uuid:7001,name:"风怒",triType:TriType.ATK,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.WFUNY,value:150,attrs:TalAttrs.NON, 7001:{uuid:7001,name:"风怒",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.WFUNY,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
desc:"普通攻击3次后, 给于目标150%伤害"}, desc:"普通攻击3次后, 立即给与目标150%伤害的额外打击"},
7002:{uuid:7002,name:"溅射",triType:TriType.ATK,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.SPLASH,value:50,attrs:TalAttrs.NON, 7002:{uuid:7002,name:"溅射",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.SPLASH,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
desc:"普通攻击3次后, 会对目标100码内的敌人造成30%伤害"}, desc:"普通攻击3次后, 会对目标100码内的敌人造成30%伤害"},
7003:{uuid:7003,name:"回血",triType:TriType.ATK,Trigger:3,target:TalTarget.SELF,effet:TalEffet.HP,value:1,attrs:TalAttrs.NON, 7003:{uuid:7003,name:"回血",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.HP,vType:BType.RATIO, value:1,attrs:TalAttrs.NON,
desc:"普通攻击3次后, 会回复10%的生命值"}, desc:"普通攻击3次后, 会回复10%的生命值"},
7004:{uuid:7004,name:"回蓝",triType:TriType.ATK,Trigger:3,target:TalTarget.SELF,effet:TalEffet.MP,value:1,attrs:TalAttrs.NON, 7004:{uuid:7004,name:"回蓝",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.MP,vType:BType.RATIO, value:1,attrs:TalAttrs.NON,
desc:"普通攻击3次后, 会回复10%的蓝值"}, desc:"普通攻击3次后, 会回复10%的蓝值"},
7005:{uuid:7005,name:"冰冻",triType:TriType.ATK,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.BUFF,value:5,attrs:TalAttrs.FREEZE_CHANCE, 7005:{uuid:7005,name:"冰冻",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:5,attrs:TalAttrs.FREEZE_CHANCE,
desc:"普通攻击3次后, 获得5%的冻结率"}, desc:"普通攻击3次后, 获得5%的冻结率"},
7006:{uuid:7006,name:"沉默",triType:TriType.ATK,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.BUFF,value:5,attrs:TalAttrs.SILENCE_CHANCE, 7006:{uuid:7006,name:"沉默",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:5,attrs:TalAttrs.SILENCE_CHANCE,
desc:"普通攻击3次后, 获得5%的沉默率"}, desc:"普通攻击3次后, 获得5%的沉默率"},
7007:{uuid:7007,name:"击退",triType:TriType.ATK,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.BUFF,value:5,attrs:TalAttrs.BACK_CHANCE, 7007:{uuid:7007,name:"击退",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:5,attrs:TalAttrs.BACK_CHANCE,
desc:"普通攻击3次后, 获得5%的击退率"}, desc:"普通攻击3次后, 获得5%的击退率"},
7008:{uuid:7008,name:"会心",triType:TriType.ATK,Trigger:3,target:TalTarget.SELF,effet:TalEffet.BUFF,value:5,attrs:TalAttrs.CRITICAL, 7008:{uuid:7008,name:"会心",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.BUFF,vType:BType.RATIO, value:5,attrs:TalAttrs.CRITICAL,
desc:"普通攻击3次后, 获得5%的暴击率"}, desc:"普通攻击3次后, 获得5%的暴击率"},
7009:{uuid:7009,name:"眩晕",triType:TriType.ATK,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.BUFF,value:5,attrs:TalAttrs.STUN_CHANCE, 7009:{uuid:7009,name:"眩晕",triType:TriType.ATK,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.BUFF,vType:BType.RATIO, value:5,attrs:TalAttrs.STUN_CHANCE,
desc:"普通攻击3次后, 获得5%的眩晕率"}, desc:"普通攻击3次后, 获得5%的眩晕率"},
7010:{uuid:7010,name:"熟练",triType:TriType.ATK,Trigger:10,target:TalTarget.SELF,effet:TalEffet.D_SKILL,value:2,attrs:TalAttrs.NON, 7010:{uuid:7010,name:"熟练",triType:TriType.ATK,Trigger:10,count:1,target:TalTarget.SELF,effet:TalEffet.D_SKILL,vType:BType.RATIO, value:0,attrs:TalAttrs.NON,
desc:"普通攻击10次后, 获得下2次一般技能触发2次"}, desc:"普通攻击10次后, 次一般技能额外释放1次,伤害100%"},
/*** 受伤触发 ***/ /*** 受伤触发 ***/
7101:{uuid:7101,name:"反击",triType:TriType.DMG,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.DMG,value:50,attrs:TalAttrs.NON, 7101:{uuid:7101,name:"反击",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.DMG,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
desc:"被攻击3次后, 给于目标50%的伤害"}, desc:"被攻击3次后, 给于目标50%的伤害"},
7102:{uuid:7102,name:"护盾",triType:TriType.DMG,Trigger:3,target:TalTarget.SELF,effet:TalEffet.SHIELD,value:20,attrs:TalAttrs.NON, 7102:{uuid:7102,name:"护盾",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.SELF,effet:TalEffet.SHIELD,vType:BType.RATIO, value:20,attrs:TalAttrs.NON,
desc:"被攻击3次后, 获得20%的生命值护盾"}, desc:"被攻击3次后, 获得20%的生命值护盾"},
7103:{uuid:7103,name:"减伤",triType:TriType.DMG,Trigger:3,target:TalTarget.ENEMY,effet:TalEffet.LDMG,value:50,attrs:TalAttrs.NON, 7103:{uuid:7103,name:"减伤",triType:TriType.DMG,Trigger:3,count:1,target:TalTarget.ENEMY,effet:TalEffet.LDMG,vType:BType.RATIO, value:50,attrs:TalAttrs.NON,
desc:"被攻击3次后, 下1次伤害减50%"}, desc:"被攻击3次后, 下1次伤害减50%"},
/*** 失去血量触发 ***/ //需要重新设计,触发类型 /*** 失去血量触发 ***/
7201:{uuid:7201,name:"背水",triType:TriType.HPL,Trigger:50,target:TalTarget.SELF,effet:TalEffet.BUFF,value:10,attrs:TalAttrs.AP, 7201:{uuid:7201,name:"背水",triType:TriType.HPL,Trigger:50,count:10,target:TalTarget.SELF,effet:TalEffet.C_ATK,vType:BType.VALUE, value:0,attrs:TalAttrs.NON,
desc:"每失去50%生命值,获得下10次普通攻击暴击"}, desc:"每失去50%生命值,获得下10次普通攻击暴击"},
/*** 升级触发 ***/ //需要重新设计,触发类型 /*** 升级触发 ***/
7301:{uuid:7301,name:"勤勉",triType:TriType.LUP,Trigger:1,target:TalTarget.SELF,effet:TalEffet.BUFF,value:5,attrs:TalAttrs.AP, 7301:{uuid:7301,name:"勤勉",triType:TriType.LUP,Trigger:1,count:5,target:TalTarget.SELF,effet:TalEffet.C_SKILL,vType:BType.VALUE, value:0,attrs:TalAttrs.NON,
desc:"每升1级,获得下5次技能暴击"}, desc:"每升1级,获得下5次技能暴击"},
}; };

View File

@@ -1,5 +1,5 @@
import { v3 } from "cc" import { v3 } from "cc"
import { FacSet } from "./GameSet" import { BoxSet, FacSet } from "./GameSet"
import { smc } from "../SingletonModuleComp" import { smc } from "../SingletonModuleComp"
import { BuffConf } from "./SkillSet" import { BuffConf } from "./SkillSet"
@@ -46,23 +46,23 @@ export const getMonList = ()=>{
} }
export const HeroPos={ export const HeroPos={
0:{pos:v3(-240,120,0)}, 0:{pos:v3(-240,BoxSet.GAME_LINE,0)},
1:{pos:v3(0,120,0)}, 1:{pos:v3(0,BoxSet.GAME_LINE,0)},
2:{pos:v3(0,120,0)}, 2:{pos:v3(0,BoxSet.GAME_LINE,0)},
} }
export const MonSet = { export const MonSet = {
0:{pos:v3(240,130,0)}, 0:{pos:v3(240,BoxSet.GAME_LINE+10,0)},
1:{pos:v3(240,110,0)}, 1:{pos:v3(240,BoxSet.GAME_LINE-10,0)},
2:{pos:v3(300,130,0)}, 2:{pos:v3(300,BoxSet.GAME_LINE+10,0)},
3:{pos:v3(300,110,0)}, 3:{pos:v3(300,BoxSet.GAME_LINE-10,0)},
4:{pos:v3(320,130,0)}, 4:{pos:v3(320,BoxSet.GAME_LINE+10,0)},
5:{pos:v3(320,110,0)}, 5:{pos:v3(320,BoxSet.GAME_LINE-10,0)},
6:{pos:v3(360,130,0)}, 6:{pos:v3(360,BoxSet.GAME_LINE+10,0)},
7:{pos:v3(360,110,0)}, 7:{pos:v3(360,BoxSet.GAME_LINE-10,0)},
8:{pos:v3(400,130,0)}, 8:{pos:v3(400,BoxSet.GAME_LINE+10,0)},
9:{pos:v3(400,110,0)}, 9:{pos:v3(400,BoxSet.GAME_LINE-10,0)},
10:{pos:v3(440,130,0)}, 10:{pos:v3(440,BoxSet.GAME_LINE+10,0)},
11:{pos:v3(440,110,0)}, 11:{pos:v3(440,BoxSet.GAME_LINE-10,0)},
} }
export enum MonStart { export enum MonStart {

View File

@@ -8,14 +8,7 @@ import { HeroViewComp } from "./HeroViewComp";
import { DamageQueueComp, DamageEvent, DamageQueueHelper } from "./DamageQueueComp"; import { DamageQueueComp, DamageEvent, DamageQueueHelper } from "./DamageQueueComp";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
/** 业务层对象 */
@ecs.register('HeroAtk')
export class HeroAtkComp extends ecs.Comp {
/** 业务层组件移除时,重置所有数据为默认值 */
reset() {
}
}
/** 最终伤害数据接口 */ /** 最终伤害数据接口 */
interface FinalData { interface FinalData {
damage: number; damage: number;
@@ -94,19 +87,17 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
* @returns * @returns
*/ */
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData { private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
const targetModel = target.get(HeroAttrsComp); const targetAttrs = target.get(HeroAttrsComp);
const targetView = target.get(HeroViewComp); const targetView = target.get(HeroViewComp);
let reDate:FinalData={ let reDate:FinalData={
damage:0, damage:0,
isCrit:false, isCrit:false,
isDodge:false, isDodge:false,
} }
if (!targetModel || targetModel.is_dead) return reDate; if (!targetAttrs || targetAttrs.is_dead) return reDate;
// 获取攻击者数据
const caster = damageEvent.caster; const caster = damageEvent.caster;
const casterModel = caster.ent.get(HeroAttrsComp); const attackerModel = caster?.ent?.get(HeroAttrsComp);
if (!casterModel) return reDate;
// 获取技能配置 // 获取技能配置
const skillConf = SkillSet[damageEvent.s_uuid]; const skillConf = SkillSet[damageEvent.s_uuid];
@@ -116,38 +107,40 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
this.onAttacked(target); this.onAttacked(target);
// 闪避判定 // 闪避判定
if (this.checkDodge(targetModel)) { const isDodge =this.checkChance(targetAttrs.Attrs[Attrs.DODGE] || 0);
if (isDodge) {
// TODO: 触发闪避视图表现 // TODO: 触发闪避视图表现
reDate.isDodge=true; reDate.isDodge=true;
return reDate; return reDate;
} }
// 暴击判定 // 暴击判定
const isCrit = this.checkCrit(targetModel.Attrs[Attrs.CRITICAL]); const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]);
if (isCrit) attackerModel?.clearTalBuffByAttr(Attrs.CRITICAL);
// 计算伤害
let damage = this.dmgCount(damageEvent.Attrs,damageEvent.s_uuid); let damage = this.dmgCount(damageEvent.Attrs,damageEvent.s_uuid);
if (isCrit) { if (isCrit) {
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + targetModel.Attrs[Attrs.CRITICAL_DMG]) / 100)); damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + targetAttrs.Attrs[Attrs.CRITICAL_DMG]) / 100));
reDate.isCrit=true; reDate.isCrit=true;
} }
// 伤害计算考虑易伤等debuff // 伤害计算考虑易伤等debuff
damage = this.calculateDamage(targetModel, damage); damage = this.calculateDamage(targetAttrs, damage);
// 护盾吸收 // 护盾吸收
damage =Math.floor(this.absorbShield(targetModel, damage)) damage =Math.floor(this.absorbShield(targetAttrs, damage))
if (damage <= 0) return reDate; if (damage <= 0) return reDate;
// 应用伤害到数据层 // 应用伤害到数据层
targetModel.hp -= damage; targetAttrs.hp -= damage;
targetModel.atked_count++; targetAttrs.atked_count++;
//击退判定
const isBack = this.checkChance(damageEvent.Attrs[Attrs.BACK_CHANCE] || 0);
if (isBack) attackerModel?.clearTalBuffByAttr(Attrs.BACK_CHANCE);
// ✅ 触发视图层表现(伤害数字、受击动画、后退) // ✅ 触发视图层表现(伤害数字、受击动画、后退)
if (targetView) { if (targetView) targetView.do_atked(damage, isCrit, damageEvent.s_uuid, isBack);
targetView.do_atked(damage, isCrit, damageEvent.s_uuid);
}
// 检查死亡 // 检查死亡
if (targetModel.hp <= 0) { if (targetAttrs.hp <= 0) {
this.doDead(target); this.doDead(target);
// ✅ 触发死亡视图表现 // ✅ 触发死亡视图表现
if (targetView) { if (targetView) {
@@ -156,7 +149,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
} }
if (this.debugMode) { if (this.debugMode) {
console.log(`[HeroAtkSystem] ${targetModel.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`); console.log(`[HeroAtkSystem] ${targetAttrs.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
} }
reDate.damage=damage; reDate.damage=damage;
@@ -182,35 +175,19 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
this.onDeath(entity); this.onDeath(entity);
if (this.debugMode) { if (this.debugMode) {
console.log(`[HeroBattleSystem] ${model.hero_name} 死亡`); console.log(`[HeroAtkSystem] ${model.hero_name} 死亡`);
} }
} }
/**
*
*/
private checkDodge(model: HeroAttrsComp): boolean {
if (model.Attrs[Attrs.DODGE] > 0) {
const random = Math.random() * 100;
if (random < model.Attrs[Attrs.DODGE]) {
if (this.debugMode) {
console.log(`[HeroBattleSystem] ${model.hero_name} 闪避了攻击`);
}
return true;
}
}
return false;
}
/** /**
* *
*/ */
private checkCrit(critRate: number): boolean { private checkChance(rate: number): boolean {
if (critRate > 0) { if (rate <= 0) return false;
const random = Math.random() * 100; const r = Math.random() * 100;
return random < critRate; return r < rate;
}
return false;
} }
/** /**

View File

@@ -3,9 +3,12 @@ import { Attrs, AttrsType, BType, NeAttrs } from "../common/config/HeroAttrs";
import { BuffConf } from "../common/config/SkillSet"; import { BuffConf } from "../common/config/SkillSet";
import { HeroInfo, AttrSet } from "../common/config/heroSet"; import { HeroInfo, AttrSet } from "../common/config/heroSet";
import { HeroSkillsComp } from "./HeroSkills"; import { HeroSkillsComp } from "./HeroSkills";
import { talConf, TalAttrs } from "../common/config/TalSet";
interface talTrigger{
value:number
count:number
}
@ecs.register('HeroAttrs') @ecs.register('HeroAttrs')
export class HeroAttrsComp extends ecs.Comp { export class HeroAttrsComp extends ecs.Comp {
Ebus:any=null! Ebus:any=null!
@@ -32,6 +35,8 @@ export class HeroAttrsComp extends ecs.Comp {
shield: number = 0; // 当前护盾 shield: number = 0; // 当前护盾
Attrs: any = []; // 最终属性数组经过Buff计算后 Attrs: any = []; // 最终属性数组经过Buff计算后
NeAttrs: any = []; // 负面状态数组 NeAttrs: any = []; // 负面状态数组
Talents: Record<number, talTrigger> = {};
BUFFS_TAL: Record<number, {count:number,BType:BType,attrIndex:number,value: number}> = {};
// ==================== 技能距离缓存 ==================== // ==================== 技能距离缓存 ====================
maxSkillDistance: number = 0; // 最远技能攻击距离缓存受MP影响 maxSkillDistance: number = 0; // 最远技能攻击距离缓存受MP影响
@@ -43,8 +48,7 @@ export class HeroAttrsComp extends ecs.Comp {
/** 临时型buff数组 - 按时间自动过期 */ /** 临时型buff数组 - 按时间自动过期 */
BUFFS_TEMP: Record<number, Array<{value: number, BType: BType, remainTime: number}>> = {}; BUFFS_TEMP: Record<number, Array<{value: number, BType: BType, remainTime: number}>> = {};
/** 天赋buff数组 - 触发过期,数量可叠加 */
BUFFS_TAL: Record<number, Array<{tal:number,value: number, BType: BType,count:number}>> = {};
// ==================== 标记状态 ==================== // ==================== 标记状态 ====================
is_dead: boolean = false; is_dead: boolean = false;
@@ -74,6 +78,7 @@ export class HeroAttrsComp extends ecs.Comp {
this.BUFFS = {}; this.BUFFS = {};
this.BUFFS_TEMP = {}; this.BUFFS_TEMP = {};
this.BUFFS_TAL = {}; this.BUFFS_TAL = {};
this.Talents = {};
// 获取英雄配置 // 获取英雄配置
const heroInfo = HeroInfo[this.hero_uuid]; const heroInfo = HeroInfo[this.hero_uuid];
@@ -181,12 +186,10 @@ export class HeroAttrsComp extends ecs.Comp {
} }
} }
} }
// 遍历天赋buff数组数值型叠加 value*count for (const key in this.BUFFS_TAL) {
if (this.BUFFS_TAL[attrIndex] && this.BUFFS_TAL[attrIndex].length > 0) { const buff = this.BUFFS_TAL[Number(key)];
for (const buff of this.BUFFS_TAL[attrIndex]) { if (buff.attrIndex === attrIndex && buff.BType === BType.VALUE) {
if (buff.BType === BType.VALUE) { totalValue += buff.value;
totalValue += buff.value * buff.count;
}
} }
} }
@@ -209,12 +212,10 @@ export class HeroAttrsComp extends ecs.Comp {
} }
} }
} }
// 遍历天赋buff数组百分比型叠加 value*count for (const key in this.BUFFS_TAL) {
if (this.BUFFS_TAL[attrIndex] && this.BUFFS_TAL[attrIndex].length > 0) { const buff = this.BUFFS_TAL[Number(key)];
for (const buff of this.BUFFS_TAL[attrIndex]) { if (buff.attrIndex === attrIndex && buff.BType === BType.RATIO) {
if (buff.BType === BType.RATIO) { totalRatio += buff.value;
totalRatio += buff.value * buff.count;
}
} }
} }
@@ -406,6 +407,48 @@ export class HeroAttrsComp extends ecs.Comp {
} }
addTalBuff(t_uuid: number, attrIndex?: number, bType?: BType, value: number = 0) {
if (attrIndex === undefined || bType === undefined) return;
const buff = this.BUFFS_TAL[t_uuid];
if (!buff) {
this.BUFFS_TAL[t_uuid] = { count: 1, BType: bType, attrIndex, value };
} else {
buff.count += 1;
buff.value += value;
}
this.recalculateSingleAttr(attrIndex);
}
clearTalBuff(t_uuid: number) {
const buff = this.BUFFS_TAL[t_uuid];
if (!buff) return;
const attrIndex = buff.attrIndex;
delete this.BUFFS_TAL[t_uuid];
this.recalculateSingleAttr(attrIndex);
}
clearTalBuffByAttr(attrIndex: number) {
let changed = false;
for (const key in this.BUFFS_TAL) {
const b = this.BUFFS_TAL[Number(key)];
if (b && b.attrIndex === attrIndex) {
delete this.BUFFS_TAL[Number(key)];
changed = true;
}
}
if (changed) this.recalculateSingleAttr(attrIndex);
}
addTalent(eff: number, value: number) {
const t = this.Talents[eff] || { value: 0, count: 0 };
t.value = value;
t.count += 1;
this.Talents[eff] = t;
}
consumeTalent(eff: number): boolean {
const t = this.Talents[eff];
if (!t || t.count <= 0) return false;
t.count -= 1;
return true;
}
reset() { reset() {
// 重置为初始状态 // 重置为初始状态
@@ -429,6 +472,7 @@ export class HeroAttrsComp extends ecs.Comp {
this.BUFFS = {}; this.BUFFS = {};
this.BUFFS_TEMP = {}; this.BUFFS_TEMP = {};
this.BUFFS_TAL = {}; this.BUFFS_TAL = {};
this.Talents = {};
// 重置技能距离缓存 // 重置技能距离缓存
this.maxSkillDistance = 0; this.maxSkillDistance = 0;
this.minSkillDistance = 0; this.minSkillDistance = 0;
@@ -444,45 +488,10 @@ export class HeroAttrsComp extends ecs.Comp {
this.atk_count = 0; this.atk_count = 0;
this.atked_count = 0; this.atked_count = 0;
} }
private getTalAttr(tal: number) {
const conf = talConf[tal];
if (!conf) return null;
const attrIndex = conf.attrs ?? TalAttrs.NON;
if (attrIndex === TalAttrs.NON) return null;
const bType = AttrsType[attrIndex as unknown as number];
const value = conf.value;
return { attrIndex: attrIndex as unknown as number, bType, value };
}
addTalBuff(tal: number, count: number = 1) {
const info = this.getTalAttr(tal);
if (!info) return;
const { attrIndex, bType, value } = info;
if (!this.BUFFS_TAL[attrIndex]) this.BUFFS_TAL[attrIndex] = [];
const list = this.BUFFS_TAL[attrIndex];
const exist = list.find(i => i.tal === tal && i.BType === bType);
if (exist) {
exist.count += count;
} else {
list.push({ tal, value, BType: bType, count });
}
this.recalculateSingleAttr(attrIndex);
}
clearTalBuff(tal: number) {
const affected = new Set<number>();
for (const key in this.BUFFS_TAL) {
const idx = parseInt(key);
const list = this.BUFFS_TAL[idx];
if (!list || list.length === 0) continue;
const newList = list.filter(i => i.tal !== tal);
if (newList.length !== list.length) {
this.BUFFS_TAL[idx] = newList;
affected.add(idx);
if (newList.length === 0) delete this.BUFFS_TAL[idx];
}
}
affected.forEach(i => this.recalculateSingleAttr(i));
}
} }

View File

@@ -38,6 +38,7 @@ export class HeroSkillsComp extends ecs.Comp {
// ==================== 技能槽位列表 ==================== // ==================== 技能槽位列表 ====================
/** 技能槽位数组最多4个技能 */ /** 技能槽位数组最多4个技能 */
skills: Record<number, SkillSlot> = {}; skills: Record<number, SkillSlot> = {};
max_auto: boolean = true;
// ==================== 辅助方法 ==================== // ==================== 辅助方法 ====================
@@ -270,4 +271,7 @@ export class HeroSkillsComp extends ecs.Comp {
reset() { reset() {
this.skills = {}; this.skills = {};
} }
setMaxAuto(on: boolean) {
this.max_auto = on;
}
} }

View File

@@ -350,7 +350,7 @@ export class HeroViewComp extends CCComp {
this.ent.destroy(); this.ent.destroy();
} }
do_atked(damage:number,isCrit:boolean,s_uuid:number){ do_atked(damage:number,isCrit:boolean,s_uuid:number,isBack:boolean=false){
// 受到攻击时显示血条并设置显示时间即使伤害为0也显示 // 受到攻击时显示血条并设置显示时间即使伤害为0也显示
this.top_node.active = true; this.top_node.active = true;
this.hpBarShowCD = this.hpBarShowTime; this.hpBarShowCD = this.hpBarShowTime;
@@ -359,8 +359,8 @@ export class HeroViewComp extends CCComp {
// 视图层表现 // 视图层表现
let SConf=SkillSet[s_uuid] let SConf=SkillSet[s_uuid]
this.back() if (isBack) this.back()
this.showDamage(damage, isCrit, SConf.DAnm); // 暴击状态由战斗系统内部处理, DAnm和EAnm共用设定数组 this.showDamage(damage, isCrit, SConf.DAnm);
} }
private isBackingUp: boolean = false; // 🔥 添加后退状态标记 private isBackingUp: boolean = false; // 🔥 添加后退状态标记

View File

@@ -8,6 +8,7 @@ import { Skill } from "../skill/Skill";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
import { TalComp } from "./TalComp"; import { TalComp } from "./TalComp";
import { TalEffet, TriType } from "../common/config/TalSet"; import { TalEffet, TriType } from "../common/config/TalSet";
import { BoxSet } from "../common/config/GameSet";
/** /**
* ==================== 自动施法系统 ==================== * ==================== 自动施法系统 ====================
@@ -52,6 +53,7 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
for (const s_uuid of readySkills) { for (const s_uuid of readySkills) {
const skill = skills.getSkill(s_uuid); const skill = skills.getSkill(s_uuid);
if (!skill) continue; if (!skill) continue;
if (skill.hset === HSSet.max && !skills.max_auto) continue;
const config = SkillSet[skill.s_uuid]; const config = SkillSet[skill.s_uuid];
if (!config || config.SType !== SType.damage) continue; if (!config || config.SType !== SType.damage) continue;
@@ -66,20 +68,44 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
break; break;
} }
} }
private startCast(e: ecs.Entity,skill:SkillSlot,hset:HSSet): void { private startCast(e: ecs.Entity,skill:SkillSlot,hset:HSSet): boolean {
if (!skill||!e) return if (!skill||!e) return false
const skills = e.get(HeroSkillsComp); const skills = e.get(HeroSkillsComp);
const heroAttrs = e.get(HeroAttrsComp); const heroAttrs = e.get(HeroAttrsComp);
const heroView = e.get(HeroViewComp); const heroView = e.get(HeroViewComp);
// 3. 检查施法条件 // 3. 检查施法条件
if (!this.checkCastConditions(skills, heroAttrs, skill.s_uuid)) return if (!this.checkCastConditions(skills, heroAttrs, skill.s_uuid)) return false
// 4. 执行施法 // 4. 执行施法
this.executeCast(e, skill.s_uuid, heroView,hset); const castSucess = this.executeCast(e, skill.s_uuid, heroView,hset);
// 5. 扣除资源和重置CD // 5. 扣除资源和重置CD
heroAttrs.mp -= skill.cost; if (castSucess) {
skills.resetCD(skill.s_uuid); heroAttrs.mp -= skill.cost;
skills.resetCD(skill.s_uuid);
}
return castSucess;
}
public manualCast(e: ecs.Entity, s_uuid: number): boolean {
if (!e) return false
const skills = e.get(HeroSkillsComp)
const heroAttrs = e.get(HeroAttrsComp)
const heroView = e.get(HeroViewComp)
if (!skills || !heroAttrs || !heroView) return false
const slot = skills.getSkill(s_uuid)
if (!slot) return false
return this.startCast(e, slot, slot.hset)
}
public manualCastMax(e: ecs.Entity): boolean {
const skills = e.get(HeroSkillsComp)
if (!skills) return false
for (const key in skills.skills) {
const s_uuid = Number(key)
const slot = skills.getSkill(s_uuid)
if (slot && slot.hset === HSSet.max) {
return this.manualCast(e, s_uuid)
}
}
return false
} }
/** /**
* 检查施法条件 * 检查施法条件
@@ -106,53 +132,65 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
/** /**
* 执行施法 * 执行施法
*/ */
private executeCast(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp,hset:HSSet) { private executeCast(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp,hset:HSSet): boolean {
const heroAttrs=casterEntity.get(HeroAttrsComp)
const config = SkillSet[s_uuid]; const config = SkillSet[s_uuid];
if (!config) { if (!config) {
console.error("[SACastSystem] 技能配置不存在:", s_uuid); console.error("[SACastSystem] 技能配置不存在:", s_uuid);
return; return false;
} }
// 1. 播放施法动画 // 1. 播放施法动画
heroView.playSkillEffect(s_uuid); heroView.playSkillEffect(s_uuid);
let isDSill=false /**********************天赋处理*************************************************************************/
let isWFuny=false
// 2. 更新攻击类型的天赋触发值 // 2. 更新攻击类型的天赋触发值
if(casterEntity.has(TalComp)){ if(casterEntity.has(TalComp)){
const talComp = casterEntity.get(TalComp); const talComp = casterEntity.get(TalComp);
if (hset === HSSet.atk) { if (hset === HSSet.atk) talComp.updateCur(TriType.ATK);
talComp.updateCur(TriType.ATK); if (hset != HSSet.atk) talComp.updateCur(TriType.SKILL);
isWFuny= talComp.checkIsTrigger(TalEffet.WFUNY); }
} /**********************天赋处理*************************************************************************/
if (hset != HSSet.atk) { // 获取目标位置
talComp.updateCur(TriType.SKILL); let targets = this.sTargets(heroView, s_uuid);
isDSill= talComp.checkIsTrigger(TalEffet.D_SKILL); if (targets.length === 0) {
} console.warn("[SACastSystem] 没有找到有效目标");
return false;
} }
// 2. 延迟创建技能实体(等待动画) // 2. 延迟创建技能实体(等待动画)
const delay = 0.3 const delay = 0.3
heroView.scheduleOnce(() => { heroView.scheduleOnce(() => {
this.createSkill(s_uuid, heroView,isWFuny); this.createSkill(s_uuid, heroView,targets);
isWFuny=false
}, delay); }, delay);
if(isDSill){ //风怒wfuny 只针对 普通攻击起效
if (hset === HSSet.atk && heroAttrs.consumeTalent(TalEffet.WFUNY)){
heroView.playSkillEffect(s_uuid); heroView.playSkillEffect(s_uuid);
//需要再添加 风怒动画
this.createSkill(s_uuid, heroView,targets);
}
// 双技能 只针对 技能起效
if(hset === HSSet.skill && heroAttrs.consumeTalent(TalEffet.D_SKILL)){
targets = this.sTargets(heroView, s_uuid);
if (targets.length === 0) {
console.warn("[SACastSystem] 没有找到有效目标");
return false;
}
heroView.playSkillEffect(s_uuid);
//需要再添加 双技能动画
heroView.scheduleOnce(() => { heroView.scheduleOnce(() => {
this.createSkill(s_uuid, heroView,isWFuny); this.createSkill(s_uuid, heroView,targets);
isWFuny=false
}, delay); }, delay);
} }
const heroAttrs = casterEntity.get(HeroAttrsComp);
// console.log(`[SACastSystem] ${heroAttrs?.hero_name ?? '未知'} 施放技能: ${config.name}`); return true;
} }
/** /**
* 创建技能实体 * 创建技能实体
*/ */
private createSkill(s_uuid: number, caster: HeroViewComp,isWFuny:boolean) { private createSkill(s_uuid: number, caster: HeroViewComp,targets:Vec3[]=[],ext_dmg:number=0) {
// 检查节点有效性 // 检查节点有效性
if (!caster.node || !caster.node.isValid) { if (!caster.node || !caster.node.isValid) {
console.warn("[SACastSystem] 施法者节点无效"); console.warn("[SACastSystem] 施法者节点无效");
@@ -166,12 +204,7 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
return; return;
} }
// 获取目标位置
const targets = this.sTargets(caster);
if (targets.length === 0) {
console.warn("[SACastSystem] 没有找到有效目标");
return;
}
// 创建技能实体 // 创建技能实体
const skill = ecs.getEntity<Skill>(Skill); const skill = ecs.getEntity<Skill>(Skill);
@@ -182,26 +215,22 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
const targetPos = targets[0]; // 使用第一个目标位置 const targetPos = targets[0]; // 使用第一个目标位置
// console.log(`[SACastSystem]: ${s_uuid}, 起始位置: ${startPos}, 目标位置: ${targetPos}`); // console.log(`[SACastSystem]: ${s_uuid}, 起始位置: ${startPos}, 目标位置: ${targetPos}`);
// 加载技能实体(包括预制体、组件初始化等) // 加载技能实体(包括预制体、组件初始化等)
skill.load(startPos, parent, s_uuid, targetPos, caster); skill.load(startPos, parent, s_uuid, targetPos, caster,ext_dmg);
} }
/** /**
* 选择目标位置 * 选择目标位置
*/ */
private sTargets(caster: HeroViewComp): Vec3[] { private sTargets(caster: HeroViewComp, s_uuid: number): Vec3[] {
// 简化版:选择最前方的敌人
const targets: Vec3[] = [];
// 这里可以调用 SkillConComp 的目标选择逻辑
// 暂时返回默认位置
if (caster == null) return targets;
if (caster.ent == null) return targets;
const heroAttrs = caster.ent.get(HeroAttrsComp); const heroAttrs = caster.ent.get(HeroAttrsComp);
const fac = heroAttrs?.fac ?? 0; if (!heroAttrs) return [];
const defaultX = fac === 0 ? 400 : -400; const config = SkillSet[s_uuid];
targets.push(v3(defaultX, 0, 0)); if (!config) return this.sDefaultTargets(caster, heroAttrs.fac);
const maxTargets = Math.max(1, Number((config as any).t_num ?? 1));
const targets = this.sDamageTargets(caster, config, maxTargets);
if (targets.length === 0) {
targets.push(...this.sDefaultTargets(caster, heroAttrs.fac));
}
return targets; return targets;
} }
@@ -213,8 +242,8 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
const heroAttrs = caster.ent.get(HeroAttrsComp); const heroAttrs = caster.ent.get(HeroAttrsComp);
if (!heroAttrs) return targets; if (!heroAttrs) return targets;
// 寻找最近的敌人 const range = Number((config as any).range ?? config.dis ?? 300);
const enemyPositions = this.findNearbyEnemies(caster, heroAttrs.fac, config.range || 300); const enemyPositions = this.findNearbyEnemies(caster, heroAttrs.fac, range);
// 选择最多maxTargets个目标 // 选择最多maxTargets个目标
for (let i = 0; i < Math.min(maxTargets, enemyPositions.length); i++) { for (let i = 0; i < Math.min(maxTargets, enemyPositions.length); i++) {
@@ -229,82 +258,49 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
return targets; return targets;
} }
/**
* 选择治疗技能目标
*/
private sHealTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] {
const targets: Vec3[] = [];
const heroAttrs = caster.ent.get(HeroAttrsComp);
if (!heroAttrs) return targets;
// 寻找血量最低的友军
const allyPositions = this.findLowHealthAllies(caster, heroAttrs.fac, config.range || 200);
for (let i = 0; i < Math.min(maxTargets, allyPositions.length); i++) {
targets.push(allyPositions[i]);
}
// 如果没有找到友军,治疗自己
if (targets.length === 0 && caster.node) {
targets.push(caster.node.position.clone());
}
return targets;
}
/**
* 选择BUFF技能目标
*/
private sBuffTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] {
// BUFF技能通常施放在自己或友军身上
return this.sHealTargets(caster, config, maxTargets);
}
/**
* 选择DEBUFF技能目标
*/
private sDebuffTargets(caster: HeroViewComp, config: any, maxTargets: number): Vec3[] {
// DEBUFF技能通常施放在敌人身上
return this.sDamageTargets(caster, config, maxTargets);
}
/** /**
* 选择默认目标 * 选择默认目标
*/ */
private sDefaultTargets(caster: HeroViewComp, faction: number): Vec3[] { private sDefaultTargets(caster: HeroViewComp, fac: number): Vec3[] {
const targets: Vec3[] = []; const targets: Vec3[] = [];
const defaultX = faction === 0 ? 400 : -400; const defaultX = fac === 0 ? 400 : -400;
targets.push(v3(defaultX, 0, 0)); targets.push(v3(defaultX, BoxSet.GAME_LINE, 1));
return targets; return targets;
} }
/** /**
* 查找附近的敌人 * 查找附近的敌人
*/ */
private findNearbyEnemies(caster: HeroViewComp, faction: number, range: number): Vec3[] { private findNearbyEnemies(caster: HeroViewComp, fac: number, range: number): Vec3[] {
// 简化实现实际应该查询ECS中的敌方实体
const enemies: Vec3[] = []; const enemies: Vec3[] = [];
if (!caster || !caster.node) return enemies;
// 模拟敌人位置 const currentPos = caster.node.position;
const enemyX = faction === 0 ? 300 : -300; const results: { pos: Vec3; dist: number; laneBias: number }[] = [];
enemies.push(v3(enemyX, 0, 0)); ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
enemies.push(v3(enemyX + 50, 20, 0)); const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
if (!model || !view || !view.node) return false;
if (model.is_dead) return false;
if (model.fac === fac) return false;
const pos = view.node.position;
const dist = Math.abs(currentPos.x - pos.x);
if (dist <= range) {
const laneBias = Math.abs(currentPos.y - pos.y);
results.push({ pos: pos.clone(), dist, laneBias });
}
return false;
});
results.sort((a, b) => {
if (a.laneBias !== b.laneBias) return a.laneBias - b.laneBias;
return a.dist - b.dist;
});
for (const r of results) enemies.push(r.pos);
return enemies; return enemies;
} }
/**
* 查找血量低的友军
*/
private findLowHealthAllies(caster: HeroViewComp, faction: number, range: number): Vec3[] {
// 简化实现实际应该查询ECS中的友方实体并按血量排序
const allies: Vec3[] = [];
// 如果自己血量低,优先治疗自己
return allies;
}
/** /**
* 检查技能攻击范围内是否有敌人 * 检查技能攻击范围内是否有敌人

View File

@@ -1,145 +0,0 @@
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";
import { smc } from "../common/SingletonModuleComp";
/**
* ==================== 技能施法系统 手动施法====================
*
* 职责:
* 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 {
if(!smc.mission.play || smc.mission.pause) return;
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);
}
}

View File

@@ -1,9 +0,0 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "25f14ca0-5053-495e-bc3d-08b1bb4ee5d7",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -1,5 +1,7 @@
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { BType } from "../common/config/HeroAttrs";
import { TalAttrs, talConf, TalEffet, TalTarget, TriType} from "../common/config/TalSet"; import { TalAttrs, talConf, TalEffet, TalTarget, TriType} from "../common/config/TalSet";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp"; import { HeroViewComp } from "./HeroViewComp";
/** /**
@@ -13,8 +15,11 @@ export interface TalSlot {
target: TalTarget; target: TalTarget;
effet: TalEffet; effet: TalEffet;
attrs?:TalAttrs //触发的attrs效果的对应attrs value: number; // 触发的效果数值 attrs?:TalAttrs //触发的attrs效果的对应attrs value: number; // 触发的效果数值
vType:BType; // 数值型还是百分比型
value: number; // 触发的效果数值 value: number; // 触发的效果数值
value_add: number; // 触发的效果数值增量 value_add: number; // 触发的效果数值增量
count: number; // 执行次数,及可以触发的次数
count_add: number; // 执行次数增量
Trigger: number; // 天赋触发阈值 Trigger: number; // 天赋触发阈值
Trigger_add: number; // 天赋触发阈值减值 Trigger_add: number; // 天赋触发阈值减值
desc: string; // 天赋描述(说明触发条件和效果) desc: string; // 天赋描述(说明触发条件和效果)
@@ -56,37 +61,40 @@ export class TalComp extends ecs.Comp {
/** /**
* 为英雄添加一个新天赋 * 为英雄添加一个新天赋
* @param talUuid 要添加的天赋ID * @param uuid 要添加的天赋ID
* *
* 添加流程: * 添加流程:
* 1. 检查天赋是否已存在 * 1. 检查天赋是否已存在
* 2. 检查天赋配置是否存在 * 2. 检查天赋配置是否存在
* 3. 创建并初始化天赋数据 * 3. 创建并初始化天赋数据
*/ */
addTal(talUuid: number) { addTal(uuid: number) {
// 检查天赋是否已存在 // 检查天赋是否已存在
if (this.Tals[talUuid]) { if (this.Tals[uuid]) {
console.error(`[TalComp]天赋已存在,天赋ID:${talUuid}`); console.error(`[TalComp]天赋已存在,天赋ID:${uuid}`);
return; return;
} }
// 获取天赋配置 // 获取天赋配置
const tConf = talConf[talUuid]; const tConf = talConf[uuid];
if (!tConf) { if (!tConf) {
console.error(`[TalComp]天赋配置不存在,天赋ID:${talUuid}`); console.error(`[TalComp]天赋配置不存在,天赋ID:${uuid}`);
return; return;
} }
// 创建并初始化天赋数据 // 创建并初始化天赋数据
this.Tals[talUuid] = { this.Tals[uuid] = {
uuid: talUuid, uuid: uuid,
name: tConf.name, name: tConf.name,
triType: tConf.triType, triType: tConf.triType,
target: tConf.target, target: tConf.target,
effet: tConf.effet, effet: tConf.effet,
attrs: tConf.attrs, attrs: tConf.attrs,
vType: tConf.vType,
value: tConf.value, // 效果数值初始为配置值 value: tConf.value, // 效果数值初始为配置值
value_add: 0, // 效果数值增量初始为0 value_add: 0, // 效果数值增量初始为0
count: 1, // 执行次数,及可以触发的次数
count_add:0, // 执行次数增量初始为0
Trigger: tConf.Trigger, // 触发阈值(后续可从配置中读取) Trigger: tConf.Trigger, // 触发阈值(后续可从配置中读取)
Trigger_add: 0, // 触发阈值增量初始为0 Trigger_add: 0, // 触发阈值增量初始为0
desc: tConf.desc, desc: tConf.desc,
@@ -96,87 +104,55 @@ export class TalComp extends ecs.Comp {
checkTal() { checkTal() {
return Object.keys(this.Tals).length > 0; return Object.keys(this.Tals).length > 0;
} }
/** getTriggers() {
* 检查并触发指定类型的天赋
* @param triType 要检查的天赋触发类型
* @returns 触发的天赋对象集合若没有触发则返回false
*
* 检查逻辑:
* 1. 遍历所有同类型天赋
* 2. 检查累积值是否达到触发条件
* 3. 触发后重置累积值
* 4. 收集并返回所有触发的天赋
*/
checkTriggers(effet: TalEffet) {
// 存储所有触发的天赋 // 存储所有触发的天赋
let Triggers: Record<string, TalSlot> = {}; let Triggers: Record<string, TalSlot> = {};
// 遍历所有天赋 // 遍历所有天赋
for (let uuid in this.Tals) { for (let uuid in this.Tals) {
const talent = this.Tals[uuid]; const talent = this.Tals[uuid];
// 匹配天赋类型 if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发
if (talent.effet == effet) { console.log(`[TalComp]天赋触发,天赋ID:${uuid}`);
// 修复触发条件逻辑:累积值达到或超过触发阈值时触发 // 重置累积值
// 原逻辑中 `talent.Trigger-talent.Trigger` 总是为0导致任何累积值都能触发 talent.cur = 0;
if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发 // 添加到触发列表
console.log(`[TalComp]天赋触发,天赋ID:${uuid}`); Triggers[uuid] = talent;
// 重置累积值 }
talent.cur = 0;
// 添加到触发列表
Triggers[uuid] = talent;
}
}
} }
// 判断是否有天赋被触发 // 判断是否有天赋被触发
return Triggers; return Triggers;
} }
checkIsTrigger(effet: TalEffet) {
for (let uuid in this.Tals) {
const talent = this.Tals[uuid];
// 匹配天赋类型
if (talent.effet == effet) {
// 修复触发条件逻辑:累积值达到或超过触发阈值时触发
// 原逻辑中 `talent.Trigger-talent.Trigger` 总是为0导致任何累积值都能触发
if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发
console.log(`[TalComp]天赋触发,天赋ID:${uuid}`);
// 重置累积值
talent.cur = 0;
// 添加到触发列表
return true;
}
}
}
}
/** /**
* 更新天赋的效果数值 * 更新天赋的效果数值
* @param talUuid 天赋ID * @param uuid 天赋ID
* @param val 要增减的数值 * @param val 要增减的数值
* *
* 功能: * 功能:
* - 用于调整天赋的实际效果数值 * - 用于调整天赋的实际效果数值
* - 可通过正负数来增加或减少效果 * - 可通过正负数来增加或减少效果
*/ */
updateVal(talUuid: number, val: number) { updateVal(uuid: number, val: number) {
// 检查天赋是否存在 // 检查天赋是否存在
if (!this.Tals[talUuid]) { if (!this.Tals[uuid]) {
console.error(`[TalComp]天赋不存在,天赋ID:${talUuid}`); console.error(`[TalComp]天赋不存在,天赋ID:${uuid}`);
return; return;
} }
// 更新天赋效果数值 // 更新天赋效果数值
this.Tals[talUuid].value_add += val; this.Tals[uuid].value_add += val;
} }
updateTrigger(talUuid: number, val: number) { updateTrigger(uuid: number, val: number) {
// 检查天赋是否存在 // 检查天赋是否存在
if (!this.Tals[talUuid]) { if (!this.Tals[uuid]) {
console.error(`[TalComp]天赋不存在,天赋ID:${talUuid}`); console.error(`[TalComp]天赋不存在,天赋ID:${uuid}`);
return; return;
} }
// 更新天赋触发阈值 // 更新天赋触发阈值
this.Tals[talUuid].Trigger_add += val; this.Tals[uuid].Trigger_add += val;
if (this.Tals[talUuid].Trigger-this.Tals[talUuid].Trigger_add <= 1) { if (this.Tals[uuid].Trigger-this.Tals[uuid].Trigger_add <= 1) {
this.Tals[talUuid].Trigger_add = this.Tals[talUuid].Trigger-1; this.Tals[uuid].Trigger_add = this.Tals[uuid].Trigger-1;
} }
} }
/** /**
@@ -193,22 +169,57 @@ export class TalComp extends ecs.Comp {
for (let uuid in this.Tals) { for (let uuid in this.Tals) {
const talent = this.Tals[uuid]; const talent = this.Tals[uuid];
// 找到第一个匹配类型的天赋并更新 // 找到所有匹配类型的天赋并更新
if (talent.triType == triType) { if (talent.triType == triType) {
talent.cur += val; talent.cur += val;
break; // 只更新第一个匹配的天赋 this.checkTrigger(talent.uuid);
} }
} }
} }
checkTrigger(uuid:number){
const talent = this.Tals[uuid];
if (talent.cur >= (talent.Trigger - talent.Trigger_add)) { // 修复触发条件,累积值达到或超过触发阈值时触发
console.log(`[TalComp]天赋触发,天赋ID:${uuid}`);
for(let i=0;i<(talent.count+talent.count_add);i++){
this.doTriggerTal(talent.uuid);
}
// 重置累积值
talent.cur = 0;
}
}
//执行天赋触发效果
doTriggerTal(uuid: number) {
// 检查天赋是否存在
if (!this.Tals[uuid]) {
console.error(`[TalComp]天赋不存在,天赋ID:${uuid}`);
return;
}
const talent = this.Tals[uuid];
const heroAttrs=this.ent.get(HeroAttrsComp);
switch(talent.effet){
case TalEffet.WFUNY:
heroAttrs.addTalent(TalEffet.WFUNY, talent.value + talent.value_add);
break;
case TalEffet.D_SKILL:
heroAttrs.addTalent(TalEffet.D_SKILL, talent.value + talent.value_add);
break;
case TalEffet.C_ATK:
heroAttrs.addTalent(TalEffet.C_ATK, talent.value + talent.value_add);
break;
case TalEffet.C_SKILL:
heroAttrs.addTalent(TalEffet.C_SKILL, talent.value + talent.value_add);
break;
case TalEffet.C_MSKILL:
heroAttrs.addTalent(TalEffet.C_MSKILL, talent.value + talent.value_add);
break;
case TalEffet.BUFF:
heroAttrs.addTalBuff(talent.uuid, talent.attrs, talent.vType, talent.value + talent.value_add);
break;
}
}
/** /**
* 重置组件状态 * 重置组件状态
*
* 功能:
* - 清空所有天赋数据
* - 重置英雄ID
* - 清除英雄视图引用
* - 为组件的复用做准备
*/ */
reset() { reset() {
this.Tals = {}; this.Tals = {};

View File

@@ -29,7 +29,7 @@ export class Skill extends ecs.Entity {
this.addComponents<SMoveDataComp>(SMoveDataComp); this.addComponents<SMoveDataComp>(SMoveDataComp);
} }
load(startPos: Vec3, parent: Node, s_uuid: number, targetPos: Vec3, load(startPos: Vec3, parent: Node, s_uuid: number, targetPos: Vec3,
caster:HeroViewComp) { caster:HeroViewComp,ext_dmg:number=0) {
const config = SkillSet[s_uuid]; const config = SkillSet[s_uuid];
if (!config) { if (!config) {
@@ -90,7 +90,7 @@ export class Skill extends ecs.Entity {
const sDataCom = this.get(SDataCom); const sDataCom = this.get(SDataCom);
sDataCom.group=caster.box_group sDataCom.group=caster.box_group
sDataCom.caster=caster sDataCom.caster=caster
sDataCom.Attrs=cAttrsComp.Attrs sDataCom.Attrs={...cAttrsComp.Attrs}
sDataCom.s_uuid=s_uuid sDataCom.s_uuid=s_uuid
sDataCom.fac=cAttrsComp.fac sDataCom.fac=cAttrsComp.fac
} }