docs: 为游戏地图模块添加详细的代码注释
为游戏地图模块的脚本文件添加全面的注释,说明每个组件的职责、关键设计、依赖关系和使用方式。注释覆盖了英雄信息面板、技能卡槽位管理器、排行榜弹窗、卡牌控制器、背景滚动组件等核心功能模块,提高了代码的可读性和维护性。 同时修复了英雄预制体的激活状态和技能效果预制体的尺寸参数。
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user