refactor(monster): 重构波次怪物管理逻辑,优化配置与流程
1. 更新怪物配置注释,修正近战/远程怪物的描述与分类 2. 移除MissionComp中过时的自适应刷怪逻辑 3. 重构MissionMonComp:删除插队刷怪队列、简化波次流程、统一怪物生成逻辑 4. 移除冗余日志与注释,优化代码可读性 5. 调整波次准备阶段的怪物生成时机与数据处理
This commit is contained in:
@@ -381,40 +381,40 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
*/
|
||||
|
||||
|
||||
// 基础怪物 (全部远程攻击,HType仅决定站位)
|
||||
// 近战位怪物 (站在前排,承受更多伤害) — v5: TD节奏CD,多而弱爽感设计
|
||||
// 基础怪物 (全部固定点位站桩攻击,HType仅决定是前排还是后排)
|
||||
// 前排怪物 (站在前排,承受更多伤害) — v5: TD节奏CD,多而弱爽感设计
|
||||
6001:{uuid:6001,name:"兽人战士",path:"m1", fac:FacSet.MON,lv:1,type:HType.Melee,hp:220,ap:10,speed:70,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"基础近战位怪"},
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"基础前排怪"},
|
||||
6002:{uuid:6002,name:"兽人精锐战士",path:"m2", fac:FacSet.MON,lv:1,type:HType.Melee,hp:300,ap:14,speed:110,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow2].cd,ccd:0}},info:"进阶近战位怪,更快更痛"},
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow2].cd,ccd:0}},info:"进阶前排怪,更快更痛"},
|
||||
6003:{uuid:6003,name:"兽人重装兵",path:"m3", fac:FacSet.MON,lv:1,type:HType.Melee,hp:850,ap:20,speed:50,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"重型坦克怪,高HP慢攻"},
|
||||
// 远程位怪物 (站在后排,输出更高)
|
||||
// 后排怪物 (站在后排,输出更高)
|
||||
6004:{uuid:6004,name:"兽人射手",path:"m4", fac:FacSet.MON,lv:1,type:HType.Long,hp:190,ap:35,speed:70,
|
||||
skills:{6008:{uuid:6008,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"远程高DPS怪"},
|
||||
skills:{6008:{uuid:6008,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"后排高DPS怪"},
|
||||
6005:{uuid:6005,name:"兽人刺客",path:"m5", fac:FacSet.MON,lv:1,type:HType.Long,hp:210,ap:38,speed:130,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow2].cd,ccd:0}},info:"高AP快速攻击刺客"},
|
||||
// 特殊位怪物
|
||||
6006:{uuid:6006,name:"骷髅领主",path:"m6", fac:FacSet.MON,lv:1,type:HType.Melee,hp:5000,ap:20,speed:60,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"MiniBoss级坦克"},
|
||||
6007:{uuid:6007,name:"兽人术士",path:"m7", fac:FacSet.MON,lv:1,type:HType.Melee,hp:300,ap:24,speed:70,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"法师怪,远程魔法攻击"},
|
||||
6008:{uuid:6008,name:"兽人火法",path:"m8", fac:FacSet.MON,lv:1,type:HType.Melee,hp:270,ap:32,speed:70,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow2].cd,ccd:0}},info:"高输出法师怪"},
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"前排MiniBoss级坦克"},
|
||||
6007:{uuid:6007,name:"兽人术士",path:"m7", fac:FacSet.MON,lv:1,type:HType.Long,hp:300,ap:24,speed:70,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"后排法师怪,魔法攻击"},
|
||||
6008:{uuid:6008,name:"兽人火法",path:"m8", fac:FacSet.MON,lv:1,type:HType.Long,hp:270,ap:32,speed:70,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow2].cd,ccd:0}},info:"后排高输出法师怪"},
|
||||
|
||||
// BOSS怪物 — Boss节奏1.2-1.5s,删除不存在的6206技能
|
||||
6101:{uuid:6101,name:"兽人首领-双刀战士",path:"mb1", fac:FacSet.MON,lv:6,type:HType.Long,hp:1900,ap:30,speed:120,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"远程Boss,高攻速"},
|
||||
6101:{uuid:6101,name:"兽人首领-双刀战士",path:"mb1", fac:FacSet.MON,lv:6,type:HType.Melee,hp:1900,ap:30,speed:120,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"前排Boss,高攻速"},
|
||||
6102:{uuid:6102,name:"兽人首领-斧头战士",path:"mb2", fac:FacSet.MON,lv:6,type:HType.Melee,hp:7500,ap:26,speed:60,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"近战Boss,超高HP"},
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"前排Boss,超高HP"},
|
||||
6103:{uuid:6103,name:"兽人首领-魔法师",path:"mb3", fac:FacSet.MON,lv:6,type:HType.Long,hp:2250,ap:38,speed:110,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow2].cd,ccd:0}},info:"远程法系Boss,高AP"},
|
||||
6104:{uuid:6104,name:"兽人首领-射手",path:"mb4", fac:FacSet.MON,lv:6,type:HType.Melee,hp:6800,ap:30,speed:70,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"近战位Boss,均衡型"},
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow2].cd,ccd:0}},info:"后排法系Boss,高AP"},
|
||||
6104:{uuid:6104,name:"兽人首领-射手",path:"mb4", fac:FacSet.MON,lv:6,type:HType.Long,hp:6800,ap:30,speed:70,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"后排位Boss,均衡型"},
|
||||
6105:{uuid:6105,name:"亡灵首领-法师",path:"mb5", fac:FacSet.MON,lv:6,type:HType.Long,hp:2600,ap:42,speed:110,
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"远程高AP Boss"},
|
||||
skills:{6103:{uuid:6103,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"后排高AP Boss"},
|
||||
6106:{uuid:6106,name:"亡灵首领-骑马战士",path:"mb6", fac:FacSet.MON,lv:6,type:HType.Melee,hp:9000,ap:26,speed:130,
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"终极Boss,最高HP+高速"},
|
||||
skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow3].cd,ccd:0}},info:"前排终极Boss,最高HP+高速"},
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -856,11 +856,6 @@ export class MissionComp extends CCComp {
|
||||
// 怪物全灭检测:如果战斗阶段场上没有任何活着的怪物,且待刷新的怪物队列也为空,直接结束战斗进入下一波的准备阶段
|
||||
const pendingCount = smc.vmdata.mission_data.pending_mon_num || 0;
|
||||
if (monsterCount === 0 && pendingCount === 0 && smc.mission.play && !smc.mission.pause && this.currentPhase === MissionPhase.Battle) {
|
||||
let heroesAliveRatio = heroCount / 6.0; // 假设最大 6 个站位,或者直接基于存活数算比例
|
||||
// 如果能获取当前已部署英雄数最好,这里简化处理,大于 4 个就算高存活
|
||||
heroesAliveRatio = Math.min(1.0, heroCount / 4.0);
|
||||
spawningEngine.updateAdaptive(heroesAliveRatio, this.clearTime);
|
||||
|
||||
if (this.currentWave >= 15) {
|
||||
// 15 波通关
|
||||
this.open_Victory(null, false);
|
||||
|
||||
@@ -3,27 +3,13 @@
|
||||
* @description 怪物(Monster)波次刷新管理组件(逻辑层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 管理每一波怪物的 **生成计划**:根据 WaveSlotConfig 生成怪物。
|
||||
* 2. 处理特殊插队刷怪请求(MonQueue),优先于常规刷新。
|
||||
* 3. 自动推进波次:当前波所有怪物被清除后自动进入下一波。
|
||||
* 1. 管理每一波怪物的生成计划:根据 RogueConfig 生成怪物。
|
||||
* 2. 自动推进波次:在准备阶段结束时(PhasePrepareEnd)统一刷出怪物。
|
||||
*
|
||||
* 关键设计:
|
||||
* - 突破 5 槽限制,怪物按刷怪顺序依次从 X=280 开始向右(每隔 50)排布。
|
||||
* - 6 条刷怪线:在三路 Y 轴范围内随机偏移,实现 6 路进军。
|
||||
* - resetSlotSpawnData(wave) 在每波开始时读取配置,分配并立即生成所有怪物。
|
||||
* - 去除跨波 HP 继承,上一波残留怪在波次结束/开始时销毁。
|
||||
*
|
||||
* 怪物属性计算公式:
|
||||
* ap = floor((base_ap + stage × grow_ap) × SpawnPowerBias)
|
||||
* hp = floor((base_hp + stage × grow_hp) × SpawnPowerBias)
|
||||
* 其中 stage = currentWave - 1
|
||||
*
|
||||
* 依赖:
|
||||
* - RogueConfig —— 怪物类型、成长值、波次配置
|
||||
* - Monster(hero/Mon.ts)—— 怪物 ECS 实体类
|
||||
* - HeroInfo(heroSet)—— 怪物基础属性配置(与英雄共用配置)
|
||||
* - HeroAttrsComp / MonMoveComp —— 怪物属性和移动组件
|
||||
* - BoxSet.GAME_LINE —— 地面基准 Y 坐标
|
||||
* - 采用 12 个硬编码的网格位置点 (MON_POSITIONS,3行x4列)
|
||||
* - 每次生成最多 12 个怪物,固定在位置点。
|
||||
* - 上一波残留怪在波次结束/开始时统一清理。
|
||||
*/
|
||||
import { _decorator, v3, Vec3 } from "cc";
|
||||
import { mLogger } from "../common/Logger";
|
||||
@@ -31,21 +17,15 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||
import { Monster } from "../hero/Mon";
|
||||
import { HeroInfo, HType } from "../common/config/heroSet";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import {BoxSet, FacSet } from "../common/config/GameSet";
|
||||
import { spawningEngine, GeneratedMonster, AffixType, MonType, MonList, TestModeConfig } from "./RogueConfig";
|
||||
import { BoxSet, FacSet } from "../common/config/GameSet";
|
||||
import { spawningEngine, GeneratedMonster, TestModeConfig } from "./RogueConfig";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { MonMoveComp } from "../hero/MonMoveComp";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* MissionMonCompComp —— 怪物波次刷新管理器
|
||||
*
|
||||
* 每波开始时根据 WaveSlotConfig 配置生成怪物,
|
||||
* 战斗中监控数量,所有怪物消灭后自动推进到下一波。
|
||||
*/
|
||||
@ccclass('MissionMonCompComp')
|
||||
@ecs.register('MissionMonComp', false)
|
||||
export class MissionMonCompComp extends CCComp {
|
||||
@@ -81,83 +61,32 @@ export class MissionMonCompComp extends CCComp {
|
||||
@property({ tooltip: "是否启用调试日志" })
|
||||
private debugMode: boolean = false;
|
||||
|
||||
// ======================== 插队刷怪队列 ========================
|
||||
|
||||
/**
|
||||
* 刷怪队列(优先于常规配置处理):
|
||||
* 用于插队生成(如运营活动怪、技能召唤怪、剧情强制怪)。
|
||||
*/
|
||||
private MonQueue: Array<{
|
||||
/** 怪物 UUID */
|
||||
uuid: number,
|
||||
/** 怪物等级 */
|
||||
level: number,
|
||||
/** 飞行层 */
|
||||
flyLane: number,
|
||||
}> = [];
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 全局生成顺序计数器(用于渲染层级排序) */
|
||||
private globalSpawnOrder: number = 0;
|
||||
/** 插队刷怪处理计时器 */
|
||||
private queueTimer: number = 0;
|
||||
/** 当前波数 */
|
||||
private currentWave: number = 0;
|
||||
/** 当前波的目标怪物总数 */
|
||||
private waveTargetCount: number = 0;
|
||||
/** 当前波已生成的怪物数量 */
|
||||
private waveSpawnedCount: number = 0;
|
||||
/** 等待生成的怪物队列(由新肉鸽引擎提供) */
|
||||
/** 等待生成的怪物队列 */
|
||||
private pendingMonsters: GeneratedMonster[] = [];
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
onLoad(){
|
||||
this.on(GameEvent.FightReady,this.fight_ready,this)
|
||||
this.on("SpawnSpecialMonster", this.onSpawnSpecialMonster, this);
|
||||
onLoad() {
|
||||
this.on(GameEvent.FightReady, this.fight_ready, this);
|
||||
this.on("PhasePrepareEnd", this.onPhasePrepareEnd, this);
|
||||
this.on("TimeUpAdvanceWave", this.onTimeUpAdvanceWave, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 帧更新:
|
||||
* 1. 检查游戏是否运行中。
|
||||
* 2. 处理插队刷怪队列。
|
||||
* 3. 逐步从 pendingMonsters 队列中生成怪物(受 stop_spawn_mon 限制)。
|
||||
*/
|
||||
protected update(dt: number): void {
|
||||
smc.vmdata.mission_data.pending_mon_num = this.pendingMonsters.length;
|
||||
|
||||
if(!smc.mission.play) return
|
||||
if(smc.mission.pause) return
|
||||
if(smc.mission.stop_mon_action) return;
|
||||
if(!smc.mission.in_fight) return;
|
||||
|
||||
this.updateSpecialQueue(dt);
|
||||
}
|
||||
|
||||
// ======================== 事件处理 ========================
|
||||
|
||||
/**
|
||||
* 接收特殊刷怪事件并入队。
|
||||
* @param event 事件名
|
||||
* @param args { uuid: number, level: number, flyLane?: number }
|
||||
*/
|
||||
private onSpawnSpecialMonster(event: string, args: any) {
|
||||
if (!args) return;
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', `[MissionMonComp] 收到特殊刷怪指令:`, args);
|
||||
this.MonQueue.push({
|
||||
uuid: args.uuid,
|
||||
level: args.level,
|
||||
flyLane: args.flyLane || 0
|
||||
});
|
||||
// 加速队列消费
|
||||
this.queueTimer = 1.0;
|
||||
}
|
||||
|
||||
start() {
|
||||
}
|
||||
start() {}
|
||||
|
||||
private setupWaveData(monsters: GeneratedMonster[]) {
|
||||
this.pendingMonsters = monsters.slice(0, MissionMonCompComp.MAX_MONSTERS);
|
||||
@@ -166,9 +95,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
let hasBoss = monsters.some(m => m.isBoss);
|
||||
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 生成怪物总数: ${this.waveTargetCount}`);
|
||||
const uuids = monsters.map(m => m.uuid);
|
||||
console.log(`[MissionMonComp] 波次 ${this.currentWave} 怪物 UUID 列表:`, uuids);
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', `[MissionMonComp] 波次 ${this.currentWave} 生成怪物总数: ${this.waveTargetCount}`);
|
||||
|
||||
oops.message.dispatchEvent(GameEvent.NewWave, {
|
||||
wave: this.currentWave,
|
||||
@@ -180,81 +107,41 @@ export class MissionMonCompComp extends CCComp {
|
||||
/**
|
||||
* 战斗准备:重置所有运行时状态并开始第一波。
|
||||
*/
|
||||
fight_ready(){
|
||||
smc.vmdata.mission_data.mon_num=0
|
||||
smc.mission.stop_spawn_mon = false
|
||||
this.globalSpawnOrder = 0
|
||||
this.queueTimer = 0
|
||||
this.currentWave = 1
|
||||
this.waveTargetCount = 0
|
||||
this.waveSpawnedCount = 0
|
||||
this.MonQueue = []
|
||||
this.pendingMonsters = []
|
||||
fight_ready() {
|
||||
smc.vmdata.mission_data.mon_num = 0;
|
||||
smc.mission.stop_spawn_mon = false;
|
||||
this.globalSpawnOrder = 0;
|
||||
this.currentWave = 1;
|
||||
this.waveTargetCount = 0;
|
||||
this.waveSpawnedCount = 0;
|
||||
this.pendingMonsters = [];
|
||||
|
||||
// 预生成第一波数据以获取数量和 Boss 信息
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
this.setupWaveData(monsters);
|
||||
|
||||
// 如果处于测试模式,英雄也需要限制为只产出一个,这部分通知可以配合使用
|
||||
if (TestModeConfig.enable) {
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] 测试模式已开启:每波仅生成1只基准怪物");
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] 测试模式已开启");
|
||||
}
|
||||
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System");
|
||||
}
|
||||
|
||||
// ======================== 插队刷怪 ========================
|
||||
|
||||
/**
|
||||
* 处理插队刷怪队列(每 0.15 秒尝试消费一个):
|
||||
* 1. 找到后从队列中移除并生成怪物。
|
||||
*/
|
||||
private updateSpecialQueue(dt: number) {
|
||||
if (this.MonQueue.length <= 0) return;
|
||||
this.queueTimer += dt;
|
||||
if (this.queueTimer < 0.15) return;
|
||||
|
||||
const item = this.MonQueue.shift()!;
|
||||
this.queueTimer = 0;
|
||||
|
||||
const isBoss = MonList[MonType.MeleeBoss].includes(item.uuid) ||
|
||||
MonList[MonType.LongBoss].includes(item.uuid);
|
||||
|
||||
const spawnIndex = this.waveSpawnedCount++;
|
||||
const targetPosIndex = spawnIndex % MissionMonCompComp.MAX_MONSTERS;
|
||||
|
||||
// 构造一个模拟的 GeneratedMonster 数据传递给 addMonsterAtGrid
|
||||
const base = HeroInfo[item.uuid];
|
||||
const monData: GeneratedMonster = {
|
||||
uuid: item.uuid,
|
||||
type: MonType.Melee, // 简化的兜底,真实逻辑依赖 heroSet 配置
|
||||
hp: base ? base.hp : 100,
|
||||
ap: base ? base.ap : 10,
|
||||
affixes: [],
|
||||
isBoss: isBoss,
|
||||
spawnIndex: 0
|
||||
};
|
||||
this.addMonsterAtGrid(targetPosIndex, monData, item.level);
|
||||
}
|
||||
|
||||
// ======================== 波次管理 ========================
|
||||
|
||||
/**
|
||||
* 开始下一波:
|
||||
* 1. 波数 +1 并更新全局数据。
|
||||
* 2. 分发 NewWave 事件(实际的生成在 resetSlotSpawnData 中触发)。
|
||||
* 开始下一波:波数 +1 并预生成数据
|
||||
*/
|
||||
private onTimeUpAdvanceWave() {
|
||||
this.currentWave += 1;
|
||||
smc.vmdata.mission_data.level = this.currentWave;
|
||||
|
||||
// 预生成新一波数据以获取数量和 Boss 信息
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
this.setupWaveData(monsters);
|
||||
}
|
||||
|
||||
private onPhasePrepareEnd() {
|
||||
this.resetSlotSpawnData(this.currentWave);
|
||||
this.resetSlotSpawnData();
|
||||
|
||||
// 准备结束阶段,立即刷出本波所有怪物
|
||||
if (this.pendingMonsters.length > 0) {
|
||||
@@ -262,11 +149,9 @@ export class MissionMonCompComp extends CCComp {
|
||||
for (let i = 0; i < count; i++) {
|
||||
const monData = this.pendingMonsters.shift()!;
|
||||
const targetPosIndex = this.waveSpawnedCount % MissionMonCompComp.MAX_MONSTERS;
|
||||
console.log(`[MissionMonComp] [PhasePrepareEnd] 准备生成怪物 UUID=${monData.uuid}, 当前已生成数量=${this.waveSpawnedCount}`);
|
||||
this.addMonsterAtGrid(targetPosIndex, monData);
|
||||
this.addMonsterAtGrid(targetPosIndex, monData, this.currentWave);
|
||||
this.waveSpawnedCount++;
|
||||
}
|
||||
// 生成完毕后清空 pendingMonsters
|
||||
this.pendingMonsters = [];
|
||||
}
|
||||
}
|
||||
@@ -274,14 +159,9 @@ export class MissionMonCompComp extends CCComp {
|
||||
// ======================== 槽位管理 ========================
|
||||
|
||||
/**
|
||||
* 重新分配本波所有怪物状态:
|
||||
* 1. 清理上一波残留怪物。
|
||||
* 2. pendingMonsters 已在 onTimeUpAdvanceWave / fight_ready 中准备好。
|
||||
*
|
||||
* @param wave 当前波数
|
||||
* 清理上一波残留怪物,并重置生成计数
|
||||
*/
|
||||
private resetSlotSpawnData(wave: number = 1) {
|
||||
// 1. 清理上一波残留怪物
|
||||
private resetSlotSpawnData() {
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach(e => {
|
||||
const attrs = e.get(HeroAttrsComp);
|
||||
if (attrs && attrs.fac === FacSet.MON && !attrs.is_dead) {
|
||||
@@ -289,18 +169,13 @@ export class MissionMonCompComp extends CCComp {
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 重置排号索引
|
||||
this.waveSpawnedCount = 0;
|
||||
}
|
||||
|
||||
// ======================== 怪物生成 ========================
|
||||
|
||||
/**
|
||||
* 在指定位置索引处生成一个怪物:
|
||||
*
|
||||
* @param posIndex 位置索引 (0-11)
|
||||
* @param monData 新引擎生成的怪物数据 (含 uuid, hp, ap, affixes 等)
|
||||
* @param monLv 怪物等级 (仅对旧有的 level 参数做兼容,实际属性由 monData 决定)
|
||||
* 在指定位置索引处生成一个怪物
|
||||
*/
|
||||
private addMonsterAtGrid(
|
||||
posIndex: number,
|
||||
@@ -310,51 +185,32 @@ export class MissionMonCompComp extends CCComp {
|
||||
let mon = ecs.getEntity<Monster>(Monster);
|
||||
let scale = -1;
|
||||
|
||||
// 获取硬编码的占位点坐标,不再使用随机偏移
|
||||
const basePos = MissionMonCompComp.MON_POSITIONS[posIndex % MissionMonCompComp.MON_POSITIONS.length];
|
||||
const spawnX = basePos.x;
|
||||
const landingY = basePos.y + (monData.isBoss ? 6 : 0);
|
||||
const spawnPos: Vec3 = v3(spawnX, landingY + MissionMonCompComp.MON_DROP_HEIGHT, 0);
|
||||
this.globalSpawnOrder = (this.globalSpawnOrder + 1) % 999;
|
||||
|
||||
// 如果存在测试技能覆盖,则传递下去(修改 mon.load 逻辑或者通过预存)
|
||||
// 为了避免侵入 Mon.ts 的原有逻辑,我们先预存
|
||||
if (monData.testSkills) {
|
||||
(mon as any)._testSkills = monData.testSkills;
|
||||
}
|
||||
|
||||
mon.load(spawnPos, scale, monData.uuid, monData.isBoss, landingY, monLv, posIndex);
|
||||
|
||||
// 设置渲染排序
|
||||
const move = mon.get(MonMoveComp);
|
||||
if (move) {
|
||||
move.spawnOrder = this.globalSpawnOrder;
|
||||
}
|
||||
|
||||
// 应用新引擎计算好的最终属性和词缀
|
||||
// 应用新引擎计算好的最终属性
|
||||
const model = mon.get(HeroAttrsComp);
|
||||
if (!model) return;
|
||||
if (model) {
|
||||
model.ap = monData.ap;
|
||||
model.hp_max = monData.hp;
|
||||
model.hp = model.hp_max;
|
||||
|
||||
// 将词缀记录到属性组件上,供战斗层使用
|
||||
(model as any).affixes = monData.affixes || [];
|
||||
|
||||
// 解析特定的抗性词缀
|
||||
if (monData.affixes) {
|
||||
if (monData.affixes.includes(AffixType.CritRes)) {
|
||||
model.critical_res = 50;
|
||||
}
|
||||
if (monData.affixes.includes(AffixType.FreezeRes)) {
|
||||
model.freeze_res = 50;
|
||||
}
|
||||
if (monData.affixes.includes(AffixType.KnockbackRes)) {
|
||||
model.knockback_res = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ECS 组件移除时触发(当前不销毁节点) */
|
||||
reset() {
|
||||
// this.node.destroy();
|
||||
}
|
||||
/** ECS 组件移除时触发 */
|
||||
reset() {}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user