docs: 为游戏地图模块添加详细的代码注释

为游戏地图模块的脚本文件添加全面的注释,说明每个组件的职责、关键设计、依赖关系和使用方式。注释覆盖了英雄信息面板、技能卡槽位管理器、排行榜弹窗、卡牌控制器、背景滚动组件等核心功能模块,提高了代码的可读性和维护性。

同时修复了英雄预制体的激活状态和技能效果预制体的尺寸参数。
This commit is contained in:
walkpan
2026-04-07 19:00:30 +08:00
parent 9a1d517aa9
commit e880613f8f
21 changed files with 1840 additions and 242 deletions

View File

@@ -1,3 +1,32 @@
/**
* @file MissionComp.ts
* @description 任务关卡核心控制组件UI + 逻辑层)
*
* 职责:
* 1. 管理单局游戏的 **完整生命周期**:初始化 → 准备阶段 → 战斗阶段 → 结算。
* 2. 在战斗阶段每帧更新战斗计时器、同步怪物数量、检测英雄全灭。
* 3. 管理怪物数量阈值(暂停 / 恢复刷怪的上下限)。
* 4. 处理新一波事件NewWave进入准备阶段并发放金币奖励。
* 5. 提供战斗结束后的结算弹窗入口VictoryComp
* 6. (可选)内建性能监控面板,显示内存、帧率、实体数量等开发信息。
*
* 关键设计:
* - mission_start() 初始化所有游戏数据 → 进入准备阶段 → 显示 loading。
* - 准备阶段enterPreparePhase停止刷怪显示开始按钮。
* - 战斗阶段to_fight开始刷怪隐藏按钮由 update 驱动。
* - 怪物数量管理采用 max/resume 双阈值:
* * 超过 max → 暂停刷怪stop_spawn_mon=true
* * 降至 resume 以下 → 恢复刷怪
* - cleanComponents() 在任务开始/结束时销毁所有英雄和技能 ECS 实体。
* - clearBattlePools() 回收对象池Monster / Skill / Tooltip
*
* 依赖:
* - smc.mission —— 全局任务运行状态play / pause / in_fight / stop_spawn_mon 等)
* - smc.vmdata.mission_data —— 局内数据(金币 / 波数 / 怪物数量等)
* - FightSet —— 战斗常量配置
* - CardInitCoins —— 初始金币数
* - UIID.Victory —— 结算弹窗
*/
import { _decorator, Vec3,Animation, instantiate, Prefab, Node, NodeEventType, ProgressBar, Label } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
@@ -19,7 +48,12 @@ const { ccclass, property } = _decorator;
//@todo 需要关注 当boss死亡的时候的动画播放完成后需要触发事件通知 MissionComp 进行奖励处理
/** 视图层对象 */
/**
* MissionComp —— 任务(关卡)核心控制器
*
* 驱动单局游戏的完整流程:准备 → 战斗 → 结算。
* 管理战斗计时、怪物数量控制、英雄全灭检测和金币奖励发放。
*/
@ccclass('MissionComp')
@ecs.register('MissionComp', false)
export class MissionComp extends CCComp {
@@ -28,66 +62,105 @@ export class MissionComp extends CCComp {
@property({ tooltip: "是否显示战斗内存观测面板" })
private showMemoryPanel: boolean = false;
// ======================== 配置参数 ========================
/** 怪物数量上限(超过后暂停刷怪) */
private maxMonsterCount: number = 5;
/** 怪物数量恢复阈值(降至此值以下恢复刷怪) */
private resumeMonsterCount: number = 3;
/** 新一波金币奖励基础值 */
private prepareBaseCoinReward: number = 100;
/** 每一波金币增长值 */
private prepareCoinWaveGrow: number = 1;
/** 金币奖励上限 */
private prepareCoinRewardCap: number = 500;
// VictoryComp:any = null;
// reward:number = 0;
// reward_num:number = 0;
// ======================== 编辑器绑定节点 ========================
/** 开始战斗按钮 */
@property(Node)
start_btn:Node = null!
/** 时间/波数显示节点 */
@property(Node)
time_node:Node = null!
// ======================== 运行时状态 ========================
/** 战斗倒计时(秒) */
FightTime:number = FightSet.FiIGHT_TIME
/** 剩余复活次数 */
revive_times: number = 1;
/** 掉落奖励列表 */
rewards:any[]=[]
/** 累计游戏数据 */
game_data:any={
exp:0,
gold:0,
diamond:0
}
/** 上一次显示的时间字符串(避免重复设置) */
private lastTimeStr: string = "";
/** 上一次显示的秒数(避免重复计算) */
private lastTimeSecond: number = -1;
/** 性能监控面板 Label 引用 */
private memoryLabel: Label | null = null;
/** 性能监控刷新计时器 */
private memoryRefreshTimer: number = 0;
/** 上一次性能文本(避免重复渲染) */
private lastMemoryText: string = "";
/** 帧间隔累加(用于计算平均 FPS */
private perfDtAcc: number = 0;
/** 帧数计数 */
private perfFrameCount: number = 0;
/** 初始堆内存基准值MB */
private heapBaseMB: number = -1;
/** 堆内存峰值MB */
private heapPeakMB: number = 0;
/** 堆内存增长趋势MB/分钟) */
private heapTrendPerMinMB: number = 0;
/** 趋势计算计时器 */
private heapTrendTimer: number = 0;
/** 趋势计算基准MB */
private heapTrendBaseMB: number = -1;
/** 怪物数量同步计时器(降低同步频率) */
private monsterCountSyncTimer: number = 0;
/** 当前波数 */
private currentWave: number = 0;
/** 上一次发放金币奖励的波数(防止重复发放) */
private lastPrepareCoinWave: number = 0;
// ======================== ECS 查询匹配器(预缓存) ========================
/** 匹配拥有 HeroViewComp 的实体(英雄/怪物视图) */
private readonly heroViewMatcher = ecs.allOf(HeroViewComp);
/** 匹配拥有 SkillView 的实体(技能视图) */
private readonly skillViewMatcher = ecs.allOf(SkillView);
/** 匹配拥有 HeroAttrsComp 的实体(英雄/怪物属性) */
private readonly heroAttrsMatcher = ecs.allOf(HeroAttrsComp);
// 记录已触发的特殊刷怪索引
// ======================== 生命周期 ========================
onLoad(){
this.showMemoryPanel = false
// 注册生命周期事件
this.on(GameEvent.MissionStart,this.mission_start,this)
// this.on(GameEvent.HeroDead,this.do_hero_dead,this)
// this.on(GameEvent.FightEnd,this.fight_end,this)
this.on(GameEvent.MissionEnd,this.mission_end,this)
this.on(GameEvent.NewWave,this.onNewWave,this)
this.on(GameEvent.DO_AD_BACK,this.do_ad,this)
this.start_btn?.on(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this)
this.removeMemoryPanel()
}
onDestroy(){
this.start_btn?.off(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this)
}
/**
* 帧更新:
* - 非播放 / 暂停状态 → 跳过
* - 战斗中 → 同步怪物状态、更新计时器
*/
protected update(dt: number): void {
if(!smc.mission.play) return
if(smc.mission.pause) return
@@ -96,10 +169,13 @@ export class MissionComp extends CCComp {
if(smc.mission.stop_mon_action) return
smc.vmdata.mission_data.fight_time+=dt
this.FightTime-=dt
// 检查特殊刷怪时间
this.update_time();
}
}
// ======================== 时间显示 ========================
/** 更新时间/波数显示(仅在秒数变化时更新以减少 Label 操作) */
update_time(){
const time = Math.max(0, this.FightTime);
const remainSecond = Math.floor(time);
@@ -115,12 +191,16 @@ export class MissionComp extends CCComp {
}
}
// ======================== 奖励与广告 ========================
//奖励发放
/** 奖励发放(预留) */
do_reward(){
// 奖励发放
}
/**
* 广告回调处理:
* 成功 → 增加刷新次数;失败 → 分发失败事件。
*/
do_ad(){
if(this.ad_back()){
oops.message.dispatchEvent(GameEvent.AD_BACK_TRUE)
@@ -129,15 +209,24 @@ export class MissionComp extends CCComp {
oops.message.dispatchEvent(GameEvent.AD_BACK_FALSE)
}
}
/** 广告观看结果(预留,默认返回 true */
ad_back(){
return true
}
// ======================== 任务生命周期 ========================
/**
* 任务开始:
* 1. 取消上一局延迟回调。
* 2. 清理残留实体。
* 3. 初始化全部局内数据。
* 4. 分发 FightReady 事件。
* 5. 进入准备阶段并显示 loading。
*/
async mission_start(){
// 防止上一局的 fight_end 延迟回调干扰新局
this.unscheduleAllCallbacks();
// 确保清理上一局的残留实体
this.cleanComponents();
this.node.active=true
this.data_init()
@@ -148,17 +237,29 @@ export class MissionComp extends CCComp {
this.scheduleOnce(()=>{
loading.active=false
},0.5)
}
/**
* 进入战斗:
* - 恢复刷怪
* - 标记战斗中
* - 隐藏开始按钮
* - 分发 FightStart 事件
*/
to_fight(){
smc.mission.stop_spawn_mon = false;
smc.mission.in_fight=true
smc.vmdata.mission_data.in_fight = true
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = false;
oops.message.dispatchEvent(GameEvent.FightStart) //GameSetMonComp 监听刷怪
oops.message.dispatchEvent(GameEvent.FightStart)
}
/**
* 进入准备阶段:
* - 标记非战斗
* - 暂停刷怪
* - 显示开始按钮
*/
private enterPreparePhase() {
smc.mission.in_fight = false;
smc.vmdata.mission_data.in_fight = false
@@ -166,6 +267,7 @@ export class MissionComp extends CCComp {
if (this.start_btn && this.start_btn.isValid) this.start_btn.active = true;
}
/** 开始战斗按钮点击回调 */
private onStartFightBtnClick() {
if (!smc.mission.play) return;
if (smc.mission.pause) return;
@@ -174,11 +276,16 @@ export class MissionComp extends CCComp {
}
/**
* 打开结算弹窗:
* - 暂停游戏
* - 打开 VictoryComp 弹窗
*
* @param e 事件对象(未使用)
* @param is_hero_dead 是否因英雄全灭触发
*/
open_Victory(e:any,is_hero_dead: boolean = false){
// 暂停游戏循环和怪物行为
// smc.mission.play = false;
smc.mission.pause = true;
// oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false})
mLogger.log(this.debugMode, 'MissionComp', " open_Victory",is_hero_dead,this.revive_times)
oops.gui.open(UIID.Victory,{
victory:false,
@@ -189,10 +296,8 @@ export class MissionComp extends CCComp {
}
/** 战斗结束:延迟清理组件和对象池 */
fight_end(){
// mLogger.log(this.debugMode, 'MissionComp', "任务结束")
// 延迟0.5秒后执行任务结束逻辑
this.scheduleOnce(() => {
smc.mission.play=false
this.cleanComponents()
@@ -200,9 +305,14 @@ export class MissionComp extends CCComp {
}, 0.5)
}
/**
* 任务结束(完全退出关卡):
* - 取消所有延迟回调
* - 重置全局标志
* - 清理组件和对象池
* - 隐藏节点
*/
mission_end(){
// mLogger.log(this.debugMode, 'MissionComp', " mission_end")
// 合并 FightEnd 逻辑:清理组件、停止游戏循环
this.unscheduleAllCallbacks();
smc.mission.play=false
smc.mission.pause = false;
@@ -214,8 +324,14 @@ export class MissionComp extends CCComp {
this.node.active=false
}
/**
* 初始化全部局内数据:
* - 全局运行标志
* - 战斗时间 / 怪物数量 / 金币 / 波数
* - 奖励列表 / 复活次数
* - 性能监控基准值
*/
data_init(){
//局内数据初始化 smc 数据初始化
smc.mission.play = true;
smc.mission.pause = false;
smc.mission.stop_mon_action = false;
@@ -227,8 +343,8 @@ export class MissionComp extends CCComp {
smc.vmdata.mission_data.mon_max = Math.max(1, Math.floor(this.maxMonsterCount))
this.currentWave = 1;
this.FightTime=FightSet.FiIGHT_TIME
this.rewards=[] // 改为数组,用于存储掉落物品列表
this.revive_times = 1; // 每次任务开始重置复活次数
this.rewards=[]
this.revive_times = 1;
this.lastTimeStr = "";
this.lastTimeSecond = -1;
this.memoryRefreshTimer = 0;
@@ -243,15 +359,20 @@ export class MissionComp extends CCComp {
this.monsterCountSyncTimer = 0;
this.lastPrepareCoinWave = 0;
smc.vmdata.mission_data.coin = Math.max(0, Math.floor(CardInitCoins));
// 重置全局属性加成和主角引用 (确保新一局数据干净)
// smc.role = null;
// 重置英雄数据,确保新一局是初始状态
// mLogger.log(this.debugMode, 'MissionComp', "局内数据初始化",smc.vmdata.mission_data)
}
// ======================== 波次管理 ========================
/**
* 新一波事件回调:
* 1. 进入准备阶段。
* 2. 更新当前波数。
* 3. 发放本波金币奖励。
* 4. 刷新时间显示。
*
* @param event 事件名
* @param data { wave: number }
*/
private onNewWave(event: string, data: any) {
const wave = Number(data?.wave ?? 0);
if (wave <= 0) return;
@@ -263,6 +384,13 @@ export class MissionComp extends CCComp {
this.update_time();
}
/**
* 按波数发放金币奖励:
* reward = min(cap, base + (wave - 1) × grow)
* 仅在波数首次到达时发放,防止重复。
*
* @param wave 当前波数
*/
private grantPrepareCoinByWave(wave: number) {
if (wave <= 0) return;
if (wave <= this.lastPrepareCoinWave) return;
@@ -280,12 +408,26 @@ export class MissionComp extends CCComp {
mLogger.log(this.debugMode, 'MissionComp', "prepare coin reward", { wave, reward, coin: smc.vmdata.mission_data.coin });
}
// ======================== 怪物数量管理 ========================
/**
* 获取怪物数量阈值配置。
* @returns { max: 刷怪上限, resume: 恢复刷怪阈值 }
*/
private getMonsterThresholds(): { max: number; resume: number } {
const max = Math.max(1, Math.floor(this.maxMonsterCount));
const resume = Math.min(max - 1, Math.max(0, Math.floor(this.resumeMonsterCount)));
return { max, resume };
}
/**
* 同步怪物刷新状态(降频执行,每 0.2 秒一次):
* 1. 遍历所有 HeroAttrsComp 实体,统计怪物和英雄数量。
* 2. 检测英雄全灭。
* 3. 根据 max/resume 阈值切换 stop_spawn_mon 状态。
*
* @param dt 帧间隔
*/
private syncMonsterSpawnState(dt: number) {
this.monsterCountSyncTimer += dt;
if (dt > 0 && this.monsterCountSyncTimer < 0.2) return;
@@ -309,12 +451,18 @@ export class MissionComp extends CCComp {
smc.vmdata.mission_data.mon_max = max;
const stopSpawn = !!smc.mission.stop_spawn_mon;
if (stopSpawn) {
// 降至恢复阈值以下 → 恢复刷怪
if (monsterCount <= resume) smc.mission.stop_spawn_mon = false;
return;
}
// 超过上限 → 暂停刷怪
if (monsterCount >= max) smc.mission.stop_spawn_mon = true;
}
/**
* 英雄全灭检测:若场上无存活英雄且处于战斗中,触发结算弹窗。
* @param heroCount 当前存活英雄数量
*/
private handleHeroWipe(heroCount: number) {
if (heroCount > 0) return;
if (!smc.mission.play || smc.mission.pause) return;
@@ -324,6 +472,9 @@ export class MissionComp extends CCComp {
this.open_Victory(null, true);
}
// ======================== 清理 ========================
/** 清理所有英雄和技能 ECS 实体 */
private cleanComponents() {
const heroEntities: ecs.Entity[] = [];
ecs.query(this.heroViewMatcher).forEach(entity => {
@@ -341,6 +492,7 @@ export class MissionComp extends CCComp {
});
}
/** 回收所有战斗对象池Monster / Skill / Tooltip并清理场景节点 */
private clearBattlePools() {
Monster.clearPools();
Skill.clearPools();
@@ -348,6 +500,7 @@ export class MissionComp extends CCComp {
this.clearBattleSceneNodes();
}
/** 清理战斗场景中的 HERO 和 SKILL 根节点下的所有子节点 */
private clearBattleSceneNodes() {
const scene = smc.map?.MapView?.scene;
const layer = scene?.entityLayer?.node;
@@ -366,6 +519,7 @@ export class MissionComp extends CCComp {
}
}
/** 获取战斗层的英雄和技能节点数量(用于性能监控) */
private getBattleLayerNodeCount() {
const scene = smc.map?.MapView?.scene;
const layer = scene?.entityLayer?.node;
@@ -378,8 +532,11 @@ export class MissionComp extends CCComp {
};
}
// ======================== 性能监控面板 ========================
/** 性能监控相关代码 */
/** 初始化性能监控面板:在 time_node 下创建 Label */
private initMemoryPanel() {
if (!this.showMemoryPanel || !this.time_node) return;
let panel = this.time_node.getChildByName("mem_panel");
@@ -397,6 +554,7 @@ export class MissionComp extends CCComp {
this.memoryLabel = label;
}
/** 移除性能监控面板 */
private removeMemoryPanel() {
const panel = this.time_node?.getChildByName("mem_panel");
if (panel) {
@@ -407,6 +565,10 @@ export class MissionComp extends CCComp {
}
/**
* 更新性能监控面板内容(每 0.5 秒一次):
* 显示 堆内存 / 增长趋势 / 帧率 / 实体数量 / 对象池状态 等信息。
*/
private updateMemoryPanel(dt: number) {
if (!this.showMemoryPanel || !this.memoryLabel) return;
this.perfDtAcc += dt;
@@ -466,7 +628,7 @@ export class MissionComp extends CCComp {
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
/** ECS 组件移除时销毁节点 */
reset() {
this.node.destroy();
}