LevelConfigManager.ts 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import { _decorator, Component, JsonAsset, resources } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. /**
  4. * 关卡配置数据结构
  5. */
  6. interface LevelConfig {
  7. levelId: number;
  8. name: string;
  9. scene: string;
  10. description?: string;
  11. backgroundImage?: string; // 背景图片路径
  12. weapons: string[];
  13. waves: WaveConfig[];
  14. levelSettings?: {
  15. initialHealth?: number;
  16. timeLimit?: number;
  17. difficulty?: string;
  18. energyMax?: number;
  19. healthMultiplier?: number;
  20. };
  21. }
  22. /**
  23. * 波次配置数据结构
  24. */
  25. interface WaveConfig {
  26. waveId: number;
  27. enemies: EnemyWaveConfig[];
  28. healthMultiplier?: number;
  29. }
  30. /**
  31. * 敌人波次配置
  32. */
  33. interface EnemyWaveConfig {
  34. enemyType: string;
  35. count: number;
  36. spawnInterval: number;
  37. characteristics: string[];
  38. }
  39. /**
  40. * 关卡配置管理器
  41. * 让策划在编辑器中配置所有关卡的JSON文件
  42. */
  43. @ccclass('LevelConfigManager')
  44. export class LevelConfigManager extends Component {
  45. private static instance: LevelConfigManager = null;
  46. @property({
  47. tooltip: '总关卡数量'
  48. })
  49. public totalLevels: number = 5;
  50. @property({
  51. type: [JsonAsset],
  52. tooltip: '关卡配置文件列表(按关卡序号排列)'
  53. })
  54. public levelConfigs: JsonAsset[] = [];
  55. // 缓存已加载的关卡配置
  56. private loadedConfigs: Map<number, LevelConfig> = new Map();
  57. onLoad() {
  58. if (LevelConfigManager.instance === null) {
  59. LevelConfigManager.instance = this;
  60. this.validateConfigs();
  61. } else if (LevelConfigManager.instance !== this) {
  62. this.destroy();
  63. return;
  64. }
  65. }
  66. onDestroy() {
  67. if (LevelConfigManager.instance === this) {
  68. LevelConfigManager.instance = null;
  69. }
  70. }
  71. public static getInstance(): LevelConfigManager {
  72. return LevelConfigManager.instance;
  73. }
  74. /**
  75. * 验证关卡配置的完整性
  76. */
  77. private validateConfigs() {
  78. // 检查是否所有关卡都有配置(按数组索引对应关卡ID)
  79. for (let i = 1; i <= this.totalLevels; i++) {
  80. const configFile = this.levelConfigs[i - 1];
  81. if (!configFile) {
  82. console.warn(`关卡 ${i} 缺少JSON文件`);
  83. }
  84. }
  85. }
  86. /**
  87. * 获取关卡配置
  88. */
  89. public async getLevelConfig(levelId: number): Promise<LevelConfig | null> {
  90. // 先从缓存中查找
  91. if (this.loadedConfigs.has(levelId)) {
  92. return this.loadedConfigs.get(levelId);
  93. }
  94. // 按数组索引查找对应的配置文件
  95. const configFile = this.levelConfigs[levelId - 1];
  96. if (!configFile) {
  97. console.error(`关卡 ${levelId} 配置不存在或缺少JSON文件`);
  98. return null;
  99. }
  100. try {
  101. // 解析JSON数据
  102. const jsonData = configFile.json;
  103. if (!jsonData) {
  104. console.error(`关卡 ${levelId} JSON文件解析失败`);
  105. return null;
  106. }
  107. // 验证JSON数据结构
  108. const levelConfig = this.validateLevelConfigData(jsonData, levelId);
  109. if (levelConfig) {
  110. // 缓存配置
  111. this.loadedConfigs.set(levelId, levelConfig);
  112. return levelConfig;
  113. }
  114. } catch (error) {
  115. console.error(`关卡 ${levelId} 配置加载失败:`, error);
  116. }
  117. return null;
  118. }
  119. /**
  120. * 验证关卡配置数据结构
  121. */
  122. private validateLevelConfigData(jsonData: any, levelId: number): LevelConfig | null {
  123. try {
  124. // 基本字段验证
  125. const weapons = jsonData.weapons || jsonData.availableWeapons;
  126. if (!jsonData.name || !jsonData.scene || !weapons) {
  127. console.error(`关卡 ${levelId} JSON数据缺少必要字段`);
  128. if (!jsonData.name) console.error(` 缺少字段: name`);
  129. if (!jsonData.scene) console.error(` 缺少字段: scene`);
  130. if (!weapons) console.error(` 缺少字段: weapons 或 availableWeapons`);
  131. return null;
  132. }
  133. // 检查武器列表是否为空
  134. if (!Array.isArray(weapons) || weapons.length === 0) {
  135. console.error(`关卡 ${levelId} 没有配置武器列表`);
  136. return null;
  137. }
  138. // 构建关卡配置对象
  139. const levelConfig: LevelConfig = {
  140. levelId: levelId,
  141. name: jsonData.name,
  142. scene: jsonData.scene,
  143. description: jsonData.description,
  144. backgroundImage: jsonData.backgroundImage, // 添加背景图片字段
  145. weapons: weapons,
  146. waves: [],
  147. levelSettings: {
  148. timeLimit: jsonData.timeLimit,
  149. difficulty: jsonData.difficulty,
  150. healthMultiplier: jsonData.healthMultiplier,
  151. ...jsonData.levelSettings
  152. }
  153. };
  154. // 验证波次配置
  155. if (Array.isArray(jsonData.waves)) {
  156. for (const waveData of jsonData.waves) {
  157. const wave: WaveConfig = {
  158. waveId: waveData.waveId || 0,
  159. enemies: [],
  160. healthMultiplier: waveData.healthMultiplier
  161. };
  162. if (Array.isArray(waveData.enemies)) {
  163. for (const enemyData of waveData.enemies) {
  164. const enemy: EnemyWaveConfig = {
  165. enemyType: enemyData.enemyType || '',
  166. count: enemyData.count || 1,
  167. spawnInterval: enemyData.spawnInterval || 5,
  168. characteristics: enemyData.characteristics || []
  169. };
  170. wave.enemies.push(enemy);
  171. }
  172. }
  173. levelConfig.waves.push(wave);
  174. }
  175. }
  176. return levelConfig;
  177. } catch (error) {
  178. console.error(`关卡 ${levelId} 数据验证失败:`, error);
  179. return null;
  180. }
  181. }
  182. /**
  183. * 获取所有可用关卡ID列表
  184. */
  185. public getAvailableLevels(): number[] {
  186. const ids: number[] = [];
  187. for (let i = 0; i < this.levelConfigs.length; i++) {
  188. if (this.levelConfigs[i]) {
  189. ids.push(i + 1);
  190. }
  191. }
  192. return ids.sort((a, b) => a - b);
  193. }
  194. /**
  195. * 获取关卡名称
  196. */
  197. public getLevelName(levelId: number): string {
  198. const asset = this.levelConfigs[levelId - 1];
  199. return asset ? (asset.name || `关卡 ${levelId}`) : `关卡 ${levelId}`;
  200. }
  201. /**
  202. * 检查关卡是否已配置
  203. */
  204. public isLevelConfigured(levelId: number): boolean {
  205. return !!this.levelConfigs[levelId - 1];
  206. }
  207. /**
  208. * 获取总关卡数
  209. */
  210. public getTotalLevels(): number {
  211. return this.totalLevels;
  212. }
  213. /**
  214. * 重新加载所有关卡配置(开发调试用)
  215. */
  216. public reloadAllConfigs() {
  217. this.loadedConfigs.clear();
  218. this.validateConfigs();
  219. }
  220. /**
  221. * 调试:打印所有关卡配置信息
  222. */
  223. public debugPrintAllConfigs() {
  224. console.log(`=== 所有关卡配置信息 ===`);
  225. console.log(`总关卡数: ${this.totalLevels}`);
  226. for (let i = 0; i < this.levelConfigs.length; i++) {
  227. const asset = this.levelConfigs[i];
  228. console.log(`关卡 ${i + 1}: ${asset ? asset.name : '未设置'}`);
  229. }
  230. }
  231. }