304 lines
9.3 KiB
TypeScript
304 lines
9.3 KiB
TypeScript
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||
import { FacSet } from "../common/config/GameSet";
|
||
import { Attrs } from "../common/config/HeroAttrs";
|
||
import { FightSet } from "../common/config/GameSet";
|
||
import { SkillSet } from "../common/config/SkillSet";
|
||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||
import { HeroViewComp } from "./HeroViewComp";
|
||
import { DamageQueueComp, DamageEvent, DamageQueueHelper } from "./DamageQueueComp";
|
||
import { smc } from "../common/SingletonModuleComp";
|
||
|
||
/** 业务层对象 */
|
||
@ecs.register('HeroAtk')
|
||
export class HeroAtkComp extends ecs.Comp {
|
||
/** 业务层组件移除时,重置所有数据为默认值 */
|
||
reset() {
|
||
|
||
}
|
||
}
|
||
/** 最终伤害数据接口 */
|
||
interface FinalData {
|
||
damage: number;
|
||
isCrit: boolean;
|
||
isDodge: boolean;
|
||
}
|
||
/** 业务层业务逻辑处理对象 伤害处理系统 */
|
||
@ecs.register('HeroAtkSystem')
|
||
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||
|
||
private debugMode: boolean = false; // 是否启用调试模式
|
||
|
||
/**
|
||
* 过滤器:处理拥有伤害队列的实体
|
||
*/
|
||
filter(): ecs.IMatcher {
|
||
return ecs.allOf(HeroAttrsComp, DamageQueueComp);
|
||
}
|
||
|
||
/**
|
||
* 系统更新(每帧调用)
|
||
* 处理伤害队列中的所有伤害事件
|
||
*/
|
||
update(e: ecs.Entity): void {
|
||
if(!smc.mission.play || smc.mission.pause) return;
|
||
const model = e.get(HeroAttrsComp);
|
||
const damageQueue = e.get(DamageQueueComp);
|
||
|
||
if (!model || !damageQueue || damageQueue.isEmpty()) return;
|
||
|
||
// 标记正在处理
|
||
damageQueue.isProcessing = true;
|
||
|
||
// 处理队列中的所有伤害事件
|
||
let processedCount = 0;
|
||
while (!damageQueue.isEmpty()) {
|
||
const damageEvent = damageQueue.getNextDamageEvent();
|
||
if (!damageEvent) break;
|
||
|
||
// 处理单个伤害事件
|
||
const FDData = this.doAttack(e, damageEvent);
|
||
processedCount++;
|
||
damageQueue.processedCount++;
|
||
|
||
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}`);
|
||
}
|
||
|
||
// 如果目标已死亡,停止处理后续伤害
|
||
if (model.is_dead) {
|
||
if (this.debugMode) {
|
||
console.log(`[HeroAtkSystem] ${model.hero_name} 已死亡,停止处理剩余伤害`);
|
||
}
|
||
damageQueue.clear(); // 清空剩余伤害
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 如果队列已空,移除伤害队列组件
|
||
if (damageQueue.isEmpty()) {
|
||
e.remove(DamageQueueComp);
|
||
|
||
if (this.debugMode && processedCount > 0) {
|
||
console.log(`[HeroAtkSystem] ${model.hero_name} 伤害队列处理完成,共处理 ${processedCount} 个伤害事件`);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 执行攻击计算
|
||
* @param target 目标实体
|
||
* @param damageEvent 伤害事件数据
|
||
* @returns 最终伤害数据
|
||
*/
|
||
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
|
||
const targetModel = target.get(HeroAttrsComp);
|
||
const targetView = target.get(HeroViewComp);
|
||
let reDate:FinalData={
|
||
damage:0,
|
||
isCrit:false,
|
||
isDodge:false,
|
||
}
|
||
if (!targetModel || targetModel.is_dead) return reDate;
|
||
|
||
// 获取攻击者数据
|
||
const caster = damageEvent.caster;
|
||
|
||
// 获取技能配置
|
||
const skillConf = SkillSet[damageEvent.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(damageEvent.Attrs,damageEvent.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, damageEvent.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;
|
||
}
|
||
|
||
|
||
} |