| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- import { _decorator, Component, JsonAsset, resources } from 'cc';
- const { ccclass, property } = _decorator;
- /**
- * 关卡配置数据结构
- */
- interface LevelConfig {
- levelId: number;
- name: string;
- scene: string;
- description?: string;
- backgroundImage?: string; // 背景图片路径
- weapons: string[];
- waves: WaveConfig[];
- levelSettings?: {
- initialHealth?: number;
- timeLimit?: number;
- difficulty?: string;
- energyMax?: number;
- healthMultiplier?: number;
- };
- }
- /**
- * 波次配置数据结构
- */
- interface WaveConfig {
- waveId: number;
- enemies: EnemyWaveConfig[];
- }
- /**
- * 敌人波次配置
- */
- interface EnemyWaveConfig {
- enemyType: string;
- count: number;
- spawnInterval: number;
- characteristics: string[];
- }
- /**
- * 关卡JSON文件配置项
- */
- @ccclass('LevelJsonConfig')
- export class LevelJsonConfig {
- @property({
- tooltip: '关卡ID'
- })
- public levelId: number = 1;
- @property({
- tooltip: '关卡名称'
- })
- public levelName: string = '';
- @property({
- type: JsonAsset,
- tooltip: '关卡配置JSON文件'
- })
- public configFile: JsonAsset = null;
- }
- /**
- * 关卡配置管理器
- * 让策划在编辑器中配置所有关卡的JSON文件
- */
- @ccclass('LevelConfigManager')
- export class LevelConfigManager extends Component {
- private static instance: LevelConfigManager = null;
- @property({
- tooltip: '总关卡数量'
- })
- public totalLevels: number = 5;
- @property({
- type: [LevelJsonConfig],
- tooltip: '关卡配置列表(拖入对应的JSON文件)'
- })
- public levelConfigs: LevelJsonConfig[] = [];
- // 缓存已加载的关卡配置
- private loadedConfigs: Map<number, LevelConfig> = new Map();
- onLoad() {
- if (LevelConfigManager.instance === null) {
- LevelConfigManager.instance = this;
- this.validateConfigs();
- } else if (LevelConfigManager.instance !== this) {
- this.destroy();
- return;
- }
- }
- onDestroy() {
- if (LevelConfigManager.instance === this) {
- LevelConfigManager.instance = null;
- }
- }
- public static getInstance(): LevelConfigManager {
- return LevelConfigManager.instance;
- }
- /**
- * 验证关卡配置的完整性
- */
- private validateConfigs() {
- // 检查是否所有关卡都有配置
- for (let i = 1; i <= this.totalLevels; i++) {
- const config = this.levelConfigs.find(c => c.levelId === i);
- if (!config) {
- console.warn(`关卡 ${i} 缺少配置`);
- } else if (!config.configFile) {
- console.warn(`关卡 ${i} 缺少JSON文件`);
- }
- }
- // 检查是否有重复的关卡ID
- const levelIds = this.levelConfigs.map(c => c.levelId);
- const duplicates = levelIds.filter((id, index) => levelIds.indexOf(id) !== index);
- if (duplicates.length > 0) {
- console.error(`发现重复的关卡ID: ${duplicates.join(', ')}`);
- }
- }
- /**
- * 获取关卡配置
- */
- public async getLevelConfig(levelId: number): Promise<LevelConfig | null> {
- // 先从缓存中查找
- if (this.loadedConfigs.has(levelId)) {
- return this.loadedConfigs.get(levelId);
- }
- // 查找对应的配置项
- const configItem = this.levelConfigs.find(c => c.levelId === levelId);
- if (!configItem || !configItem.configFile) {
- console.error(`关卡 ${levelId} 配置不存在或缺少JSON文件`);
- return null;
- }
- try {
- // 解析JSON数据
- const jsonData = configItem.configFile.json;
- if (!jsonData) {
- console.error(`关卡 ${levelId} JSON文件解析失败`);
- return null;
- }
- // 验证JSON数据结构
- const levelConfig = this.validateLevelConfigData(jsonData, levelId);
- if (levelConfig) {
- // 缓存配置
- this.loadedConfigs.set(levelId, levelConfig);
- return levelConfig;
- }
- } catch (error) {
- console.error(`关卡 ${levelId} 配置加载失败:`, error);
- }
- return null;
- }
- /**
- * 验证关卡配置数据结构
- */
- private validateLevelConfigData(jsonData: any, levelId: number): LevelConfig | null {
- try {
- // 基本字段验证
- const weapons = jsonData.weapons || jsonData.availableWeapons;
- if (!jsonData.name || !jsonData.scene || !weapons) {
- console.error(`关卡 ${levelId} JSON数据缺少必要字段`);
- if (!jsonData.name) console.error(` 缺少字段: name`);
- if (!jsonData.scene) console.error(` 缺少字段: scene`);
- if (!weapons) console.error(` 缺少字段: weapons 或 availableWeapons`);
- return null;
- }
- // 检查武器列表是否为空
- if (!Array.isArray(weapons) || weapons.length === 0) {
- console.error(`关卡 ${levelId} 没有配置武器列表`);
- return null;
- }
- // 构建关卡配置对象
- const levelConfig: LevelConfig = {
- levelId: levelId,
- name: jsonData.name,
- scene: jsonData.scene,
- description: jsonData.description,
- backgroundImage: jsonData.backgroundImage, // 添加背景图片字段
- weapons: weapons,
- waves: [],
- levelSettings: {
- timeLimit: jsonData.timeLimit,
- difficulty: jsonData.difficulty,
- healthMultiplier: jsonData.healthMultiplier,
- ...jsonData.levelSettings
- }
- };
- // 验证波次配置
- if (Array.isArray(jsonData.waves)) {
- for (const waveData of jsonData.waves) {
- const wave: WaveConfig = {
- waveId: waveData.waveId || 0,
- enemies: []
- };
- if (Array.isArray(waveData.enemies)) {
- for (const enemyData of waveData.enemies) {
- const enemy: EnemyWaveConfig = {
- enemyType: enemyData.enemyType || '',
- count: enemyData.count || 1,
- spawnInterval: enemyData.spawnInterval || 5,
- characteristics: enemyData.characteristics || []
- };
- wave.enemies.push(enemy);
- }
- }
- levelConfig.waves.push(wave);
- }
- }
- return levelConfig;
- } catch (error) {
- console.error(`关卡 ${levelId} 数据验证失败:`, error);
- return null;
- }
- }
- /**
- * 获取所有可用关卡ID列表
- */
- public getAvailableLevels(): number[] {
- return this.levelConfigs
- .filter(config => config.configFile !== null)
- .map(config => config.levelId)
- .sort((a, b) => a - b);
- }
- /**
- * 获取关卡名称
- */
- public getLevelName(levelId: number): string {
- const config = this.levelConfigs.find(c => c.levelId === levelId);
- return config ? config.levelName : `关卡 ${levelId}`;
- }
- /**
- * 检查关卡是否已配置
- */
- public isLevelConfigured(levelId: number): boolean {
- const config = this.levelConfigs.find(c => c.levelId === levelId);
- return config !== undefined && config.configFile !== null;
- }
- /**
- * 获取总关卡数
- */
- public getTotalLevels(): number {
- return this.totalLevels;
- }
- /**
- * 重新加载所有关卡配置(开发调试用)
- */
- public reloadAllConfigs() {
- this.loadedConfigs.clear();
- this.validateConfigs();
- }
- /**
- * 创建示例关卡配置(开发辅助)
- */
- public generateSampleConfig(levelId: number): LevelConfig {
- const samples = {
- 1: {
- name: '新手引导(草地平原)',
- scene: 'grassland',
- backgroundImage: 'images/LevelBackground/BG1',
- weapons: ['毛豆射手', '尖胡萝卜'],
- waves: [
- {
- waveId: 1,
- enemies: [
- { enemyType: '普通僵尸', count: 8, spawnInterval: 5, characteristics: ['中速移动', '无技能'] }
- ]
- },
- {
- waveId: 2,
- enemies: [
- { enemyType: '普通僵尸', count: 10, spawnInterval: 5, characteristics: ['中速移动', '无技能'] }
- ]
- },
- {
- waveId: 3,
- enemies: [
- { enemyType: '路障僵尸', count: 5, spawnInterval: 6, characteristics: ['高生命', '慢速移动'] }
- ]
- }
- ]
- },
- 2: {
- name: '丛林探险(森林场景)',
- scene: 'forest',
- backgroundImage: 'images/LevelBackground/BG2',
- weapons: ['锯齿草', '西瓜炸弹', '毛豆射手'],
- waves: [
- {
- waveId: 1,
- enemies: [
- { enemyType: '普通僵尸', count: 10, spawnInterval: 4, characteristics: ['中速移动', '无技能'] }
- ]
- },
- {
- waveId: 2,
- enemies: [
- { enemyType: '漫步僵尸', count: 6, spawnInterval: 5, characteristics: ['左右摇摆', '近战范围大'] }
- ]
- }
- ]
- }
- };
- return samples[levelId] || samples[1];
- }
- /**
- * 调试:打印所有关卡配置信息
- */
- public debugPrintAllConfigs() {
- console.log(`=== 所有关卡配置信息 ===`);
- console.log(`总关卡数: ${this.totalLevels}`);
-
- for (const config of this.levelConfigs) {
- console.log(`关卡 ${config.levelId}: ${config.levelName}`);
- console.log(` JSON文件: ${config.configFile ? config.configFile.name : '未设置'}`);
- }
- }
- }
|