Files
heros/assets/script/game/hero/HeroAtk.ts
panw 8e0d09fc98 refactor(战斗系统): 优化伤害计算与技能释放逻辑,下一步 将伤害信标处理,改为队列处理
- 移除HeroViewComp中的调试日志
- 缩短技能释放前摇时间从0.3秒到0.1秒
- 重构Skill类,清理无用导入并优化属性传递
- 改进HeroAtkSystem,添加伤害数据深拷贝避免重复处理
- 完善SkillView,增加技能结束类型处理并优化伤害应用逻辑
2025-10-31 16:43:27 +08:00

284 lines
8.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { FacSet } from "../common/config/BoxSet";
import { Attrs } from "../common/config/HeroAttrs";
import { FightSet } from "../common/config/Mission";
import { SkillSet } from "../common/config/SkillSet";
import { DmgDataCom } from "../skill/SDataCom";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp";
/** 业务层对象 */
@ecs.register('HeroAtk')
export class HeroAtkComp extends ecs.Comp {
/** 业务层组件移除时,重置所有数据为默认值 */
reset() {
}
}
interface FDData{
damage:number,
isCrit:boolean,
isDodge:boolean,
}
/** 业务层业务逻辑处理对象 伤害处理系统 */
@ecs.register('HeroAtkSystem')
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate, ecs.IEntityEnterSystem {
private debugMode: boolean = false; // 是否启用调试模式
/**
* 过滤器:只处理拥有伤害数据的实体
*/
filter(): ecs.IMatcher {
return ecs.allOf(HeroAttrsComp, DmgDataCom);
}
/**
* 实体首次进入系统时调用(每个实体只调用一次)
*/
entityEnter(e: ecs.Entity): void {
const model = e.get(HeroAttrsComp);
const dmgData = e.get(DmgDataCom);
if (!model || !dmgData) return;
const caster = dmgData.caster;
// 深度拷贝伤害数据,避免组件移除后数据丢失
const dmgDataCopy = this.deepCopyDmgData(dmgData);
// 立即移除组件,避免重复处理
e.remove(DmgDataCom);
// 使用拷贝的数据进行伤害计算
let FDData = this.doAttack(e, dmgDataCopy);
console.log(`[HeroAtkSystem] 英雄${model.hero_name} (uuid: ${model.hero_uuid}) 受到 ${caster.ent.get(HeroAttrsComp).hero_name}(uuid: ${caster.ent.get(HeroAttrsComp).hero_uuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击技能ID ${dmgDataCopy.s_uuid}`);
}
/**
* 深度拷贝伤害数据
*/
private deepCopyDmgData(dmgData: DmgDataCom): any {
return {
Attrs: dmgData.Attrs ? { ...dmgData.Attrs } : null,
s_uuid: dmgData.s_uuid
};
}
/**
* 处理角色被攻击
* @param target 被攻击的目标实体
* @param dmgData 伤害数据(可以是组件或拷贝的对象)
* @returns 实际造成的伤害
*/
public doAttack(target: ecs.Entity, dmgDataCopy: any): FDData {
const targetModel = target.get(HeroAttrsComp);
const targetView = target.get(HeroViewComp);
let reDate:FDData={
damage:0,
isCrit:false,
isDodge:false,
}
if (!targetModel || targetModel.is_dead) return reDate;
// 获取技能配置
const skillConf = SkillSet[dmgDataCopy.s_uuid];
if (!skillConf) return reDate;
// 触发被攻击事件
this.onAttacked(target);
// 闪避判定
if (this.checkDodge(targetModel)) {
// TODO: 触发闪避视图表现
reDate.isDodge=true;
return reDate;
}
// 暴击判定
const isCrit = this.checkCrit(targetModel.Attrs[Attrs.CRITICAL]);
let damage = this.dmgCount(dmgDataCopy.Attrs,dmgDataCopy.s_uuid);
if (isCrit) {
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + targetModel.Attrs[Attrs.CRITICAL_DMG]) / 100));
reDate.isCrit=true;
}
// 伤害计算考虑易伤等debuff
damage = this.calculateDamage(targetModel, damage);
// 护盾吸收
damage =Math.floor(this.absorbShield(targetModel, damage))
if (damage <= 0) return reDate;
// 应用伤害到数据层
targetModel.hp -= damage;
targetModel.atked_count++;
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
if (targetView) {
targetView.do_atked(damage, isCrit, dmgDataCopy.s_uuid);
}
// 检查死亡
if (targetModel.hp <= 0) {
this.doDead(target);
// ✅ 触发死亡视图表现
if (targetView) {
targetView.do_dead();
}
}
if (this.debugMode) {
console.log(`[HeroAtkSystem] ${targetModel.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
}
reDate.damage=damage;
return reDate;
}
//伤害计算,暂时简单计算
private dmgCount(CAttrs:any,s_uuid:number){
let sConf = SkillSet[s_uuid];
if (!sConf) return 0;
let AP = sConf.ap*CAttrs[Attrs.AP]/100;
return AP;
}
/**
* 处理角色死亡
*/
private doDead(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp);
if (!model || model.is_dead) return;
model.is_dead = true;
// 触发死亡事件
this.onDeath(entity);
if (this.debugMode) {
console.log(`[HeroBattleSystem] ${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 {
if (critRate > 0) {
const random = Math.random() * 100;
return random < critRate;
}
return false;
}
/**
* 伤害计算考虑易伤等debuff
*/
private calculateDamage(model: HeroAttrsComp, baseDamage: number): number {
// 这里可以添加易伤等debuff的计算逻辑
// 例如如果目标有易伤buff增加受到的伤害
return baseDamage;
}
/**
* 护盾吸收伤害
*/
private absorbShield(model: HeroAttrsComp, damage: number): number {
if (model.shield <= 0) return damage;
if (model.shield >= damage) {
model.shield -= damage;
if (model.shield <= 0) {
model.shield = 0;
model.Attrs[Attrs.SHIELD_MAX] = 0;
}
return 0;
} else {
const remainingDamage = damage - model.shield;
model.shield = 0;
model.Attrs[Attrs.SHIELD_MAX] = 0;
return remainingDamage;
}
}
/**
* 被攻击时触发的事件
*/
private onAttacked(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp);
if (!model || model.is_dead) return;
// 这里可以添加被攻击时的特殊处理逻辑
if (model.fac === FacSet.MON) return;
// 例如:触发某些天赋效果、反击逻辑等
}
/**
* 死亡时触发的事件
*/
private onDeath(entity: ecs.Entity): void {
const model = entity.get(HeroAttrsComp);
if (!model) return;
if (model.fac === FacSet.MON) {
// 怪物死亡处理
this.scheduleDrop(entity);
} else if (model.fac === FacSet.HERO) {
// 英雄死亡处理
this.scheduleHeroDeath(entity);
}
}
/**
* 延迟执行掉落逻辑
*/
private scheduleDrop(entity: ecs.Entity): void {
// 这里可以添加掉落逻辑
// 例如:延迟一段时间后生成掉落物品
}
/**
* 延迟执行英雄死亡逻辑
*/
private scheduleHeroDeath(entity: ecs.Entity): void {
// 这里可以添加英雄死亡的特殊处理
// 例如:触发游戏结束、复活机制等
}
/**
* 启用调试模式
*/
enableDebug() {
this.debugMode = true;
}
/**
* 禁用调试模式
*/
disableDebug() {
this.debugMode = false;
}
/**
* 系统更新(每帧调用)
* 可以在这里添加需要每帧处理的战斗逻辑
*/
update(e: ecs.Entity): void {
// 这里可以添加需要每帧处理的战斗逻辑
// 例如:持续伤害、战斗状态检查等
}
}