feat(战斗系统): 添加反伤机制并优化属性变量命名

添加新的技能配置5000(反伤)和实现反伤逻辑
将targetAttrs统一重命名为TAttrsComp以提高代码一致性
This commit is contained in:
2025-11-27 16:12:23 +08:00
parent 0692d58e01
commit b2cc25b32b
2 changed files with 66 additions and 45 deletions

View File

@@ -30,7 +30,7 @@ interface FinalData {
*
* 重要概念:
* - damageEvent.Attrs: 施法者属性快照(创建技能时保存)
* - targetAttrs: 被攻击者实时属性
* - TAttrsComp: 被攻击者实时属性
* - 属性来源规范:攻击判定用施法者,防御判定用被攻击者
*/
@ecs.register('HeroAtkSystem')
@@ -51,10 +51,10 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
*/
update(e: ecs.Entity): void {
if(!smc.mission.play || smc.mission.pause) return;
const model = e.get(HeroAttrsComp);
const TAttrsComp = e.get(HeroAttrsComp);
const damageQueue = e.get(DamageQueueComp);
if (!model || !damageQueue || damageQueue.isEmpty()) return;
if (!TAttrsComp || !damageQueue || damageQueue.isEmpty()) return;
// 标记正在处理
damageQueue.isProcessing = true;
@@ -73,13 +73,13 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
if (this.debugMode) {
const casterName = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_name || "未知";
const casterUuid = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_uuid || 0;
console.log(`[HeroAtkSystem] 英雄${model.hero_name} (uuid: ${model.hero_uuid}) 受到 ${casterName}(uuid: ${casterUuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击技能ID ${damageEvent.s_uuid}`);
console.log(`[HeroAtkSystem] 英雄${TAttrsComp.hero_name} (uuid: ${TAttrsComp.hero_uuid}) 受到 ${casterName}(uuid: ${casterUuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击技能ID ${damageEvent.s_uuid}`);
}
// 如果目标已死亡,停止处理后续伤害
if (model.is_dead) {
if (TAttrsComp.is_dead) {
if (this.debugMode) {
console.log(`[HeroAtkSystem] ${model.hero_name} 已死亡,停止处理剩余伤害`);
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 已死亡,停止处理剩余伤害`);
}
damageQueue.clear(); // 清空剩余伤害
break;
@@ -91,7 +91,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
e.remove(DamageQueueComp);
if (this.debugMode && processedCount > 0) {
console.log(`[HeroAtkSystem] ${model.hero_name} 伤害队列处理完成,共处理 ${processedCount} 个伤害事件`);
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 伤害队列处理完成,共处理 ${processedCount} 个伤害事件`);
}
}
}
@@ -109,7 +109,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
* - HIT: 命中率(用于闪避计算)
* - AP/MAP: 攻击力(基础伤害计算)
*
* ✅ 正确使用被攻击者属性(targetAttrs - 实时):
* ✅ 正确使用被攻击者属性(TAttrsComp - 实时):
* - DODGE: 闪避率(用于闪避计算)
* - SHIELD_MAX: 护盾最大值(护盾吸收)
* - hp: 当前生命值(伤害应用)
@@ -124,17 +124,17 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
* @returns 最终伤害数据(包含伤害值、暴击标记、闪避标记)
*/
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
const targetAttrs = target.get(HeroAttrsComp);
const TAttrsComp = target.get(HeroAttrsComp);
const targetView = target.get(HeroViewComp);
let reDate:FinalData={
damage:0,
isCrit:false,
isDodge:false,
}
if (!targetAttrs || targetAttrs.is_dead) return reDate;
if (!TAttrsComp || TAttrsComp.is_dead) return reDate;
const caster = damageEvent.caster;
const attackerModel = caster?.ent?.get(HeroAttrsComp);
const attackerTAttrsComp = caster?.ent?.get(HeroAttrsComp);
// 获取技能配置
const skillConf = SkillSet[damageEvent.s_uuid];
@@ -145,19 +145,19 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 闪避判定
// 闪避成功概率 = 被攻击者闪避率 - 施法者命中率
// targetAttrs.Attrs[Attrs.DODGE]: 被攻击者的实时闪避属性
// TAttrsComp.Attrs[Attrs.DODGE]: 被攻击者的实时闪避属性
// damageEvent.Attrs[Attrs.HIT]: 施法者在技能创建时的命中属性快照
const isDodge =this.checkChance((targetAttrs.Attrs[Attrs.DODGE]-damageEvent.Attrs[Attrs.HIT]) || 0);
const isDodge =this.checkChance((TAttrsComp.Attrs[Attrs.DODGE]-damageEvent.Attrs[Attrs.HIT]) || 0);
if (isDodge) {
// TODO: 触发闪避视图表现
reDate.isDodge=true;
return reDate;
}
// 暴击判定
// 使用施法者的暴击率属性damageEvent.Attrs 快照),- 被攻击者的暴击抗性属性targetAttrs.Attrs[Attrs.CRITICAL_RESIST]
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]-targetAttrs.Attrs[Attrs.CRITICAL_RESIST]);
// 使用施法者的暴击率属性damageEvent.Attrs 快照),- 被攻击者的暴击抗性属性TAttrsComp.Attrs[Attrs.CRITICAL_RESIST]
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]-TAttrsComp.Attrs[Attrs.CRITICAL_RESIST]);
// 计算基础伤害
let damage = this.dmgCount(damageEvent,targetAttrs);
let damage = this.dmgCount(damageEvent,TAttrsComp);
if (isCrit) {
// 暴击伤害计算
// 使用施法者的暴击伤害加成属性damageEvent.Attrs 快照)
@@ -165,20 +165,22 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
const casterCritDmg = damageEvent.Attrs[Attrs.CRITICAL_DMG] || 0;
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + casterCritDmg) / 100));
reDate.isCrit=true;
attackerModel?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
attackerTAttrsComp?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
}
// 护盾吸收
damage =Math.floor(this.absorbShield(targetAttrs, damage))
damage =Math.floor(this.absorbShield(TAttrsComp, damage))
if (damage <= 0) return reDate;
// 应用伤害到数据层
targetAttrs.hp -= damage;
targetAttrs.atked_count++;
TAttrsComp.hp -= damage;
TAttrsComp.atked_count++;
//反伤判定 并应用到施法者
this.check_thorns(TAttrsComp, caster?.ent,damage);
// 击退判定
// 使用施法者的击退概率属性damageEvent.Attrs 快照)
// 击退成功后需要清理施法者的相关天赋buff
const isBack = this.checkChance(damageEvent.Attrs[Attrs.BACK_CHANCE] || 0);
if (isBack) attackerModel?.useValueTalByAttr(Attrs.BACK_CHANCE);
if (isBack) attackerTAttrsComp?.useValueTalByAttr(Attrs.BACK_CHANCE);
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
@@ -186,7 +188,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 检查死亡
if (targetAttrs.hp <= 0) {
if (TAttrsComp.hp <= 0) {
this.doDead(target);
// ✅ 触发死亡视图表现
if (targetView) {
@@ -195,12 +197,27 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
}
if (this.debugMode) {
console.log(`[HeroAtkSystem] ${targetAttrs.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
}
reDate.damage=damage;
return reDate;
}
check_thorns(TAttrsComp:HeroAttrsComp, caster: ecs.Entity, damage:number) {
// 检查目标是否有反伤属性
if (!caster||damage<=0) return;
let thornsDamage=0;
thornsDamage=TAttrsComp.Attrs[Attrs.THORNS]||0+TAttrsComp.useCountValTal(Attrs.THORNS);
let CAttrs=caster.get(HeroAttrsComp);
// 计算反伤伤害
let thornsDmg=Math.floor(thornsDamage*damage/100);
// 应用反伤伤害到数据层
CAttrs.hp -= thornsDmg;
CAttrs.atked_count++;
let CView=caster.get(HeroViewComp);
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
if (CView) CView.do_atked(thornsDmg, false, SkillSet[5000].uuid, false);
}
/**
* 详细伤害计算核心方法
*
@@ -343,16 +360,16 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
* 这确保了死亡逻辑的单一性和一致性
*/
private doDead(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp);
if (!model || model.is_dead) return;
const TAttrsComp = entity.get(HeroAttrsComp);
if (!TAttrsComp || TAttrsComp.is_dead) return;
model.is_dead = true;
TAttrsComp.is_dead = true;
// 触发死亡事件
this.onDeath(entity);
if (this.debugMode) {
console.log(`[HeroAtkSystem] ${model.hero_name} 死亡`);
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 死亡`);
}
}
@@ -395,24 +412,24 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
* 2. 如果护盾值 < 伤害值:部分吸收,剩余伤害 = 原伤害 - 护盾值
* 3. 护盾被击破时,重置护盾最大值属性
*
* @param model 被攻击者的属性组件(包含当前护盾值)
* @param TAttrsComp 被攻击者的属性组件(包含当前护盾值)
* @param damage 原始伤害值
* @returns 剩余伤害值(护盾吸收后的结果)
*/
private absorbShield(model: HeroAttrsComp, damage: number): number {
if (model.shield <= 0) return damage;
private absorbShield(TAttrsComp: HeroAttrsComp, damage: number): number {
if (TAttrsComp.shield <= 0) return damage;
if (model.shield >= damage) {
model.shield -= damage;
if (model.shield <= 0) {
model.shield = 0;
model.Attrs[Attrs.SHIELD_MAX] = 0;
if (TAttrsComp.shield >= damage) {
TAttrsComp.shield -= damage;
if (TAttrsComp.shield <= 0) {
TAttrsComp.shield = 0;
TAttrsComp.Attrs[Attrs.SHIELD_MAX] = 0;
}
return 0;
} else {
const remainingDamage = damage - model.shield;
model.shield = 0;
model.Attrs[Attrs.SHIELD_MAX] = 0;
const remainingDamage = damage - TAttrsComp.shield;
TAttrsComp.shield = 0;
TAttrsComp.Attrs[Attrs.SHIELD_MAX] = 0;
return remainingDamage;
}
}
@@ -430,11 +447,11 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
* @todo 当前对怪物实体直接返回,后续可以根据需求扩展怪物的被攻击逻辑
*/
private onAttacked(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp);
if (!model || model.is_dead) return;
const TAttrsComp = entity.get(HeroAttrsComp);
if (!TAttrsComp || TAttrsComp.is_dead) return;
// 这里可以添加被攻击时的特殊处理逻辑
if (model.fac === FacSet.MON) return;
if (TAttrsComp.fac === FacSet.MON) return;
// 例如:触发某些天赋效果、反击逻辑等
}
@@ -458,13 +475,13 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
* @important 死亡事件应该幂等,避免重复触发
*/
private onDeath(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp);
if (!model) return;
const TAttrsComp = entity.get(HeroAttrsComp);
if (!TAttrsComp) return;
if (model.fac === FacSet.MON) {
if (TAttrsComp.fac === FacSet.MON) {
// 怪物死亡处理
this.scheduleDrop(entity);
} else if (model.fac === FacSet.HERO) {
} else if (TAttrsComp.fac === FacSet.HERO) {
// 英雄死亡处理
this.scheduleHeroDeath(entity);
}