跳到主要内容

关卡进度

相关源文件

本页记录关卡完成系统:包含清理条件、传送门激活以及胜利触发流程。关卡推进系统会跨普通生成点与竞技场追踪敌人清除情况,判断何时完成关卡,并管理“解锁状态”的切换(玩家可通过传送门离开关卡)。

敌人生成机制请参见 敌人生成系统。竞技场波次机制请参见 竞技场战斗系统。传送门触发区域与 TMX 加载请参见 TMX 加载与碰撞


系统概览

关卡推进系统管理三种互斥状态:

  1. 进行中(Active):战斗尚未结束;传送门锁定
  2. 已清理(Cleared):所有目标完成;传送门解锁并播放特效
  3. 离开(Exiting):玩家与传送门交互返回地图

该系统集中在 LevelMap 中实现,并由 GameScene 进行编排;完成状态通过 GameProgressSaveData::isLevelCleared 持久化。

来源: Classes/Scenes/LevelMap.h L70-L83

Classes/Scenes/LevelMap.cpp L71-L82

Classes/Save/SaveData.h L119-L122


完成度追踪状态

状态变量

LevelMap 维护了三个计数/标记,它们共同决定关卡是否完成:

变量类型用途
_currentActiveMonstersint存活怪物数量(生成时递增,死亡时递减)
_pendingEnemySpawnPointssize_t尚未触发的 enemy_g 生成点数量
_isLevelClearedbool是否已触发“关卡清理完成”

此外,_arenas 中的每个 ArenaConfig 会用 isFinished 表示该竞技场是否完成。

来源: Classes/Scenes/LevelMap.h L194-L195

Classes/Scenes/LevelMap.cpp L510-L514

初始化逻辑

如果关卡没有任何战斗配置(既没有 enemy_g 生成点,也没有竞技场对象层),传送门会默认解锁。这让“Hub/对话类”关卡可以无需战斗也能正常运作。

来源: Classes/Scenes/LevelMap.cpp L71-L82


清理条件

条件评估

checkAllClear() 会评估三项条件,全部满足才算“关卡清理完成”:

来源: Classes/Scenes/LevelMap.cpp L458-L468

条件说明

条件描述变化时机
_currentActiveMonsters == 0场景内没有存活怪物刷怪时递增;怪物死亡回调里递减
_pendingEnemySpawnPoints == 0所有 enemy_g 生成点都已触发初始化为生成点数量;生成点触发后递减
所有竞技场完成_arenas 里每个竞技场都 isFinished=true最后一波清完后置位

击杀事件到清理检测

来源: Classes/Scenes/LevelMap.cpp L449-L456

Classes/Scenes/GameScene.cpp L236

Classes/Scenes/LevelMap.cpp L655-L670


胜利序列

触发流程

checkAllClear() 返回 truetriggerLevelClear() 会执行胜利序列:

来源: Classes/Scenes/LevelMap.cpp L471-L483

传送门特效(Gate Activation)

每个 _gateAreas 的矩形中心都会生成一个常驻粒子效果,用于提示“已可交互”:

来源: Classes/Scenes/LevelMap.cpp L408-L433

胜利横幅(Victory Banner)

来源: Classes/Scenes/LevelMap.cpp L484-L507


传送门交互系统

交互判定

isPointAtGate() 会强制要求“关卡已清理”后传送门才可交互:

步骤代码行为
1if (!_isLevelCleared) return false;未清理时禁止交互
2if (_gateAreas.empty()) return false;没有门区就不交互
3for (const auto& gateRect : _gateAreas)遍历门区矩形
4if (gateRect.containsPoint(worldPos)) return true;玩家进入门区则可交互

来源: Classes/Scenes/LevelMap.cpp L391-L404

输入绑定

GameInputController 通过 gateQuery 轮询门区状态,命中后执行 gateEnter:

来源: Classes/Scenes/GameInputController.cpp L267-L274

Classes/Scenes/GameScene.cpp L552-L557

Classes/Scenes/GameScene.cpp L745-L767


存/读档集成

存档数据结构

来源: Classes/Save/SaveData.h L109-L168

存档写入

存档时,GameScene::fillProgressDataForSave() 会把清理状态写入 GameProgressSaveData

outProgress.isLevelCleared = (_levelMap != nullptr) ? _levelMap->isLevelCleared() : false;

来源: Classes/Scenes/GameScene.cpp L328-L389

读档恢复

来源: Classes/Scenes/GameScene.cpp L198-L306

Classes/Scenes/LevelMap.cpp L435-L447

旧版存档兼容(字段缺失推断)

旧存档如果缺少 isLevelCleared 字段,系统会根据“当前世界状态”推断是否应视为已清理,避免出现“旧版本已通关但读档后门被锁住”的体验问题。

来源: Classes/Scenes/GameScene.cpp L277-L303


与自动存档的集成

关卡清理状态会通过自动存档系统被持续写入:

由于 isLevelCleared 会被写入每一次 GameProgressSaveData,清理状态会被手动存档与 60 秒自动存档一并捕获。这保证玩家清理完关卡后可以安全退出而不丢进度。

来源: Classes/Scenes/GameScene.cpp L935-L1011

Classes/Save/SaveManager.cpp L49-L80


关键代码实体

LevelMap 方法

方法签名用途
finalizeInitialState()void finalizeInitialState()根据战斗配置决定初始是否清理完成
onMonsterKilled()void onMonsterKilled()递减存活计数并检查是否完成
checkAllClear()bool checkAllClear()评估是否满足全部清理条件
triggerLevelClear()void triggerLevelClear()执行胜利序列并解锁传送门
showVictoryBanner()void showVictoryBanner()播放胜利 UI 动画
isPointAtGate()bool isPointAtGate(const Vec2&) const判断某点是否在门区且关卡已清理
restoreLevelClearedForLoad()void restoreLevelClearedForLoad(bool cleared)读档恢复清理状态(不播放 banner)

来源: Classes/Scenes/LevelMap.h L78-L83

Classes/Scenes/LevelMap.cpp L71-L507

GameScene 方法

方法签名用途
fillProgressDataForSave()void fillProgressDataForSave(GameProgressSaveData&) const存档时提取清理状态
returnToMapScene()void returnToMapScene()缓存玩家数据并切换回地图

来源: Classes/Scenes/GameScene.h L66-L69

Classes/Scenes/GameScene.cpp L328-L389

Classes/Scenes/GameScene.cpp L745-L767

存档字段

字段类型文件
GameProgressSaveData::isLevelClearedboolClasses/Save/SaveData.h L122
LevelMap::_isLevelClearedboolClasses/Scenes/LevelMap.h L195
LevelMap::_currentActiveMonstersintClasses/Scenes/LevelMap.h L194
LevelMap::_pendingEnemySpawnPointssize_tClasses/Scenes/LevelMap.h L191