Files
heros/assets/script/game/hero/HeroAtk.ts
2025-11-01 15:02:31 +08:00

306 lines
9.4 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 { 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 casterModel = caster.ent.get(HeroAttrsComp);
if (!casterModel) return reDate;
// 获取技能配置
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;
}
}