refactor: 重构关卡经济与战斗流程
1. 移除战斗阶段限制,允许玩家在战斗中操作卡牌 2. 新增波次间5秒自动倒计时机制 3. 将固定波次金币奖励改为怪物死亡掉落 4. 重构卡牌面板逻辑,统一抽卡按钮状态判断 5. 清理冗余的战斗阶段状态变量与相关代码
This commit is contained in:
@@ -15,6 +15,8 @@ import { FieldSkillType } from "../common/config/SkillSet";
|
||||
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { SkillTriggerHelper } from "./SkillTriggerHelper";
|
||||
import { getMonsterGoldDrop } from "../map/RogueConfig";
|
||||
import { MissionEconomy } from "../map/MissionEconomy";
|
||||
|
||||
/** 最终伤害数据接口
|
||||
* 用于封装一次攻击计算的所有结果数据
|
||||
@@ -39,8 +41,8 @@ interface FinalData {
|
||||
* - 属性来源规范:攻击判定用施法者,防御判定用被攻击者
|
||||
*/
|
||||
@ecs.register('HeroAtkSystem')
|
||||
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
|
||||
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
|
||||
private debugMode: boolean = false; // 是否启用调试模式
|
||||
|
||||
/**
|
||||
@@ -55,22 +57,22 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
* 处理伤害队列中的所有伤害事件
|
||||
*/
|
||||
update(e: ecs.Entity): void {
|
||||
if(!smc.mission.play ) return
|
||||
if(smc.mission.pause) return
|
||||
if (!smc.mission.play) return
|
||||
if (smc.mission.pause) return
|
||||
const TAttrsComp = e.get(HeroAttrsComp)
|
||||
const damageQueue = e.get(DamageQueueComp)
|
||||
|
||||
|
||||
if (!TAttrsComp || !damageQueue || damageQueue.isEmpty()) return;
|
||||
|
||||
|
||||
// 标记正在处理
|
||||
damageQueue.isProcessing = true;
|
||||
|
||||
|
||||
// 处理队列中的所有伤害事件
|
||||
let processedCount = 0;
|
||||
while (!damageQueue.isEmpty()) {
|
||||
const damageEvent = damageQueue.getNextDamageEvent();
|
||||
if (!damageEvent) break;
|
||||
|
||||
|
||||
// 处理单个伤害事件
|
||||
this.doAttack(e, damageEvent);
|
||||
processedCount++;
|
||||
@@ -82,11 +84,11 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 如果队列已空,移除伤害队列组件
|
||||
if (damageQueue.isEmpty()) {
|
||||
e.remove(DamageQueueComp);
|
||||
|
||||
|
||||
if (processedCount > 0) {
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` ${TAttrsComp.hero_name} 伤害队列处理完成,共处理 ${processedCount} 个伤害事件`);
|
||||
}
|
||||
@@ -109,9 +111,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
|
||||
const TAttrsComp = target.get(HeroAttrsComp);
|
||||
const targetView = target.get(HeroViewComp);
|
||||
let reDate:FinalData={
|
||||
damage:0,
|
||||
isCrit:false,
|
||||
let reDate: FinalData = {
|
||||
damage: 0,
|
||||
isCrit: false,
|
||||
}
|
||||
if (!TAttrsComp || TAttrsComp.is_dead || TAttrsComp.is_reviving) return reDate;
|
||||
|
||||
@@ -120,30 +122,30 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
// 获取技能配置
|
||||
const skillConf = SkillSet[damageEvent.s_uuid];
|
||||
if (!skillConf) return reDate;
|
||||
|
||||
|
||||
// 触发被攻击事件
|
||||
this.onAttacked(target);
|
||||
|
||||
|
||||
// 暴击判定
|
||||
// 使用施法者的暴击率属性(damageEvent.Attrs 快照),- 被攻击者的暴击抗性属
|
||||
const criticalChance = (damageEvent.Attrs[Attrs.critical] || 0) - (TAttrsComp.critical_res || 0);
|
||||
const isCrit = this.checkChance(criticalChance);
|
||||
|
||||
|
||||
// 计算基础伤害
|
||||
let damage = this.dmgCount(damageEvent,TAttrsComp);
|
||||
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " dmgCount",damage)
|
||||
let damage = this.dmgCount(damageEvent, TAttrsComp);
|
||||
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " dmgCount", damage)
|
||||
if (isCrit) {
|
||||
const critDamageBonus = damageEvent.Attrs[Attrs.critical_damage] || 0;
|
||||
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + critDamageBonus) / 100));
|
||||
reDate.isCrit=true;
|
||||
reDate.isCrit = true;
|
||||
if (damageEvent.Attrs.fac === FacSet.HERO) {
|
||||
// 【评分系统 - 输出分】统计暴击次数与暴击造成的总伤害
|
||||
smc.vmdata.scores.crt_count++;
|
||||
smc.vmdata.scores.crit_dmg_total += damage;
|
||||
}
|
||||
}
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " after crit",damage)
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " after crit", damage)
|
||||
// 护盾吸收
|
||||
const shieldResult = this.absorbShield(TAttrsComp, damage);
|
||||
damage = shieldResult.remainingDamage;
|
||||
@@ -151,16 +153,16 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
// 【评分系统 - 防御分】统计护盾成功抵挡伤害的次数
|
||||
smc.vmdata.scores.shield_block_count += shieldResult.absorbedDamage;
|
||||
}
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " after shield",damage)
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " after shield", damage)
|
||||
// 显示护盾吸收飘字
|
||||
if (shieldResult.absorbedDamage > 0 && targetView) {
|
||||
targetView.shield_tip(shieldResult.absorbedDamage);
|
||||
}
|
||||
if (damage <= 0) return reDate;
|
||||
|
||||
|
||||
// TAttrsComp.hp -= damage; // 应用伤害到数据层
|
||||
TAttrsComp.add_hp(-damage); // 使用 add_hp 以触发 dirty_hp 和 UI 更新
|
||||
|
||||
|
||||
if (damageEvent.Attrs.fac === FacSet.HERO) {
|
||||
// 【评分系统 - 输出分】统计团队造成的总伤害以及单次最高伤害记录
|
||||
smc.vmdata.scores.total_dmg += damage;
|
||||
@@ -168,7 +170,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
smc.vmdata.scores.highest_dmg = damage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 增加受击计数并触发 atked 技能
|
||||
TAttrsComp.atked_count++;
|
||||
this.checkAndTriggerAtkedSkills(TAttrsComp, targetView);
|
||||
@@ -178,12 +180,12 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
// targetView.back();
|
||||
// }
|
||||
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 英雄${TAttrsComp.hero_name} (uuid: ${TAttrsComp.hero_uuid}) 受到 eid:${casterEid} 的 伤害 ${damage},${isCrit?"暴击":"普通"}攻击,技能ID ${damageEvent.s_uuid}`);
|
||||
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 英雄${TAttrsComp.hero_name} (uuid: ${TAttrsComp.hero_uuid}) 受到 eid:${casterEid} 的 伤害 ${damage},${isCrit ? "暴击" : "普通"}攻击,技能ID ${damageEvent.s_uuid}`);
|
||||
|
||||
// 冰冻判定
|
||||
const freezeChance = (damageEvent.Attrs[Attrs.freeze_chance] || 0) - (TAttrsComp.freeze_res || 0);
|
||||
const isFrost = !TAttrsComp.isFrost() && this.checkChance(freezeChance);
|
||||
|
||||
|
||||
// 击晕判定
|
||||
const stunChance = (damageEvent.Attrs[Attrs.stun_chance] || 0) - (TAttrsComp.stun_res || 0);
|
||||
const isStun = !TAttrsComp.isStun() && this.checkChance(stunChance);
|
||||
@@ -191,9 +193,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
// 击退判定
|
||||
const knockbackChance = (damageEvent.Attrs[Attrs.knockback_chance] || 0) - (TAttrsComp.knockback_res || 0);
|
||||
const isKnockback = this.checkChance(knockbackChance);
|
||||
|
||||
|
||||
// ✅ 触发视图层表现(伤害数字、受击动画、冰冻、击晕、击退)
|
||||
if (targetView) {
|
||||
if (targetView) {
|
||||
targetView.do_atked(damage, isCrit, damageEvent.s_uuid, false);
|
||||
targetView.playEnd(skillConf.endAnm);
|
||||
if (isFrost) {
|
||||
@@ -214,8 +216,8 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
targetView.back(damageEvent.Attrs[Attrs.knockback_distance] || 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 检查死亡
|
||||
if (TAttrsComp.hp <= 0) {
|
||||
// 先触发死亡技能(如亡语),不管后续是否复活都应触发
|
||||
@@ -245,7 +247,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
// 根据技能配置恢复生命值
|
||||
TAttrsComp.hp = Math.floor(TAttrsComp.hp_max * (reviveHpPercent / 100));
|
||||
TAttrsComp.dirty_hp = true;
|
||||
|
||||
|
||||
// 触发复活动画
|
||||
if (targetView && reviveSkillConf) {
|
||||
targetView.playReady(reviveSkillConf.readyAnm);
|
||||
@@ -269,14 +271,14 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
targetView.do_dead();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` ${TAttrsComp.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
|
||||
|
||||
|
||||
reDate.damage=damage;
|
||||
|
||||
reDate.damage = damage;
|
||||
return reDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 详细伤害计算核心方法
|
||||
*
|
||||
@@ -295,23 +297,23 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
* @important 注意事项:
|
||||
|
||||
*/
|
||||
private dmgCount(damageEvent:DamageEvent,TAttrsComp:HeroAttrsComp){
|
||||
private dmgCount(damageEvent: DamageEvent, TAttrsComp: HeroAttrsComp) {
|
||||
// 1. 获取技能配置 - 如果技能不存在,直接返回0伤害
|
||||
const CAttrs=damageEvent.Attrs;
|
||||
const TAttrs=TAttrsComp;
|
||||
const CAttrs = damageEvent.Attrs;
|
||||
const TAttrs = TAttrsComp;
|
||||
let sConf = SkillSet[damageEvent.s_uuid];
|
||||
if (!sConf) return 0;
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 伤害处理对象`,CAttrs,TAttrs);
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 伤害处理对象`, CAttrs, TAttrs);
|
||||
// 2. 计算原始物理伤害和魔法伤害
|
||||
// 物理伤害基础值 = 技能物理倍率 * (施法者物理攻击力 + 额外伤害) / 100 * 额外伤害比例
|
||||
let apBase = (sConf.ap||0)*(CAttrs[Attrs.ap]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
|
||||
let apBase = (sConf.ap || 0) * (CAttrs[Attrs.ap] + damageEvent.ext_dmg) / 100 * damageEvent.dmg_ratio;
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 物理伤害基础值: ${apBase}, 技能ap=${sConf.ap},施法者物理攻击力: ${CAttrs[Attrs.ap]},}
|
||||
额外伤害:${damageEvent.ext_dmg}, 额外伤害比例:${damageEvent.dmg_ratio}`);
|
||||
|
||||
// 4. 确保伤害值非负
|
||||
let total = Math.max(0, apBase);
|
||||
|
||||
if (this.debugMode) mLogger.log(this.debugMode, 'HeroAtkSystem', ` 最终伤害: ${total} (Base: ${apBase}`);
|
||||
|
||||
if (this.debugMode) mLogger.log(this.debugMode, 'HeroAtkSystem', ` 最终伤害: ${total} (Base: ${apBase}`);
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -350,12 +352,12 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
private doDead(entity: ecs.Entity): void {
|
||||
const TAttrsComp = entity.get(HeroAttrsComp);
|
||||
if (!TAttrsComp || TAttrsComp.is_dead) return;
|
||||
|
||||
|
||||
TAttrsComp.is_dead = true;
|
||||
|
||||
|
||||
// 触发死亡事件
|
||||
this.onDeath(entity);
|
||||
|
||||
|
||||
if (this.debugMode) {
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` ${TAttrsComp.hero_name} 死亡`);
|
||||
}
|
||||
@@ -405,10 +407,10 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
* @param damage 原始伤害值
|
||||
* @returns {remainingDamage, absorbedDamage} 剩余伤害值和吸收的护盾值
|
||||
*/
|
||||
private absorbShield(TAttrsComp: HeroAttrsComp, damage: number): {remainingDamage: number, absorbedDamage: number} {
|
||||
if (TAttrsComp.shield <= 0) {
|
||||
private absorbShield(TAttrsComp: HeroAttrsComp, damage: number): { remainingDamage: number, absorbedDamage: number } {
|
||||
if (TAttrsComp.shield <= 0) {
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " 护盾值小于等于0,无法吸收伤害");
|
||||
return {remainingDamage: damage, absorbedDamage: 0};
|
||||
return { remainingDamage: damage, absorbedDamage: 0 };
|
||||
}
|
||||
TAttrsComp.shield = Math.max(0, TAttrsComp.shield - 1);
|
||||
if (TAttrsComp.shield <= 0) {
|
||||
@@ -416,7 +418,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
}
|
||||
TAttrsComp.dirty_shield = true;
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 护盾抵挡1次伤害,剩余次数 ${TAttrsComp.shield}`);
|
||||
return {remainingDamage: 0, absorbedDamage: 1};
|
||||
return { remainingDamage: 0, absorbedDamage: 1 };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,7 +439,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
TAttrsComp.atked_count++;
|
||||
// 这里可以添加被攻击时的特殊处理逻辑
|
||||
if (TAttrsComp.fac === FacSet.MON) return;
|
||||
|
||||
|
||||
// 例如:触发某些天赋效果、反击逻辑等
|
||||
}
|
||||
|
||||
@@ -462,7 +464,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
private onDeath(entity: ecs.Entity): void {
|
||||
const TAttrsComp = entity.get(HeroAttrsComp);
|
||||
if (!TAttrsComp) return;
|
||||
|
||||
|
||||
if (TAttrsComp.fac === FacSet.MON) {
|
||||
// 怪物死亡处理
|
||||
this.scheduleDrop(entity);
|
||||
@@ -473,24 +475,28 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟执行掉落逻辑
|
||||
*
|
||||
* 采用延迟执行的原因:
|
||||
* 1. 避免在伤害计算过程中阻塞主线程
|
||||
* 2. 给死亡动画播放留出时间
|
||||
* 3. 可以批量处理多个掉落,优化性能
|
||||
*
|
||||
* 怪物死亡掉落金币
|
||||
*
|
||||
* 实现说明:
|
||||
* - 通过 hero_uuid 查 HeroInfo 获取 monType
|
||||
* - 按怪物类型查 MonsterGoldSet 获取固定金币掉落数(Boss 有独立的高额奖励)
|
||||
* - 调用 MissionEconomy.addCoin 统一发放金币(会自动触发 UI 更新和评分统计)
|
||||
*
|
||||
* @param entity 死亡的怪物实体
|
||||
*
|
||||
* @todo 具体实现可以包括:
|
||||
* - 根据怪物等级计算基础掉落
|
||||
* - 幸运值影响掉落品质
|
||||
* - 特殊事件(双倍掉落、稀有掉落等)
|
||||
* - 掉落物在场景中的生成位置计算
|
||||
*/
|
||||
private scheduleDrop(entity: ecs.Entity): void {
|
||||
// 这里可以添加掉落逻辑
|
||||
// 例如:延迟一段时间后生成掉落物品
|
||||
const TAttrsComp = entity.get(HeroAttrsComp);
|
||||
if (!TAttrsComp) return;
|
||||
|
||||
// 通过 hero_uuid 查配置获取怪物类型
|
||||
const info = HeroInfo[TAttrsComp.hero_uuid];
|
||||
const monType = info?.monType ?? 0;
|
||||
const gold = getMonsterGoldDrop(monType, !!TAttrsComp.is_boss);
|
||||
if (gold <= 0) return;
|
||||
|
||||
MissionEconomy.addCoin(gold);
|
||||
mLogger.log(this.debugMode, 'HeroAtkSystem',
|
||||
` ${TAttrsComp.hero_name} 死亡掉落金币 ${gold}(monType=${monType}, isBoss=${TAttrsComp.is_boss})`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -520,7 +526,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
enableDebug() {
|
||||
this.debugMode = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 禁用调试模式
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user