LevelConfigManager.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. weapons: string[];
  12. waves: WaveConfig[];
  13. levelSettings?: {
  14. initialHealth?: number;
  15. timeLimit?: number;
  16. difficulty?: string;
  17. starRequirements?: {
  18. [key: string]: any;
  19. };
  20. };
  21. }
  22. /**
  23. * 波次配置数据结构
  24. */
  25. interface WaveConfig {
  26. waveId: number;
  27. enemies: EnemyWaveConfig[];
  28. }
  29. /**
  30. * 敌人波次配置
  31. */
  32. interface EnemyWaveConfig {
  33. enemyType: string;
  34. count: number;
  35. spawnInterval: number;
  36. characteristics: string[];
  37. }
  38. /**
  39. * 关卡JSON文件配置项
  40. */
  41. @ccclass('LevelJsonConfig')
  42. export class LevelJsonConfig {
  43. @property({
  44. tooltip: '关卡ID'
  45. })
  46. public levelId: number = 1;
  47. @property({
  48. tooltip: '关卡名称'
  49. })
  50. public levelName: string = '';
  51. @property({
  52. type: JsonAsset,
  53. tooltip: '关卡配置JSON文件'
  54. })
  55. public configFile: JsonAsset = null;
  56. }
  57. /**
  58. * 关卡配置管理器
  59. * 让策划在编辑器中配置所有关卡的JSON文件
  60. */
  61. @ccclass('LevelConfigManager')
  62. export class LevelConfigManager extends Component {
  63. private static instance: LevelConfigManager = null;
  64. @property({
  65. tooltip: '总关卡数量'
  66. })
  67. public totalLevels: number = 5;
  68. @property({
  69. type: [LevelJsonConfig],
  70. tooltip: '关卡配置列表(拖入对应的JSON文件)'
  71. })
  72. public levelConfigs: LevelJsonConfig[] = [];
  73. // 缓存已加载的关卡配置
  74. private loadedConfigs: Map<number, LevelConfig> = new Map();
  75. onLoad() {
  76. if (LevelConfigManager.instance === null) {
  77. LevelConfigManager.instance = this;
  78. this.validateConfigs();
  79. } else if (LevelConfigManager.instance !== this) {
  80. this.destroy();
  81. return;
  82. }
  83. }
  84. onDestroy() {
  85. if (LevelConfigManager.instance === this) {
  86. LevelConfigManager.instance = null;
  87. }
  88. }
  89. public static getInstance(): LevelConfigManager {
  90. return LevelConfigManager.instance;
  91. }
  92. /**
  93. * 验证关卡配置的完整性
  94. */
  95. private validateConfigs() {
  96. // 检查是否所有关卡都有配置
  97. for (let i = 1; i <= this.totalLevels; i++) {
  98. const config = this.levelConfigs.find(c => c.levelId === i);
  99. if (!config) {
  100. console.warn(`关卡 ${i} 缺少配置`);
  101. } else if (!config.configFile) {
  102. console.warn(`关卡 ${i} 缺少JSON文件`);
  103. }
  104. }
  105. // 检查是否有重复的关卡ID
  106. const levelIds = this.levelConfigs.map(c => c.levelId);
  107. const duplicates = levelIds.filter((id, index) => levelIds.indexOf(id) !== index);
  108. if (duplicates.length > 0) {
  109. console.error(`发现重复的关卡ID: ${duplicates.join(', ')}`);
  110. }
  111. }
  112. /**
  113. * 获取关卡配置
  114. */
  115. public async getLevelConfig(levelId: number): Promise<LevelConfig | null> {
  116. // 先从缓存中查找
  117. if (this.loadedConfigs.has(levelId)) {
  118. return this.loadedConfigs.get(levelId);
  119. }
  120. // 查找对应的配置项
  121. const configItem = this.levelConfigs.find(c => c.levelId === levelId);
  122. if (!configItem || !configItem.configFile) {
  123. console.error(`关卡 ${levelId} 配置不存在或缺少JSON文件`);
  124. return null;
  125. }
  126. try {
  127. // 解析JSON数据
  128. const jsonData = configItem.configFile.json;
  129. if (!jsonData) {
  130. console.error(`关卡 ${levelId} JSON文件解析失败`);
  131. return null;
  132. }
  133. // 验证JSON数据结构
  134. const levelConfig = this.validateLevelConfigData(jsonData, levelId);
  135. if (levelConfig) {
  136. // 缓存配置
  137. this.loadedConfigs.set(levelId, levelConfig);
  138. return levelConfig;
  139. }
  140. } catch (error) {
  141. console.error(`关卡 ${levelId} 配置加载失败:`, error);
  142. }
  143. return null;
  144. }
  145. /**
  146. * 验证关卡配置数据结构
  147. */
  148. private validateLevelConfigData(jsonData: any, levelId: number): LevelConfig | null {
  149. try {
  150. // 基本字段验证
  151. if (!jsonData.name || !jsonData.scene || !jsonData.weapons || !jsonData.waves) {
  152. console.error(`关卡 ${levelId} JSON数据缺少必要字段`);
  153. return null;
  154. }
  155. // 构建关卡配置对象
  156. const levelConfig: LevelConfig = {
  157. levelId: levelId,
  158. name: jsonData.name,
  159. scene: jsonData.scene,
  160. description: jsonData.description,
  161. weapons: jsonData.weapons || [],
  162. waves: [],
  163. levelSettings: jsonData.levelSettings
  164. };
  165. // 验证波次配置
  166. if (Array.isArray(jsonData.waves)) {
  167. for (const waveData of jsonData.waves) {
  168. const wave: WaveConfig = {
  169. waveId: waveData.waveId || 0,
  170. enemies: []
  171. };
  172. if (Array.isArray(waveData.enemies)) {
  173. for (const enemyData of waveData.enemies) {
  174. const enemy: EnemyWaveConfig = {
  175. enemyType: enemyData.enemyType || '',
  176. count: enemyData.count || 1,
  177. spawnInterval: enemyData.spawnInterval || 5,
  178. characteristics: enemyData.characteristics || []
  179. };
  180. wave.enemies.push(enemy);
  181. }
  182. }
  183. levelConfig.waves.push(wave);
  184. }
  185. }
  186. return levelConfig;
  187. } catch (error) {
  188. console.error(`关卡 ${levelId} 数据验证失败:`, error);
  189. return null;
  190. }
  191. }
  192. /**
  193. * 获取所有可用关卡ID列表
  194. */
  195. public getAvailableLevels(): number[] {
  196. return this.levelConfigs
  197. .filter(config => config.configFile !== null)
  198. .map(config => config.levelId)
  199. .sort((a, b) => a - b);
  200. }
  201. /**
  202. * 获取关卡名称
  203. */
  204. public getLevelName(levelId: number): string {
  205. const config = this.levelConfigs.find(c => c.levelId === levelId);
  206. return config ? config.levelName : `关卡 ${levelId}`;
  207. }
  208. /**
  209. * 检查关卡是否已配置
  210. */
  211. public isLevelConfigured(levelId: number): boolean {
  212. const config = this.levelConfigs.find(c => c.levelId === levelId);
  213. return config !== undefined && config.configFile !== null;
  214. }
  215. /**
  216. * 获取总关卡数
  217. */
  218. public getTotalLevels(): number {
  219. return this.totalLevels;
  220. }
  221. /**
  222. * 重新加载所有关卡配置(开发调试用)
  223. */
  224. public reloadAllConfigs() {
  225. this.loadedConfigs.clear();
  226. this.validateConfigs();
  227. }
  228. /**
  229. * 创建示例关卡配置(开发辅助)
  230. */
  231. public generateSampleConfig(levelId: number): LevelConfig {
  232. const samples = {
  233. 1: {
  234. name: '新手引导(草地平原)',
  235. scene: 'grassland',
  236. weapons: ['毛豆射手', '尖胡萝卜'],
  237. waves: [
  238. {
  239. waveId: 1,
  240. enemies: [
  241. { enemyType: '普通僵尸', count: 8, spawnInterval: 5, characteristics: ['中速移动', '无技能'] }
  242. ]
  243. },
  244. {
  245. waveId: 2,
  246. enemies: [
  247. { enemyType: '普通僵尸', count: 10, spawnInterval: 5, characteristics: ['中速移动', '无技能'] }
  248. ]
  249. },
  250. {
  251. waveId: 3,
  252. enemies: [
  253. { enemyType: '路障僵尸', count: 5, spawnInterval: 6, characteristics: ['高生命', '慢速移动'] }
  254. ]
  255. }
  256. ]
  257. },
  258. 2: {
  259. name: '丛林探险(森林场景)',
  260. scene: 'forest',
  261. weapons: ['锯齿草', '西瓜炸弹', '毛豆射手'],
  262. waves: [
  263. {
  264. waveId: 1,
  265. enemies: [
  266. { enemyType: '普通僵尸', count: 10, spawnInterval: 4, characteristics: ['中速移动', '无技能'] }
  267. ]
  268. },
  269. {
  270. waveId: 2,
  271. enemies: [
  272. { enemyType: '漫步僵尸', count: 6, spawnInterval: 5, characteristics: ['左右摇摆', '近战范围大'] }
  273. ]
  274. }
  275. ]
  276. }
  277. };
  278. return samples[levelId] || samples[1];
  279. }
  280. /**
  281. * 调试:打印所有关卡配置信息
  282. */
  283. public debugPrintAllConfigs() {
  284. console.log(`=== 所有关卡配置信息 ===`);
  285. console.log(`总关卡数: ${this.totalLevels}`);
  286. for (const config of this.levelConfigs) {
  287. console.log(`关卡 ${config.levelId}: ${config.levelName}`);
  288. console.log(` JSON文件: ${config.configFile ? config.configFile.name : '未设置'}`);
  289. }
  290. }
  291. }