refactor(战斗系统): 重构攻击处理逻辑并优化击退机制

- 将闪避、暴击和击退的概率检查统一为checkChance方法
- 移除HeroAtkComp类并清理无用代码
- 新增clearTalBuffByAttr方法用于清除特定属性的天赋buff
- 修改HeroViewComp.do_atked方法支持可选击退参数
- 移除Attrs.BACK属性及相关配置
This commit is contained in:
2025-11-20 16:48:14 +08:00
parent b4fd807ddc
commit 51f32b1d29
4 changed files with 42 additions and 54 deletions

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

@@ -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,17 +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 attackerModel = caster?.ent?.get(HeroAttrsComp);
// 获取技能配置 // 获取技能配置
const skillConf = SkillSet[damageEvent.s_uuid]; const skillConf = SkillSet[damageEvent.s_uuid];
@@ -114,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) {
@@ -154,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;
@@ -184,31 +179,15 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
} }
} }
/**
* 闪避判定
*/
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

@@ -425,6 +425,17 @@ export class HeroAttrsComp extends ecs.Comp {
delete this.BUFFS_TAL[t_uuid]; delete this.BUFFS_TAL[t_uuid];
this.recalculateSingleAttr(attrIndex); 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) { addTalent(eff: number, value: number) {
const t = this.Talents[eff] || { value: 0, count: 0 }; const t = this.Talents[eff] || { value: 0, count: 0 };

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; // 🔥 添加后退状态标记