import { _decorator, resources, JsonAsset } from 'cc'; import { BaseSingleton } from './BaseSingleton'; const { ccclass, property } = _decorator; // 局内金币花费配置接口 export interface InGameCostConfig { baseCost: number; shapeCosts: { [shapeId: string]: number; }; } // 弹道配置接口 export interface BulletTrajectoryConfig { type: string; speed: number; gravity: number; arcHeight: number; homingStrength: number; homingDelay: number; rotateSpeed?: number; // 旋转速率 (0~1),仅在 arc 弹道中使用 } // 弹药数量配置接口 export interface BulletCountConfig { type: string; amount: number; spreadAngle: number; burstCount: number; burstDelay: number; } // 命中效果配置接口 export interface HitEffectConfig { type: string; priority: number; damage?: number; pierceCount?: number; radius?: number; delay?: number; duration?: number; tickInterval?: number; ricochetCount?: number; ricochetAngle?: number; [key: string]: any; } // 弹药生命周期配置接口 export interface BulletLifecycleConfig { type: string; maxLifetime: number; penetration: number; ricochetCount: number; returnToOrigin: boolean; returnDelay?: number; // 返回延迟(秒) maxRange?: number; // 最大射程 effectDuration?: number; // 效果持续时间(用于地面效果) } // 武器配置接口 export interface WeaponConfig { id: string; name: string; type: string; rarity?: string; // 可选字段,支持动态稀有度(合成时可变) stats: { damage: number; fireRate: number; range: number; bulletSpeed: number; accuracy?: number; }; bulletConfig: { count: BulletCountConfig; trajectory: BulletTrajectoryConfig; hitEffects: HitEffectConfig[]; lifecycle: BulletLifecycleConfig; visual: { bulletImages: string; hitEffect: string; trailEffect?: string; explosionEffect?: string; }; }; visualConfig: { weaponSprites: { [shapeId: string]: string; }; attackSound: string; }; upgradeConfig: { maxLevel: number; levels: { [level: string]: { cost: number; damage?: number; }; }; }; // 运行时计算的实际数值(应用技能加成后) runtimeStats?: { finalDamage: number; finalCritDamage: number; critChance: number; }; inGameCostConfig?: InGameCostConfig; } // 球控制器配置接口 export interface BallControllerConfig { baseSpeed: number; maxReflectionRandomness: number; antiTrapTimeWindow: number; antiTrapHitThreshold: number; deflectionAttemptThreshold: number; antiTrapDeflectionMultiplier: number; FIRE_COOLDOWN: number; ballRadius: number; gravityScale: number; linearDamping: number; angularDamping: number; colliderGroup: number; colliderTag: number; friction: number; restitution: number; safeDistance: number; edgeOffset: number; sensor: boolean; maxAttempts: number; } // 敌人配置接口 export interface EnemyConfig { id: string; name: string; type: string; rarity: string; health: number; speed: number; attack: number; range: number; attackSpeed: number; defense: number; goldReward: number; explosionDamage?: number; explosionRadius?: number; movement: { type: string; pattern: string; speedVariation: number; swayAmplitude?: number; swayFrequency?: number; }; combat: { attackType: string; attackDelay: number; attackCooldown: number; weaponType?: string; projectileType?: string; projectileSpeed?: number; canBlock: boolean; blockChance: number; }; visualConfig: { spritePath: string; animations: { [state: string]: string; }; scale: number; flipX: boolean; weapon?: string; armor?: string; prop?: string; }; audioConfig: { [sound: string]: string; }; specialAbilities: string[]; stealthConfig?: { stealthDuration: number; stealthCooldown: number; revealOnAttack: boolean; visibilityAlpha: number; }; armorConfig?: { armorHealth: number; armorReduction: number; breakThreshold: number; }; explosionConfig?: { explosionDelay: number; explosionEffect: string; damageRadius: number; knockbackForce: number; }; bossConfig?: { phases: number; phaseHealthThreshold: number; enrageBonus?: { speed: number; damage: number; attackSpeed: number; }; summonAbility?: { minionType: string; summonCount: number; summonCooldown: number; }; laserAbility?: { damage: number; range: number; chargeTime: number; cooldown: number; }; }; projectileConfig?: { bulletImages: string; hitEffect: string; trailEffect?: string; }; } @ccclass('ConfigManager') export class ConfigManager extends BaseSingleton { // 仅用于类型声明,实例由 BaseSingleton 在运行时动态维护 public static _instance: ConfigManager; private weaponsConfig: any = null; private enemiesConfig: any = null; private configLoaded: boolean = false; /** * BaseSingleton 首次实例化回调 */ protected init() { console.log('[ConfigManager] 开始初始化配置管理器'); this.loadConfigs(); } // 加载所有配置文件 private async loadConfigs() { console.log('[ConfigManager] 开始加载配置文件'); this.configLoaded = false; try { // 确保resources bundle已经准备好 await this.ensureResourcesBundle(); // 加载武器配置 console.log('[ConfigManager] 开始加载武器配置'); await this.loadWeaponsConfig(); console.log('[ConfigManager] 武器配置加载完成'); // 加载敌人配置 console.log('[ConfigManager] 开始加载敌人配置'); await this.loadEnemiesConfig(); console.log('[ConfigManager] 敌人配置加载完成'); // 注意:球控制器配置现在通过BallController组件的装饰器直接加载 console.log('[ConfigManager] 球控制器配置通过装饰器加载,跳过ConfigManager加载'); this.configLoaded = true; console.log('[ConfigManager] ✅ 所有配置文件加载成功,配置管理器初始化完成'); } catch (error) { console.error('[ConfigManager] ❌ 配置文件加载失败:', error); this.configLoaded = false; // 延迟重试加载 console.log('[ConfigManager] 将在3秒后重试加载配置'); setTimeout(() => { console.log('[ConfigManager] 开始重试加载配置'); this.loadConfigs(); }, 3000); } } // 确保resources bundle已经准备好 private ensureResourcesBundle(): Promise { return new Promise((resolve) => { console.log('[ConfigManager] 检查resources bundle状态...'); // 增加延迟时间,确保Cocos Creator资源系统完全初始化 setTimeout(() => { console.log('[ConfigManager] resources bundle初始化等待完成'); resolve(); }, 2000); // 增加到2秒 }); } // 加载武器配置 private loadWeaponsConfig(): Promise { return new Promise((resolve, reject) => { console.log('[ConfigManager] 开始加载武器配置...'); resources.load('data/weapons', JsonAsset, (err, asset) => { if (err) { console.error('[ConfigManager] 武器配置文件加载失败:', err); reject(err); return; } if (!asset || !asset.json) { console.error('[ConfigManager] 武器配置文件内容为空'); reject(new Error('武器配置文件内容为空')); return; } this.weaponsConfig = asset.json as any; // 验证配置完整性 console.log('[ConfigManager] 验证武器配置完整性...'); if (!this.weaponsConfig.weapons || !Array.isArray(this.weaponsConfig.weapons)) { console.error('[ConfigManager] 武器配置格式错误:缺少weapons数组'); reject(new Error('武器配置格式错误')); return; } console.log(`[ConfigManager] 武器配置加载成功,共${this.weaponsConfig.weapons.length}个武器`); // 检查blockSizes配置 if (this.weaponsConfig.blockSizes && Array.isArray(this.weaponsConfig.blockSizes)) { console.log(`[ConfigManager] ✅ blockSizes配置加载成功,共${this.weaponsConfig.blockSizes.length}个形状`); this.weaponsConfig.blockSizes.forEach(shape => { console.log(`[ConfigManager] - 形状: ${shape.id} (${shape.name})`); }); } else { console.warn('[ConfigManager] ⚠️ blockSizes配置缺失或格式错误'); } resolve(); }); }); } // 加载敌人配置 private loadEnemiesConfig(): Promise { return new Promise((resolve, reject) => { console.log('加载敌人配置...'); resources.load('data/enemies', JsonAsset, (err, asset) => { if (err) { console.error('敌人配置文件加载失败:', err); reject(err); return; } if (!asset || !asset.json) { console.error('敌人配置文件内容为空'); reject(new Error('敌人配置文件内容为空')); return; } this.enemiesConfig = asset.json as any; console.log('✅ 敌人配置加载成功'); resolve(); }); }); } // 随机获取武器配置 public getRandomWeapon(rarity?: string): WeaponConfig | null { if (!this.weaponsConfig || !this.weaponsConfig.weapons || this.weaponsConfig.weapons.length === 0) { console.warn('武器配置未加载或为空'); return null; } if (rarity) { // 按稀有度筛选 const filteredWeapons = this.weaponsConfig.weapons.filter(weapon => weapon.rarity === rarity); if (filteredWeapons.length === 0) { console.warn(`没有找到稀有度为 ${rarity} 的武器`); return null; } const randomIndex = Math.floor(Math.random() * filteredWeapons.length); return filteredWeapons[randomIndex]; } // 使用稀有度权重系统进行随机选择 const rarityWeights = this.weaponsConfig.rarityWeights; if (!rarityWeights) { console.warn('稀有度权重配置未找到,使用随机选择'); const randomIndex = Math.floor(Math.random() * this.weaponsConfig.weapons.length); return this.weaponsConfig.weapons[randomIndex]; } // 计算总权重 // 计算总权重(兼容ES5) const totalWeight = Object.keys(rarityWeights).reduce((sum: number, key: string) => sum + (rarityWeights[key] as number), 0); const randomValue = Math.random() * totalWeight; // 根据权重选择稀有度 let currentWeight = 0; let selectedRarity = 'common'; // 兼容ES5的写法遍历对象 for (let rarity in rarityWeights) { if (rarityWeights.hasOwnProperty(rarity)) { const weight = rarityWeights[rarity]; currentWeight += weight as number; if (randomValue <= currentWeight) { selectedRarity = rarity; break; } } // 从选中的稀有度中随机选择武器 const weaponsOfRarity = this.weaponsConfig.weapons.filter(weapon => weapon.rarity === selectedRarity); if (weaponsOfRarity.length === 0) { console.warn(`稀有度 ${selectedRarity} 没有可用武器,使用随机选择`); const randomIndex = Math.floor(Math.random() * this.weaponsConfig.weapons.length); return this.weaponsConfig.weapons[randomIndex]; } const randomIndex = Math.floor(Math.random() * weaponsOfRarity.length); const selectedWeapon = weaponsOfRarity[randomIndex]; console.log(`随机选择武器: ${selectedWeapon.name} (${selectedRarity})`); return selectedWeapon; } } // 随机获取敌人配置 public getRandomEnemy(rarity?: string): EnemyConfig | null { // 修复:enemies.json是直接的数组结构,不需要.enemies包装 if (!this.enemiesConfig || !Array.isArray(this.enemiesConfig) || this.enemiesConfig.length === 0) { console.warn('敌人配置未加载或为空'); return null; } if (rarity) { // 按稀有度筛选 const filteredEnemies = this.enemiesConfig.filter(enemy => enemy.rarity === rarity); if (filteredEnemies.length === 0) { console.warn(`没有找到稀有度为 ${rarity} 的敌人`); return null; } const randomIndex = Math.floor(Math.random() * filteredEnemies.length); return filteredEnemies[randomIndex]; } // 直接从敌人列表中随机选择 const randomIndex = Math.floor(Math.random() * this.enemiesConfig.length); return this.enemiesConfig[randomIndex]; } // 根据ID获取武器配置 public getWeaponById(id: string): WeaponConfig | null { if (!this.weaponsConfig) return null; return this.weaponsConfig.weapons.find(weapon => weapon.id === id) || null; } // 根据ID获取敌人配置 public getEnemyById(id: string): EnemyConfig | null { // 修复:enemies.json是直接的数组结构,不需要.enemies包装 if (!this.enemiesConfig || !Array.isArray(this.enemiesConfig)) return null; return this.enemiesConfig.find(enemy => enemy.id === id) || null; } /** * 获取敌人名称到ID的映射 */ public getNameToIdMapping(): { [key: string]: string } | null { if (!this.enemiesConfig) return null; return this.enemiesConfig.nameToIdMapping || null; } // 获取所有武器配置 public getAllWeapons(): WeaponConfig[] { return this.weaponsConfig?.weapons || []; } // 获取所有敌人配置 public getAllEnemies(): EnemyConfig[] { // 修复:enemies.json是直接的数组结构,不需要.enemies包装 return Array.isArray(this.enemiesConfig) ? this.enemiesConfig : []; } // 根据稀有度获取武器列表 public getWeaponsByRarity(rarity: string): WeaponConfig[] { if (!this.weaponsConfig) return []; return this.weaponsConfig.weapons.filter(weapon => weapon.rarity === rarity); } // 根据稀有度获取敌人列表 public getEnemiesByRarity(rarity: string): EnemyConfig[] { // 修复:enemies.json是直接的数组结构,不需要.enemies包装 if (!this.enemiesConfig || !Array.isArray(this.enemiesConfig)) return []; return this.enemiesConfig.filter(enemy => enemy.rarity === rarity); } // 获取方块尺寸列表(已更新为形状ID) public getBlockSizes(): string[] { if (!this.weaponsConfig || !this.weaponsConfig.blockSizes) { return ['I', 'H-I', 'L', 'S', 'D-T']; } // 从blockSizes配置中提取形状ID return this.weaponsConfig.blockSizes.map((shape: any) => shape.id); } // 获取方块形状配置列表 public getBlockShapes(): any[] { if (!this.weaponsConfig) { console.warn('[ConfigManager] 武器配置未加载,无法获取方块形状配置'); console.warn('[ConfigManager] 配置加载状态:', this.configLoaded); return []; } if (!this.weaponsConfig.blockSizes) { console.warn('[ConfigManager] 方块形状配置(blockSizes)未找到'); console.warn('[ConfigManager] 可用的配置字段:', Object.keys(this.weaponsConfig)); return []; } if (!Array.isArray(this.weaponsConfig.blockSizes)) { console.error('[ConfigManager] blockSizes不是数组格式:', typeof this.weaponsConfig.blockSizes); return []; } console.log(`[ConfigManager] 成功获取${this.weaponsConfig.blockSizes.length}个方块形状配置`); return this.weaponsConfig.blockSizes; } // 获取波次进展配置(已废弃,波次配置现在通过关卡系统管理) public getWaveProgression(): any { console.warn('[ConfigManager] getWaveProgression已废弃,波次配置现在通过关卡系统管理'); return {}; } // 根据波次获取合适的敌人(简化版本,直接返回随机敌人) public getEnemyForWave(waveNumber: number): EnemyConfig | null { // 修复:波次配置现在通过关卡系统管理,这里简化为返回随机敌人 // 具体的波次敌人配置由EnemyController通过关卡配置处理 console.log(`[ConfigManager] 为波次 ${waveNumber} 获取随机敌人`); return this.getRandomEnemy(); } // 检查配置是否已加载 public isConfigLoaded(): boolean { return this.configLoaded; } // 获取球控制器配置 // getBallControllerConfig方法已移除,球控制器配置现在通过装饰器直接在BallController中加载 }