|
|
@@ -11,6 +11,7 @@ import { Wall } from './Wall';
|
|
|
import { BurnEffect } from './BulletEffects/BurnEffect';
|
|
|
import { Audio } from '../AudioManager/AudioManager';
|
|
|
import { BundleLoader } from '../Core/BundleLoader';
|
|
|
+import { ResourcePreloader } from '../Core/ResourcePreloader';
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
|
|
|
@@ -106,6 +107,9 @@ export class EnemyController extends BaseSingleton {
|
|
|
// 关卡配置管理器
|
|
|
private levelConfigManager: LevelConfigManager = null;
|
|
|
|
|
|
+ // 资源预加载管理器
|
|
|
+ private resourcePreloader: ResourcePreloader = null;
|
|
|
+
|
|
|
// 当前关卡血量倍率
|
|
|
private currentHealthMultiplier: number = 1.0;
|
|
|
private currentWaveHealthMultiplier: number = 1.0; // 当前波次的血量系数
|
|
|
@@ -150,6 +154,9 @@ export class EnemyController extends BaseSingleton {
|
|
|
// 获取配置管理器实例
|
|
|
this.configManager = ConfigManager.getInstance();
|
|
|
|
|
|
+ // 获取资源预加载管理器实例
|
|
|
+ this.resourcePreloader = ResourcePreloader.getInstance();
|
|
|
+
|
|
|
// 获取关卡配置管理器实例
|
|
|
if (this.levelConfigManagerNode) {
|
|
|
this.levelConfigManager = this.levelConfigManagerNode.getComponent(LevelConfigManager) || null;
|
|
|
@@ -200,10 +207,44 @@ export class EnemyController extends BaseSingleton {
|
|
|
// 初始化敌人数量显示
|
|
|
this.updateEnemyCountLabel();
|
|
|
|
|
|
+ // 延迟验证Line节点绑定(解决微信平台初始化时序问题)
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ this.validateLineNodes();
|
|
|
+ }, 0.1);
|
|
|
+
|
|
|
// 监听游戏事件
|
|
|
this.setupEventListeners();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 验证Line节点绑定(解决微信平台初始化时序问题)
|
|
|
+ */
|
|
|
+ private validateLineNodes() {
|
|
|
+ // 验证Line5节点
|
|
|
+ if (!this.line5Node && this.enemyContainer) {
|
|
|
+ this.line5Node = this.enemyContainer.getChildByName('Line5');
|
|
|
+ if (this.line5Node) {
|
|
|
+ console.log('[EnemyController] Line5节点重新绑定成功');
|
|
|
+ } else {
|
|
|
+ console.warn('[EnemyController] Line5节点未找到');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证Line6节点
|
|
|
+ if (!this.line6Node && this.enemyContainer) {
|
|
|
+ this.line6Node = this.enemyContainer.getChildByName('Line6');
|
|
|
+ if (this.line6Node) {
|
|
|
+ console.log('[EnemyController] Line6节点重新绑定成功');
|
|
|
+ } else {
|
|
|
+ console.warn('[EnemyController] Line6节点未找到');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 输出当前Line节点状态
|
|
|
+ console.log('[EnemyController] Line5节点状态:', this.line5Node ? '已绑定' : '未绑定');
|
|
|
+ console.log('[EnemyController] Line6节点状态:', this.line6Node ? '已绑定' : '未绑定');
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 设置事件监听器
|
|
|
*/
|
|
|
@@ -279,6 +320,70 @@ export class EnemyController extends BaseSingleton {
|
|
|
return 1.0;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取当前波次的血量倍率(从关卡配置中读取)
|
|
|
+ */
|
|
|
+ private async getWaveHealthMultiplier(): Promise<number> {
|
|
|
+ if (!this.levelConfigManager) {
|
|
|
+ return 1.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const saveDataManager = SaveDataManager.getInstance();
|
|
|
+ const currentLevel = saveDataManager ? saveDataManager.getCurrentLevel() : 1;
|
|
|
+ const levelConfig = await this.levelConfigManager.getLevelConfig(currentLevel);
|
|
|
+
|
|
|
+ if (levelConfig && levelConfig.waves && levelConfig.waves.length > 0) {
|
|
|
+ // 查找当前波次的配置
|
|
|
+ const currentWaveConfig = levelConfig.waves.find(wave => wave.waveId === this.currentWave);
|
|
|
+ if (currentWaveConfig && typeof currentWaveConfig.healthMultiplier === 'number') {
|
|
|
+ console.log(`[EnemyController] 从关卡配置获取波次 ${this.currentWave} 血量倍率: ${currentWaveConfig.healthMultiplier}`);
|
|
|
+ return currentWaveConfig.healthMultiplier;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('[EnemyController] 获取波次血量倍率失败:', error);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算最终的敌人血量倍率
|
|
|
+ * 综合考虑:关卡基础倍率 × 波次倍率 × 敌人个体倍率
|
|
|
+ */
|
|
|
+ /**
|
|
|
+ * 计算最终血量倍率(关卡 × 波次)
|
|
|
+ */
|
|
|
+ private async calculateFinalHealthMultiplier(): Promise<number> {
|
|
|
+ try {
|
|
|
+ // 1. 获取关卡基础血量倍率
|
|
|
+ let levelMultiplier = 1.0;
|
|
|
+ if (this.levelConfigManager) {
|
|
|
+ const saveDataManager = SaveDataManager.getInstance();
|
|
|
+ const currentLevel = saveDataManager ? saveDataManager.getCurrentLevel() : 1;
|
|
|
+ const levelConfig = await this.levelConfigManager.getLevelConfig(currentLevel);
|
|
|
+
|
|
|
+ if (levelConfig && typeof levelConfig.levelSettings.healthMultiplier === 'number') {
|
|
|
+ levelMultiplier = levelConfig.levelSettings.healthMultiplier;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取当前波次血量倍率
|
|
|
+ const waveMultiplier = await this.getWaveHealthMultiplier();
|
|
|
+
|
|
|
+ // 3. 计算最终倍率:关卡倍率 × 波次倍率
|
|
|
+ const finalMultiplier = levelMultiplier * waveMultiplier;
|
|
|
+
|
|
|
+ console.log(`[EnemyController] 血量倍率计算 - 关卡: ${levelMultiplier}, 波次: ${waveMultiplier}, 最终: ${finalMultiplier}`);
|
|
|
+
|
|
|
+ return finalMultiplier;
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('[EnemyController] 计算最终血量倍率失败:', error);
|
|
|
+ return 1.0; // 返回默认倍率
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 处理游戏暂停事件
|
|
|
*/
|
|
|
@@ -759,20 +864,8 @@ export class EnemyController extends BaseSingleton {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 获取当前敌人的血量倍率
|
|
|
- let healthMultiplier = 1.0;
|
|
|
- if (this.currentWaveEnemyConfigs.length > 0) {
|
|
|
- const configIndex = this.currentWaveEnemiesSpawned % this.currentWaveEnemyConfigs.length;
|
|
|
- const enemyTypeConfig = this.currentWaveEnemyConfigs[configIndex];
|
|
|
- if (enemyTypeConfig && typeof enemyTypeConfig.healthMultiplier === 'number') {
|
|
|
- healthMultiplier = enemyTypeConfig.healthMultiplier;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 如果没有找到敌人配置中的血量系数,则使用波次级别的血量系数作为备用
|
|
|
- if (healthMultiplier === 1.0) {
|
|
|
- healthMultiplier = await this.getCurrentHealthMultiplier();
|
|
|
- }
|
|
|
+ // 计算最终血量倍率(关卡 × 波次)
|
|
|
+ const finalHealthMultiplier = await this.calculateFinalHealthMultiplier();
|
|
|
|
|
|
if (enemyConfig && enemyId) {
|
|
|
try {
|
|
|
@@ -790,15 +883,15 @@ export class EnemyController extends BaseSingleton {
|
|
|
|
|
|
// 应用血量倍率
|
|
|
const baseHealth = enemyComp.health || this.defaultHealth;
|
|
|
- const finalHealth = Math.round(baseHealth * healthMultiplier);
|
|
|
+ const finalHealth = Math.round(baseHealth * finalHealthMultiplier);
|
|
|
enemyComp.health = finalHealth;
|
|
|
enemyComp.maxHealth = finalHealth;
|
|
|
|
|
|
- console.log(`[EnemyController] 敌人 ${enemyId} 配置已应用,血量: ${finalHealth} (系数: ${healthMultiplier})`);
|
|
|
+ console.log(`[EnemyController] 敌人 ${enemyId} 配置已应用,血量: ${finalHealth} (最终倍率: ${finalHealthMultiplier})`);
|
|
|
} catch (error) {
|
|
|
console.error(`[EnemyController] 应用敌人配置时出错:`, error);
|
|
|
// 使用默认值
|
|
|
- const finalHealth = Math.round(this.defaultHealth * healthMultiplier);
|
|
|
+ const finalHealth = Math.round(this.defaultHealth * finalHealthMultiplier);
|
|
|
enemyComp.health = finalHealth;
|
|
|
enemyComp.maxHealth = finalHealth;
|
|
|
enemyComp.speed = this.defaultEnemySpeed;
|
|
|
@@ -812,13 +905,13 @@ export class EnemyController extends BaseSingleton {
|
|
|
try {
|
|
|
enemyComp.setEnemyConfig('normal_zombie'); // 默认敌人类型
|
|
|
const baseHealth = enemyComp.health || this.defaultHealth;
|
|
|
- const finalHealth = Math.round(baseHealth * healthMultiplier);
|
|
|
+ const finalHealth = Math.round(baseHealth * finalHealthMultiplier);
|
|
|
enemyComp.health = finalHealth;
|
|
|
enemyComp.maxHealth = finalHealth;
|
|
|
} catch (error) {
|
|
|
console.error(`[EnemyController] 应用默认敌人配置时出错:`, error);
|
|
|
// 使用硬编码默认值
|
|
|
- const finalHealth = Math.round(this.defaultHealth * healthMultiplier);
|
|
|
+ const finalHealth = Math.round(this.defaultHealth * finalHealthMultiplier);
|
|
|
enemyComp.health = finalHealth;
|
|
|
enemyComp.maxHealth = finalHealth;
|
|
|
enemyComp.speed = this.defaultEnemySpeed;
|
|
|
@@ -1187,38 +1280,52 @@ export class EnemyController extends BaseSingleton {
|
|
|
|
|
|
console.log(`[EnemyController] 最终加载路径: ${spinePath}`);
|
|
|
|
|
|
- BundleLoader.loadSkeletonData(spinePath).then((skeletonData) => {
|
|
|
- if (!skeletonData) {
|
|
|
- console.warn(`加载敌人Spine动画失败: ${spinePath}`);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 获取EnemySprite子节点
|
|
|
- const enemySprite = enemyNode.getChildByName('EnemySprite');
|
|
|
- if (!enemySprite) {
|
|
|
- console.error('[EnemyController] 未找到EnemySprite子节点,无法设置骨骼动画');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let skeleton = enemySprite.getComponent(sp.Skeleton);
|
|
|
- if (!skeleton) {
|
|
|
- skeleton = enemySprite.addComponent(sp.Skeleton);
|
|
|
- }
|
|
|
- skeleton.skeletonData = skeletonData;
|
|
|
+ // 优先使用预加载的资源
|
|
|
+ let skeletonData = this.resourcePreloader.getPreloadedEnemyAnimation(spinePath);
|
|
|
+
|
|
|
+ if (skeletonData) {
|
|
|
+ console.log(`[EnemyController] 使用预加载的敌人动画: ${spinePath}`);
|
|
|
+ this.applySkeletonData(enemyNode, enemyConfig, skeletonData);
|
|
|
+ } else {
|
|
|
+ console.log(`[EnemyController] 预加载资源未找到,动态加载: ${spinePath}`);
|
|
|
+ BundleLoader.loadSkeletonData(spinePath).then((dynamicSkeletonData) => {
|
|
|
+ if (!dynamicSkeletonData) {
|
|
|
+ console.warn(`加载敌人Spine动画失败: ${spinePath}`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.applySkeletonData(enemyNode, enemyConfig, dynamicSkeletonData);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- const anims = enemyConfig.visualConfig.animations;
|
|
|
- const walkName = anims?.walk ?? 'walk';
|
|
|
- const idleName = anims?.idle ?? 'idle';
|
|
|
+ /**
|
|
|
+ * 应用骨骼动画数据到敌人节点
|
|
|
+ */
|
|
|
+ private applySkeletonData(enemyNode: Node, enemyConfig: EnemyConfig, skeletonData: any) {
|
|
|
+ // 获取EnemySprite子节点
|
|
|
+ const enemySprite = enemyNode.getChildByName('EnemySprite');
|
|
|
+ if (!enemySprite) {
|
|
|
+ console.error('[EnemyController] 未找到EnemySprite子节点,无法设置骨骼动画');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let skeleton = enemySprite.getComponent(sp.Skeleton);
|
|
|
+ if (!skeleton) {
|
|
|
+ skeleton = enemySprite.addComponent(sp.Skeleton);
|
|
|
+ }
|
|
|
+ skeleton.skeletonData = skeletonData;
|
|
|
|
|
|
+ const anims = enemyConfig.visualConfig.animations;
|
|
|
+ const walkName = anims?.walk ?? 'walk';
|
|
|
+ const idleName = anims?.idle ?? 'idle';
|
|
|
|
|
|
- if (skeleton.findAnimation(walkName)) {
|
|
|
- skeleton.setAnimation(0, walkName, true);
|
|
|
- } else if (skeleton.findAnimation(idleName)) {
|
|
|
- skeleton.setAnimation(0, idleName, true);
|
|
|
- } else {
|
|
|
- console.warn(`[EnemyController] 未找到合适的动画,walk: ${walkName}, idle: ${idleName}`);
|
|
|
- }
|
|
|
- });
|
|
|
+ if (skeleton.findAnimation(walkName)) {
|
|
|
+ skeleton.setAnimation(0, walkName, true);
|
|
|
+ } else if (skeleton.findAnimation(idleName)) {
|
|
|
+ skeleton.setAnimation(0, idleName, true);
|
|
|
+ } else {
|
|
|
+ console.warn(`[EnemyController] 未找到合适的动画,walk: ${walkName}, idle: ${idleName}`);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 更新敌人数量显示
|
|
|
@@ -1362,6 +1469,7 @@ export class EnemyController extends BaseSingleton {
|
|
|
|
|
|
// 重置血量倍率
|
|
|
this.currentHealthMultiplier = 1.0;
|
|
|
+ this.currentWaveHealthMultiplier = 1.0;
|
|
|
|
|
|
// 清空暂停状态
|
|
|
this.pausedEnemyStates.clear();
|