فهرست منبع

完成关卡配置重构

181404010226 3 ماه پیش
والد
کامیت
3820714b19

+ 101 - 0
assets/resources/data/backups/levels/Level1_20250820_104752.json

@@ -0,0 +1,101 @@
+{
+  "levelId": "Level1",
+  "name": "新手关卡(草地平原)",
+  "scene": "grassland",
+  "description": "新手引导关卡,学习基础塔防玩法",
+  "backgroundImage": "images/LevelBackground/BG1",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹"
+  ],
+  "coinReward": 300,
+  "diamondReward": 20,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 1.0,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 10,
+          "spawnInterval": 2.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 15,
+          "spawnInterval": 1.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 20,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 5,
+          "spawnInterval": 3.0,
+          "spawnDelay": 5.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 4,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 30,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 10,
+          "spawnInterval": 2.0,
+          "spawnDelay": 0.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 5,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 30,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 30,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    }
+  ]
+}

+ 148 - 0
assets/resources/data/backups/levels/Level2_20250820_104752.json

@@ -0,0 +1,148 @@
+{
+  "levelId": "Level2",
+  "name": "丛林冒险(森林场景)",
+  "scene": "forest",
+  "description": "森林场景的塔防挑战,引入新的敌人类型和武器组合",
+  "backgroundImage": "images/LevelBackground/BG2",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹"
+  ],
+  "coinReward": 500,
+  "diamondReward": 30,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 1.2,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 10,
+          "spawnInterval": 2.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 5,
+          "spawnInterval": 2.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 20,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 8,
+          "spawnInterval": 2.0,
+          "spawnDelay": 0.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 30,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 20,
+          "spawnInterval": 1.5,
+          "spawnDelay": 0.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 4,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 40,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 30,
+          "spawnInterval": 1.0,
+          "spawnDelay": 10.0,
+          "characteristics": "中速移动, 无技能"
+        }
+      ]
+    },
+    {
+      "waveId": 5,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 60,
+          "spawnInterval": 0.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 10,
+          "spawnInterval": 3.0,
+          "spawnDelay": 0.0,
+          "characteristics": "远程魔法攻击, 中等生命"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 40,
+          "spawnInterval": 0.8,
+          "spawnDelay": 0.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 6,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 60,
+          "spawnInterval": 0.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 60,
+          "spawnInterval": 0.5,
+          "spawnDelay": 0.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "boss1_gatekeeper",
+          "count": 1,
+          "spawnInterval": 1.0,
+          "spawnDelay": 20.0,
+          "characteristics": "超高生命, 多种攻击方式, 召唤小怪"
+        }
+      ]
+    }
+  ]
+}

+ 91 - 0
assets/resources/data/backups/levels/Level3_20250820_104752.json

@@ -0,0 +1,91 @@
+{
+  "levelId": "Level3",
+  "name": "魔法废墟(魔幻场景)",
+  "scene": "magic_ruins",
+  "description": "魔幻场景的塔防挑战,引入远程攻击敌人和隐身机制",
+  "backgroundImage": "images/LevelBackground/BG3",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹"
+  ],
+  "coinReward": 800,
+  "diamondReward": 50,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 1.4,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 12,
+          "spawnInterval": 2.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 3,
+          "spawnInterval": 8.0,
+          "spawnDelay": 15.0,
+          "characteristics": "远程魔法攻击, 中等生命"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 10,
+          "spawnInterval": 2.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 4,
+          "spawnInterval": 6.0,
+          "spawnDelay": 8.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 4,
+          "spawnInterval": 7.0,
+          "spawnDelay": 20.0,
+          "characteristics": "远程魔法攻击, 中等生命"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 8,
+          "spawnInterval": 1.8,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 6,
+          "spawnInterval": 5.0,
+          "spawnDelay": 10.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 5,
+          "spawnInterval": 6.0,
+          "spawnDelay": 25.0,
+          "characteristics": "远程魔法攻击, 中等生命"
+        }
+      ]
+    }
+  ]
+}

+ 95 - 0
assets/resources/data/backups/levels/Level4_20250820_104752.json

@@ -0,0 +1,95 @@
+{
+  "levelId": "Level4",
+  "name": "钢铁堡垒(工业场景)",
+  "scene": "industrial",
+  "description": "工业场景的高难度挑战,引入BOSS战和超高防御敌人",
+  "backgroundImage": "images/LevelBackground/BG1",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹",
+    "回旋镖盆栽",
+    "炙热辣椒",
+    "仙人散弹",
+    "秋葵导弹"
+  ],
+  "coinReward": 1000,
+  "diamondReward": 80,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 1.6,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 15,
+          "spawnInterval": 2.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 3,
+          "spawnInterval": 10.0,
+          "spawnDelay": 20.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 8,
+          "spawnInterval": 4.0,
+          "spawnDelay": 0.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 5,
+          "spawnInterval": 6.0,
+          "spawnDelay": 15.0,
+          "characteristics": "远程魔法攻击, 中等生命"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 4,
+          "spawnInterval": 8.0,
+          "spawnDelay": 25.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 10,
+          "spawnInterval": 1.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 6,
+          "spawnInterval": 3.5,
+          "spawnDelay": 8.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 5,
+          "spawnInterval": 7.0,
+          "spawnDelay": 20.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    }
+  ]
+}

+ 95 - 0
assets/resources/data/backups/levels/Level5_20250820_104752.json

@@ -0,0 +1,95 @@
+{
+  "levelId": "Level5",
+  "name": "终极挑战(赛博都市)",
+  "scene": "cyberpunk",
+  "description": "终极挑战关卡,包含多个BOSS和复杂的敌人组合",
+  "backgroundImage": "images/LevelBackground/BG1",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹",
+    "回旋镖盆栽",
+    "炙热辣椒",
+    "仙人散弹",
+    "秋葵导弹"
+  ],
+  "coinReward": 1300,
+  "diamondReward": 100,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 1.8,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 20,
+          "spawnInterval": 1.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 8,
+          "spawnInterval": 3.0,
+          "spawnDelay": 10.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "mage_zombie",
+          "count": 8,
+          "spawnInterval": 4.0,
+          "spawnDelay": 0.0,
+          "characteristics": "远程魔法攻击, 中等生命"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 6,
+          "spawnInterval": 6.0,
+          "spawnDelay": 15.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 15,
+          "spawnInterval": 1.2,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 10,
+          "spawnInterval": 2.5,
+          "spawnDelay": 8.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 8,
+          "spawnInterval": 3.5,
+          "spawnDelay": 20.0,
+          "characteristics": "远程魔法攻击, 中等生命"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 6,
+          "spawnInterval": 5.0,
+          "spawnDelay": 30.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    }
+  ]
+}

+ 95 - 0
assets/resources/data/backups/levels/Level6_20250820_104752.json

@@ -0,0 +1,95 @@
+{
+  "levelId": "Level6",
+  "name": "沙漠绿洲(沙漠场景)",
+  "scene": "desert",
+  "description": "沙漠场景的挑战,炎热环境下的生存战斗",
+  "backgroundImage": "images/LevelBackground/BG1",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹",
+    "回旋镖盆栽",
+    "炙热辣椒",
+    "仙人散弹",
+    "秋葵导弹"
+  ],
+  "coinReward": 1800,
+  "diamondReward": 120,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 2.0,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 18,
+          "spawnInterval": 1.8,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 4,
+          "spawnInterval": 6.0,
+          "spawnDelay": 12.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 15,
+          "spawnInterval": 1.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 5,
+          "spawnInterval": 5.0,
+          "spawnDelay": 8.0,
+          "characteristics": "远程魔法子弹攻击防御塔"
+        },
+        {
+          "enemyType": "archer_zombie",
+          "count": 3,
+          "spawnInterval": 8.0,
+          "spawnDelay": 15.0,
+          "characteristics": "远程弓箭攻击"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 20,
+          "spawnInterval": 1.2,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "stealth_zombie",
+          "count": 4,
+          "spawnInterval": 10.0,
+          "spawnDelay": 20.0,
+          "characteristics": "隐身能力, 快速移动"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 6,
+          "spawnInterval": 4.0,
+          "spawnDelay": 25.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    }
+  ]
+}

+ 107 - 0
assets/resources/data/backups/levels/Level7_20250820_104752.json

@@ -0,0 +1,107 @@
+{
+  "levelId": "Level7",
+  "name": "冰雪王国(冰雪场景)",
+  "scene": "ice",
+  "description": "冰雪场景的极地挑战,寒冷环境下的防御战",
+  "backgroundImage": "images/LevelBackground/BG1",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹",
+    "回旋镖盆栽",
+    "炙热辣椒",
+    "仙人散弹",
+    "秋葵导弹"
+  ],
+  "coinReward": 2200,
+  "diamondReward": 150,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 2.2,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 22,
+          "spawnInterval": 1.6,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 8,
+          "spawnInterval": 4.0,
+          "spawnDelay": 10.0,
+          "characteristics": "高生命, 慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 18,
+          "spawnInterval": 1.4,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "archer_zombie",
+          "count": 6,
+          "spawnInterval": 6.0,
+          "spawnDelay": 12.0,
+          "characteristics": "远程弓箭攻击"
+        },
+        {
+          "enemyType": "barrel_zombie",
+          "count": 3,
+          "spawnInterval": 12.0,
+          "spawnDelay": 20.0,
+          "characteristics": "爆炸伤害, 自爆攻击"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 25,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 8,
+          "spawnInterval": 3.0,
+          "spawnDelay": 15.0,
+          "characteristics": "超高生命, 极慢速移动"
+        },
+        {
+          "enemyType": "stealth_zombie",
+          "count": 5,
+          "spawnInterval": 8.0,
+          "spawnDelay": 25.0,
+          "characteristics": "隐身能力, 快速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 4,
+      "enemies": [
+        {
+          "enemyType": "boss1_gatekeeper",
+          "count": 1,
+          "spawnInterval": 0.0,
+          "spawnDelay": 30.0,
+          "characteristics": "超高生命, 多种攻击方式, 召唤小怪"
+        }
+      ]
+    }
+  ]
+}

+ 128 - 0
assets/resources/data/backups/levels/Level8_20250820_104752.json

@@ -0,0 +1,128 @@
+{
+  "levelId": "Level8",
+  "name": "火山熔岩(火山场景)",
+  "scene": "volcano",
+  "description": "火山场景的极限挑战,熔岩环境下的终极考验",
+  "backgroundImage": "images/LevelBackground/BG1",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹",
+    "回旋镖盆栽",
+    "炙热辣椒",
+    "仙人散弹",
+    "秋葵导弹"
+  ],
+  "coinReward": 2500,
+  "diamondReward": 170,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 2.4,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 30,
+          "spawnInterval": 1.2,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 10,
+          "spawnInterval": 3.0,
+          "spawnDelay": 8.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "wandering_zombie",
+          "count": 6,
+          "spawnInterval": 5.0,
+          "spawnDelay": 15.0,
+          "characteristics": "左右摇摆, 近战范围大"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 25,
+          "spawnInterval": 1.0,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 8,
+          "spawnInterval": 4.0,
+          "spawnDelay": 10.0,
+          "characteristics": "远程魔法子弹攻击防御塔"
+        },
+        {
+          "enemyType": "archer_zombie",
+          "count": 6,
+          "spawnInterval": 6.0,
+          "spawnDelay": 18.0,
+          "characteristics": "远程弓箭攻击"
+        },
+        {
+          "enemyType": "barrel_zombie",
+          "count": 4,
+          "spawnInterval": 10.0,
+          "spawnDelay": 25.0,
+          "characteristics": "爆炸伤害, 自爆攻击"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 20,
+          "spawnInterval": 0.8,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 12,
+          "spawnInterval": 2.5,
+          "spawnDelay": 12.0,
+          "characteristics": "超高生命, 极慢速移动"
+        },
+        {
+          "enemyType": "stealth_zombie",
+          "count": 8,
+          "spawnInterval": 6.0,
+          "spawnDelay": 20.0,
+          "characteristics": "隐身能力, 快速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 4,
+      "enemies": [
+        {
+          "enemyType": "boss2_gravedigger",
+          "count": 1,
+          "spawnInterval": 0.0,
+          "spawnDelay": 30.0,
+          "characteristics": "超高生命, 范围攻击, 召唤增援"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 6,
+          "spawnInterval": 8.0,
+          "spawnDelay": 45.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    }
+  ]
+}

+ 148 - 0
assets/resources/data/backups/levels/Level9_20250820_104752.json

@@ -0,0 +1,148 @@
+{
+  "levelId": "Level9",
+  "name": "终极试炼(终极场景)",
+  "scene": "ultimate",
+  "description": "终极试炼关卡,解锁最后的植物武器,面对最强挑战",
+  "backgroundImage": "images/LevelBackground/BG1",
+  "availableWeapons": [
+    "毛豆射手",
+    "尖胡萝卜",
+    "锯齿草",
+    "西瓜炸弹",
+    "回旋镖盆栽",
+    "炙热辣椒",
+    "仙人散弹",
+    "秋葵导弹",
+    "狼牙棒"
+  ],
+  "coinReward": 3000,
+  "diamondReward": 200,
+  "timeLimit": 300,
+  "difficulty": "normal",
+  "healthMultiplier": 2.6,
+  "waves": [
+    {
+      "waveId": 1,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 40,
+          "spawnInterval": 0.8,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "roadblock_zombie",
+          "count": 15,
+          "spawnInterval": 2.5,
+          "spawnDelay": 5.0,
+          "characteristics": "高生命, 慢速移动"
+        },
+        {
+          "enemyType": "wandering_zombie",
+          "count": 10,
+          "spawnInterval": 4.0,
+          "spawnDelay": 12.0,
+          "characteristics": "左右摇摆, 近战范围大"
+        }
+      ]
+    },
+    {
+      "waveId": 2,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 35,
+          "spawnInterval": 0.6,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "mage_zombie",
+          "count": 12,
+          "spawnInterval": 3.0,
+          "spawnDelay": 8.0,
+          "characteristics": "远程魔法子弹攻击防御塔"
+        },
+        {
+          "enemyType": "archer_zombie",
+          "count": 10,
+          "spawnInterval": 4.0,
+          "spawnDelay": 15.0,
+          "characteristics": "远程弓箭攻击"
+        },
+        {
+          "enemyType": "barrel_zombie",
+          "count": 6,
+          "spawnInterval": 8.0,
+          "spawnDelay": 22.0,
+          "characteristics": "爆炸伤害, 自爆攻击"
+        }
+      ]
+    },
+    {
+      "waveId": 3,
+      "enemies": [
+        {
+          "enemyType": "normal_zombie",
+          "count": 30,
+          "spawnInterval": 0.5,
+          "spawnDelay": 0.0,
+          "characteristics": "中速移动, 无技能"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 15,
+          "spawnInterval": 2.0,
+          "spawnDelay": 10.0,
+          "characteristics": "超高生命, 极慢速移动"
+        },
+        {
+          "enemyType": "stealth_zombie",
+          "count": 12,
+          "spawnInterval": 4.0,
+          "spawnDelay": 18.0,
+          "characteristics": "隐身能力, 快速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 4,
+      "enemies": [
+        {
+          "enemyType": "boss1_gatekeeper",
+          "count": 1,
+          "spawnInterval": 0.0,
+          "spawnDelay": 25.0,
+          "characteristics": "超高生命, 多种攻击方式, 召唤小怪"
+        },
+        {
+          "enemyType": "boss2_gravedigger",
+          "count": 1,
+          "spawnInterval": 0.0,
+          "spawnDelay": 60.0,
+          "characteristics": "超高生命, 范围攻击, 召唤增援"
+        },
+        {
+          "enemyType": "bucket_zombie",
+          "count": 10,
+          "spawnInterval": 6.0,
+          "spawnDelay": 40.0,
+          "characteristics": "超高生命, 极慢速移动"
+        }
+      ]
+    },
+    {
+      "waveId": 5,
+      "enemies": [
+        {
+          "enemyType": "终极BOSS",
+          "count": 1,
+          "spawnInterval": 0.0,
+          "spawnDelay": 30.0,
+          "characteristics": "极高生命, 全屏攻击, 无敌阶段, 召唤军团"
+        }
+      ]
+    }
+  ]
+}

BIN
assets/resources/data/excel/__pycache__/level_config_manager.cpython-313.pyc


+ 141 - 419
assets/resources/data/excel/config_manager.py

@@ -47,6 +47,13 @@ except ImportError:
     ENEMY_MANAGER_AVAILABLE = False
     print("警告: enemy_config_manager.py 未找到,敌人配置功能将不可用")
 
+try:
+    from level_config_manager import LevelConfigManager
+    LEVEL_MANAGER_AVAILABLE = True
+except ImportError:
+    LEVEL_MANAGER_AVAILABLE = False
+    print("警告: level_config_manager.py 未找到,关卡配置功能将不可用")
+
 class SkillConfigImporter:
     """技能配置表导入工具类"""
     def __init__(self, excel_dir=None):
@@ -471,14 +478,23 @@ class ConfigManagerGUI:
             ttk.Label(enemy_btn_frame, text="敌人配置管理器不可用", 
                      foreground="red").pack(side=tk.LEFT)
         
-
+        # 关卡配置专用按钮
+        level_btn_frame = ttk.Frame(right_frame)
+        level_btn_frame.grid(row=4, column=0, sticky=(tk.W, tk.E), pady=(10, 0))
+        
+        if LEVEL_MANAGER_AVAILABLE:
+            ttk.Button(level_btn_frame, text="导入关卡配置", 
+                      command=self.import_level_config).pack(side=tk.LEFT)
+        else:
+            ttk.Label(level_btn_frame, text="关卡配置管理器不可用", 
+                     foreground="red").pack(side=tk.LEFT)
         
         # 底部状态栏
         self.status_var = tk.StringVar()
         self.status_var.set("就绪")
         status_bar = ttk.Label(main_frame, textvariable=self.status_var, 
                               relief=tk.SUNKEN, anchor=tk.W)
-        status_bar.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(10, 0))
+        status_bar.grid(row=5, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(10, 0))
         
         # 绑定事件
         self.file_listbox.bind('<<ListboxSelect>>', self.on_file_select)
@@ -980,118 +996,7 @@ class ConfigManagerGUI:
         
         return config
     
-    def parse_level_multi_sheet_data(self, all_sheets_data, filename):
-        """解析关卡配置的多工作表数据"""
-        config = []
-        
-        try:
-            # 获取各个工作表的数据(支持中英文工作表名)
-            basic_config = None
-            for sheet_name in ['关卡基础配置', 'Level Config', 'levels', '关卡配置']:
-                if sheet_name in all_sheets_data:
-                    basic_config = all_sheets_data[sheet_name]
-                    break
-            
-            weapon_config = None
-            for sheet_name in ['关卡武器配置', 'Level Weapon Config', 'level_weapons', '武器配置']:
-                if sheet_name in all_sheets_data:
-                    weapon_config = all_sheets_data[sheet_name]
-                    break
-            
-            wave_config = None
-            for sheet_name in ['关卡波次配置', 'Wave Config', 'waves', '波次配置']:
-                if sheet_name in all_sheets_data:
-                    wave_config = all_sheets_data[sheet_name]
-                    break
-            
-            enemy_config = None
-            for sheet_name in ['敌人详细配置', 'Enemy Detail Config', 'enemy_details', '敌人配置']:
-                if sheet_name in all_sheets_data:
-                    enemy_config = all_sheets_data[sheet_name]
-                    break
-            
-            if basic_config is None:
-                print("错误: 未找到关卡基础配置工作表(支持的工作表名: 关卡基础配置, Level Config, levels, 关卡配置)")
-                return config
-            
-            # 处理每个关卡
-            for _, basic_row in basic_config.iterrows():
-                if pd.isna(basic_row['关卡ID']):
-                    continue
-                    
-                level_id = str(basic_row['关卡ID'])
-                
-                # 获取武器配置
-                available_weapons = []
-                if weapon_config is not None:
-                    weapon_rows = weapon_config[weapon_config['关卡ID'] == level_id]
-                    for _, weapon_row in weapon_rows.iterrows():
-                        if pd.notna(weapon_row['可用武器']):
-                            weapons_str = str(weapon_row['可用武器'])
-                            # 支持多种分隔符
-                            import re
-                            weapons = re.split(r'[、,,;;]', weapons_str)
-                            available_weapons.extend([w.strip() for w in weapons if w.strip()])
-                
-                level_data = {
-                    'levelId': level_id,
-                    'name': str(basic_row['关卡名称']) if pd.notna(basic_row['关卡名称']) else '',
-                    'scene': str(basic_row['场景']) if pd.notna(basic_row['场景']) else 'grassland',
-                    'description': str(basic_row['描述']) if pd.notna(basic_row['描述']) else '',
-                    'backgroundImage': str(basic_row['关卡背景图路径']) if pd.notna(basic_row['关卡背景图路径']) else 'images/LevelBackground/BG1',
-                    'availableWeapons': available_weapons,
-                    'coinReward': int(basic_row['钞票奖励']) if pd.notna(basic_row['钞票奖励']) else 100,
-                    'diamondReward': int(basic_row['钻石奖励']) if pd.notna(basic_row['钻石奖励']) else 0,
-                    'timeLimit': 300,  # 默认值
-                    'difficulty': 'normal',  # 默认值
-                    'healthMultiplier': float(basic_row['生命倍数']) if pd.notna(basic_row['生命倍数']) else 1.0,  # 从Excel读取生命倍数
-                    'waves': []
-                }
-                
-                # 获取该关卡的波次配置
-                if wave_config is not None:
-                    level_waves = wave_config[wave_config['关卡ID'] == level_id]
-                    
-                    for _, wave_row in level_waves.iterrows():
-                        wave_id = int(wave_row['波次ID']) if pd.notna(wave_row['波次ID']) else 1
-                        
-                        # 获取该波次的敌人配置
-                        wave_enemies = []
-                        if enemy_config is not None:
-                            wave_enemy_data = enemy_config[
-                                (enemy_config['关卡ID'] == level_id) & 
-                                (enemy_config['波次ID'] == wave_id)
-                            ]
-                            
-                            for _, enemy_row in wave_enemy_data.iterrows():
-                                enemy_type = str(enemy_row['敌人类型']) if pd.notna(enemy_row['敌人类型']) else '普通僵尸'
-                                
-                                enemy_data = {
-                                    'enemyType': enemy_type,
-                                    'count': int(enemy_row['数量']) if pd.notna(enemy_row['数量']) else 1,
-                                    'spawnInterval': float(enemy_row['生成间隔']) if pd.notna(enemy_row['生成间隔']) else 2.0,
-                                    'spawnDelay': float(enemy_row['生成延迟']) if pd.notna(enemy_row['生成延迟']) else 0.0,
-                                    'characteristics': str(enemy_row['特征描述']) if pd.notna(enemy_row['特征描述']) else ''
-                                }
-                                wave_enemies.append(enemy_data)
-                        
-                        wave_data = {
-                            'waveId': wave_id,
-                            'enemies': wave_enemies
-                        }
-                        level_data['waves'].append(wave_data)
-                
-                config.append(level_data)
-                print(f"处理关卡: {level_id}, 波次数: {len(level_data['waves'])}")
-            
-            print(f"成功解析关卡配置,共 {len(config)} 个关卡")
-            
-        except Exception as e:
-            print(f"解析关卡多工作表数据时出错: {e}")
-            import traceback
-            traceback.print_exc()
-        
-        return config
+
     
     def parse_skill_multi_sheet_data(self, all_sheets_data, filename):
         """解析技能配置的多工作表数据"""
@@ -1626,6 +1531,75 @@ class ConfigManagerGUI:
             print(error_details)
             messagebox.showerror("错误", f"启动敌人配置导入失败: {str(e)}\n\n详细错误信息已输出到控制台,请查看。")
     
+    def import_level_config(self):
+        """导入关卡配置"""
+        try:
+            if not LEVEL_MANAGER_AVAILABLE:
+                messagebox.showerror("错误", "关卡配置管理器不可用,请检查level_config_manager.py文件是否存在")
+                return
+            
+            # 创建关卡配置管理器
+            excel_dir = Path(self.excel_dir)
+            level_excel_file = excel_dir / "关卡配置" / "关卡配置表.xlsx"
+            levels_dir = excel_dir.parent / "levels"
+            
+            if not level_excel_file.exists():
+                messagebox.showwarning("警告", f"未找到关卡配置文件: {level_excel_file}")
+                return
+            
+            if not levels_dir.exists():
+                messagebox.showwarning("警告", f"未找到关卡配置目录: {levels_dir}")
+                return
+            
+            # 使用LevelConfigManager导入配置
+            level_manager = LevelConfigManager(
+                excel_path=str(level_excel_file),
+                levels_dir=str(levels_dir)
+            )
+            
+            # 在后台线程中执行导入
+            def import_thread():
+                try:
+                    success = level_manager.import_from_excel()
+                    
+                    # 在主线程中更新UI
+                    def update_ui():
+                        if success:
+                            messagebox.showinfo("成功", "关卡配置导入成功!")
+                            self.status_var.set("关卡配置导入成功")
+                            # 更新预览文本
+                            self.preview_text.delete(1.0, tk.END)
+                            self.preview_text.insert(tk.END, "关卡配置导入成功\n\n配置已从Excel文件合并到各个关卡JSON文件中")
+                        else:
+                            messagebox.showerror("错误", "关卡配置导入失败,请查看控制台输出")
+                            self.status_var.set("关卡配置导入失败")
+                    
+                    self.root.after(0, update_ui)
+                    
+                except Exception as e:
+                    def show_error():
+                        import traceback
+                        error_details = traceback.format_exc()
+                        print(f"导入关卡配置失败,详细错误信息:")
+                        print(error_details)
+                        messagebox.showerror("错误", f"导入关卡配置失败: {str(e)}\n\n详细错误信息已输出到控制台,请查看。")
+                        self.status_var.set("关卡配置导入失败")
+                    
+                    self.root.after(0, show_error)
+            
+            # 启动导入线程
+            self.status_var.set("正在导入关卡配置...")
+            thread = threading.Thread(target=import_thread)
+            thread.daemon = True
+            thread.start()
+            
+        except Exception as e:
+            import traceback
+            error_details = traceback.format_exc()
+            print(f"启动关卡配置导入失败,详细错误信息:")
+            print(error_details)
+            messagebox.showerror("错误", f"启动关卡配置导入失败: {str(e)}\n\n详细错误信息已输出到控制台,请查看。")
+    
     def _import_vertical_config(self):
         """导入纵向表格配置"""
         # 读取现有JSON配置
@@ -1773,23 +1747,14 @@ class ConfigManagerGUI:
         # 读取现有JSON配置
         print(f"JSON配置文件路径: {self.selected_json_path}")
         
-        # 检查是否是关卡配置(目录类型)
-        if is_level_config:
-            print("处理关卡配置目录...")
-            # 关卡配置是目录,确保目录存在
-            if not self.selected_json_path.exists():
-                print(f"创建关卡配置目录: {self.selected_json_path}")
-                self.selected_json_path.mkdir(parents=True, exist_ok=True)
-            current_config = {}
+        # 普通JSON文件配置
+        if self.selected_json_path.exists():
+            print("读取现有JSON配置文件...")
+            with open(self.selected_json_path, 'r', encoding='utf-8') as f:
+                current_config = json.load(f)
         else:
-            # 普通JSON文件配置
-            if self.selected_json_path.exists():
-                print("读取现有JSON配置文件...")
-                with open(self.selected_json_path, 'r', encoding='utf-8') as f:
-                    current_config = json.load(f)
-            else:
-                print("创建新的JSON配置...")
-                current_config = {}
+            print("创建新的JSON配置...")
+            current_config = {}
         
         # 根据用户选择的处理模式和数据类型处理
         if not self.selected_files:
@@ -1805,164 +1770,50 @@ class ConfigManagerGUI:
         is_single_json = self.single_json_var.get()
         print(f"处理模式 - 多工作表: {is_multi_sheet}, 单个JSON: {is_single_json}")
         
-        # 根据数据类型和用户选择的模式进行处理
-        if is_level_config:
-            # 关卡配置:始终为目录模式,每个关卡一个JSON文件
-            print("处理关卡配置...")
-            # 关卡配置:为每个关卡创建单独的JSON文件
-            levels_dir = self.selected_json_path
-            print(f"关卡配置目录: {levels_dir}")
-            
-            try:
-                # 检查并创建目录
-                if not levels_dir.exists():
-                    print(f"创建关卡配置目录: {levels_dir}")
-                    levels_dir.mkdir(parents=True, exist_ok=True)
-                else:
-                    print(f"关卡配置目录已存在: {levels_dir}")
-                
-                # 测试目录写入权限
-                test_file = levels_dir / "test_permission.tmp"
-                try:
-                    with open(test_file, 'w', encoding='utf-8') as f:
-                        f.write("test")
-                    test_file.unlink()  # 删除测试文件
-                except PermissionError:
-                    messagebox.showerror("错误", f"没有写入权限到目录: {levels_dir}\n请检查目录权限或以管理员身份运行")
-                    return
-                
-                # 检查数据格式:多工作表数据 vs 传统items数据
-                if isinstance(self.config_data, list):
-                    # 新的多工作表数据格式:直接是关卡数据列表
-                    print("使用多工作表数据格式")
-                    level_configs = self.config_data
-                elif 'items' in self.config_data:
-                    # 传统的items数据格式:需要转换
-                    print("使用传统items数据格式")
-                    level_configs = []
-                    for item in items:
-                        level_data = self._convert_level_data(item)
-                        if level_data:
-                            level_configs.append(level_data)
-                else:
-                    print(f"错误: 未知的关卡配置数据格式: {type(self.config_data)}")
-                    messagebox.showerror("错误", "关卡配置数据格式错误")
-                    return
-                
-                # 保存关卡配置文件
-                updated_count = 0
-                failed_count = 0
-                
-                for level_data in level_configs:
-                    try:
-                        if level_data and 'levelId' in level_data and level_data['levelId']:
-                            level_id = level_data['levelId']
-                            level_file = levels_dir / f"{level_id}.json"
-                            
-                            print(f"保存关卡配置: {level_file}")
-                            with open(level_file, 'w', encoding='utf-8') as f:
-                                json.dump(level_data, f, indent=2, ensure_ascii=False)
-                            updated_count += 1
-                        else:
-                            print(f"跳过无效的关卡数据: {level_data}")
-                            failed_count += 1
-                    except Exception as e:
-                        print(f"保存关卡配置时出错: {e}")
-                        failed_count += 1
-                        continue
-                
-                if updated_count > 0:
-                    message = f"关卡配置导入成功!\n更新了 {updated_count} 个关卡文件"
-                    if failed_count > 0:
-                        message += f"\n跳过了 {failed_count} 个无效配置"
-                    messagebox.showinfo("成功", message)
-                    self.status_var.set("关卡配置导入成功")
-                else:
-                    messagebox.showerror("错误", "没有成功导入任何关卡配置\n请检查Excel文件格式和数据")
-                    self.status_var.set("关卡配置导入失败")
-                
-            except Exception as e:
-                error_msg = f"关卡配置导入失败: {str(e)}"
-                print(error_msg)
-                messagebox.showerror("错误", error_msg)
-                self.status_var.set("关卡配置导入失败")
-            
-            self.clear_selection()
+        # 根据用户选择的模式和数据内容进行处理
+        print("处理配置数据...")
+        
+        # 根据数据类型自动识别配置类型
+        config_type = self._detect_config_type()
+        print(f"检测到配置类型: {config_type}")
+        
+        if config_type == 'unknown':
+            print(f"警告: 无法识别的配置类型")
+            messagebox.showwarning("警告", f"无法识别配置类型\n请检查Excel文件的工作表名称或数据格式")
             return
         
-        else:
-            # 非关卡配置:根据用户选择的模式和数据内容进行处理
-            print("处理非关卡配置...")
-            
-            # 根据数据类型自动识别配置类型
-            config_type = self._detect_config_type()
-            print(f"检测到配置类型: {config_type}")
+        # 根据配置类型处理数据
+        if config_type == 'enemy':
+            print("敌人配置现在由EnemyConfigManager处理,请使用专门的敌人配置导入按钮")
+            messagebox.showwarning("提示", "敌人配置现在由专门的管理器处理,请使用'导入敌人配置'按钮")
+            return
+        elif config_type == 'weapon':
+            print("武器配置现在由WeaponConfigManager处理,请使用专门的武器配置导入按钮")
+            messagebox.showwarning("提示", "武器配置现在由专门的管理器处理,请使用'导入武器配置'按钮")
+            return
+        elif config_type == 'skill':
+            print("处理技能配置...")
+            if 'skills' not in current_config:
+                current_config['skills'] = []
+            
+            updated_skills = []
+            for i, item in enumerate(items):
+                print(f"转换技能数据 {i+1}/{len(items)}: {item}")
+                skill_data = self._convert_skill_data(item)
+                if skill_data:
+                    updated_skills.append(skill_data)
+                    print(f"成功转换技能数据: {skill_data.get('id', 'Unknown')}")
+                else:
+                    print(f"跳过无效的技能数据: {item}")
             
-            if config_type == 'unknown':
-                print(f"警告: 无法识别的配置类型")
-                messagebox.showwarning("警告", f"无法识别配置类型\n请检查Excel文件的工作表名称或数据格式")
-                return
+            print(f"总共转换了 {len(updated_skills)} 个技能配置")
+            current_config['skills'] = updated_skills
             
-            # 根据配置类型处理数据
-            if config_type == 'enemy':
-                print("处理敌人配置...")
-                if 'enemies' not in current_config:
-                    current_config['enemies'] = []
-                
-                updated_enemies = []
-                for i, item in enumerate(items):
-                    print(f"转换敌人数据 {i+1}/{len(items)}: {item}")
-                    enemy_data = self._convert_enemy_data(item)
-                    if enemy_data:
-                        updated_enemies.append(enemy_data)
-                        print(f"成功转换敌人数据: {enemy_data['id']}")
-                    else:
-                        print(f"跳过无效的敌人数据: {item}")
-                
-                print(f"总共转换了 {len(updated_enemies)} 个敌人配置")
-                current_config['enemies'] = updated_enemies
-                
-            elif config_type == 'weapon':
-                print("处理武器配置...")
-                if 'weapons' not in current_config:
-                    current_config['weapons'] = []
-                
-                updated_weapons = []
-                for i, item in enumerate(items):
-                    print(f"转换武器数据 {i+1}/{len(items)}: {item}")
-                    weapon_data = self._convert_weapon_data(item)
-                    if weapon_data:
-                        updated_weapons.append(weapon_data)
-                        print(f"成功转换武器数据: {weapon_data.get('id', 'Unknown')}")
-                    else:
-                        print(f"跳过无效的武器数据: {item}")
-                
-                print(f"总共转换了 {len(updated_weapons)} 个武器配置")
-                current_config['weapons'] = updated_weapons
-                
-            elif config_type == 'skill':
-                print("处理技能配置...")
-                if 'skills' not in current_config:
-                    current_config['skills'] = []
-                
-                updated_skills = []
-                for i, item in enumerate(items):
-                    print(f"转换技能数据 {i+1}/{len(items)}: {item}")
-                    skill_data = self._convert_skill_data(item)
-                    if skill_data:
-                        updated_skills.append(skill_data)
-                        print(f"成功转换技能数据: {skill_data.get('id', 'Unknown')}")
-                    else:
-                        print(f"跳过无效的技能数据: {item}")
-                
-                print(f"总共转换了 {len(updated_skills)} 个技能配置")
-                current_config['skills'] = updated_skills
-                
-            else:
-                # 通用配置处理
-                print(f"处理通用配置类型: {config_type}")
-                # 直接使用items数据
-                current_config['items'] = items
+        else:
+            # 通用配置处理
+            print(f"处理通用配置类型: {config_type}")
+            # 直接使用items数据
+            current_config['items'] = items
         
         # 写入更新后的配置(关卡配置已在前面处理,跳过)
         if not is_level_config:
@@ -2015,41 +1866,7 @@ class ConfigManagerGUI:
                 # 如果config_data是字典,合并到current_config
                 print(f"合并字典格式的配置数据")
                 
-                # 特殊处理武器配置,保留现有武器中表格没有的字段
-                if 'weapons' in self.config_data and 'weapons' in current_config:
-                    print("检测到武器配置,执行智能合并以保留现有字段")
-                    new_weapons = self.config_data['weapons']
-                    existing_weapons = current_config['weapons']
-                    
-                    # 创建现有武器的ID映射
-                    existing_weapons_map = {}
-                    for weapon in existing_weapons:
-                        weapon_id = weapon.get('ID', '') or weapon.get('id', '')
-                        if weapon_id:
-                            existing_weapons_map[weapon_id] = weapon
-                    
-                    # 合并武器配置,保留现有字段
-                    merged_weapons = []
-                    for new_weapon_data in new_weapons:
-                        weapon_id = new_weapon_data.get('ID', '') or new_weapon_data.get('id', '')
-                        if weapon_id and weapon_id in existing_weapons_map:
-                            # 找到对应的现有武器,转换新数据时传入现有武器配置
-                            existing_weapon = existing_weapons_map[weapon_id]
-                            # 转换新武器数据,传入现有武器配置以保留特效字段
-                            converted_weapon = self._convert_weapon_data(new_weapon_data, existing_weapon)
-                            if converted_weapon:
-                                merged_weapons.append(converted_weapon)
-                                print(f"✓ 武器 {weapon_id} 已转换并保留了现有的特效字段")
-                        else:
-                            # 新武器,直接转换
-                            converted_weapon = self._convert_weapon_data(new_weapon_data)
-                            if converted_weapon:
-                                merged_weapons.append(converted_weapon)
-                                print(f"+ 新武器 {weapon_id} 已添加")
-                    
-                    # 更新武器配置
-                    self.config_data['weapons'] = merged_weapons
-                    print(f"武器配置合并完成,共 {len(merged_weapons)} 个武器")
+
                 
                 current_config.update(self.config_data)
             
@@ -2074,26 +1891,7 @@ class ConfigManagerGUI:
         # 刷新预览
         self.clear_selection()
     
-    def _deep_merge_weapon_config(self, existing_weapon, new_weapon):
-        """深度合并武器配置,保留现有武器中表格没有的字段"""
-        import copy
-        
-        # 创建新武器的深拷贝作为基础
-        merged = copy.deepcopy(new_weapon)
-        
-        # 递归合并函数,将现有武器中新武器没有的字段添加到合并结果中
-        def preserve_existing_fields(target, existing):
-            for key, value in existing.items():
-                if key not in target:
-                    # 现有武器有但新武器没有的字段,保留
-                    target[key] = copy.deepcopy(value)
-                elif isinstance(target[key], dict) and isinstance(value, dict):
-                    # 如果两者都是字典,递归处理
-                    preserve_existing_fields(target[key], value)
-        
-        # 执行深度合并,保留现有武器中的额外字段
-        preserve_existing_fields(merged, existing_weapon)
-        return merged
+
     
     def _detect_config_type(self):
         """根据数据内容和工作表名称自动识别配置类型"""
@@ -2107,8 +1905,7 @@ class ConfigManagerGUI:
                     return 'skill'
                 elif '武器配置' in str(self.config_data.keys()) or '武器信息' in self.config_data:
                     return 'weapon'
-                elif any('关卡' in str(key) for key in self.config_data.keys()):
-                    return 'level'
+
             
             # 检查数据内容中的字段来判断类型
             if hasattr(self, 'config_data'):
@@ -2141,10 +1938,7 @@ class ConfigManagerGUI:
                     if weapon_fields.intersection(fields):
                         return 'weapon'
                     
-                    # 关卡配置特征字段
-                    level_fields = {'levelId', 'name', 'enemies', 'waves'}
-                    if level_fields.intersection(fields):
-                        return 'level'
+
             
             # 如果无法通过数据内容判断,尝试通过文件名判断(作为后备方案)
             if hasattr(self, 'selected_files') and self.selected_files:
@@ -2155,8 +1949,7 @@ class ConfigManagerGUI:
                     return 'skill'
                 elif '武器' in filename:
                     return 'weapon'
-                elif '关卡' in filename:
-                    return 'level'
+
             
             return 'unknown'
             
@@ -2202,78 +1995,7 @@ class ConfigManagerGUI:
             print(f"转换技能数据失败: {e} - 数据: {item}")
             return None
     
-    def _convert_level_data(self, item):
-        """转换关卡数据格式"""
-        try:
-            # 如果item已经是完整的关卡数据结构(来自多工作表解析),直接返回
-            if isinstance(item, dict) and 'waves' in item:
-                return item
-            
-            # 处理传统的单行数据格式
-            # 处理可用武器字符串,转换为数组(支持中英文字段名)
-            available_weapons = []
-            weapons_field = item.get('weapons', item.get('可用武器', ''))
-            if weapons_field:
-                weapons_str = str(weapons_field)
-                # 支持逗号、顿号、分号等多种分隔符
-                for separator in ['、', ',', ',', ';', ';']:
-                    if separator in weapons_str:
-                        available_weapons = [weapon.strip() for weapon in weapons_str.split(separator)]
-                        break
-                # 如果没有找到分隔符,则作为单个武器处理
-                if not available_weapons:
-                    available_weapons = [weapons_str.strip()]
-            
-            # 获取关卡ID,用于读取现有配置(支持中英文字段名)
-            level_id = str(item.get('levelId', item.get('关卡ID', '')))
-            
-            # 尝试读取现有的关卡配置文件,保留waves数据
-            existing_waves = []
-            existing_data = {}
-            if level_id:
-                try:
-                    levels_dir = self.project_root / "assets/resources/data/levels"
-                    level_file = levels_dir / f"{level_id}.json"
-                    if level_file.exists():
-                        with open(level_file, 'r', encoding='utf-8') as f:
-                            existing_data = json.load(f)
-                            existing_waves = existing_data.get('waves', [])
-                            print(f"保留现有关卡 {level_id} 的 {len(existing_waves)} 个波次数据")
-                except Exception as e:
-                    print(f"读取现有关卡配置时出错: {e}")
-            
-            # 构建新的关卡数据,保留现有的waves(支持中英文字段名)
-            level_data = {
-                "levelId": level_id,
-                "name": str(item.get('name', item.get('关卡名称', existing_data.get('name', '')))),
-                "scene": str(item.get('scene', item.get('场景', existing_data.get('scene', '')))),
-                "description": str(item.get('description', item.get('描述', existing_data.get('description', '')))),
-                "backgroundImage": str(item.get('backgroundImage', item.get('关卡背景图路径', existing_data.get('backgroundImage', 'images/LevelBackground/BG1')))),
-                "weapons": available_weapons if available_weapons else existing_data.get('weapons', existing_data.get('availableWeapons', [])),
-                "timeLimit": int(item.get('timeLimit', item.get('时间限制', existing_data.get('timeLimit', 300)))),
-                "difficulty": str(item.get('difficulty', item.get('难度', existing_data.get('difficulty', 'normal')))),
-                "healthMultiplier": float(item.get('healthMultiplier', item.get('生命倍数', existing_data.get('healthMultiplier', 1.0)))),
-                "waves": existing_waves  # 保留现有的waves数据
-            }
-            
-            # 添加可选字段(如果存在,支持中英文字段名)
-            coin_reward = item.get('coinReward', item.get('钞票奖励'))
-            if coin_reward is not None:
-                level_data["coinReward"] = int(coin_reward)
-            elif 'coinReward' in existing_data:
-                level_data["coinReward"] = existing_data['coinReward']
-                
-            diamond_reward = item.get('diamondReward', item.get('钻石奖励'))
-            if diamond_reward is not None:
-                level_data["diamondReward"] = int(diamond_reward)
-            elif 'diamondReward' in existing_data:
-                level_data["diamondReward"] = existing_data['diamondReward']
-            
-            return level_data
-            
-        except Exception as e:
-            print(f"转换关卡数据时出错: {e}")
-            return None
+
     
 
     

+ 390 - 0
assets/resources/data/excel/level_config_manager.py

@@ -0,0 +1,390 @@
+# -*- coding: utf-8 -*-
+"""
+关卡配置管理器
+负责从Excel读取关卡配置数据,并智能合并到现有JSON文件中
+只修改或新增策划表中配置的字段,不会完全覆盖JSON文件
+"""
+
+import pandas as pd
+import json
+import os
+from datetime import datetime
+from pathlib import Path
+import re
+
+class LevelConfigManager:
+    def __init__(self, excel_path=None, levels_dir=None):
+        """
+        初始化关卡配置管理器
+        
+        Args:
+            excel_path: Excel文件路径
+            levels_dir: 关卡JSON文件目录
+        """
+        self.excel_path = excel_path
+        self.levels_dir = levels_dir or "d:/CocosGame/Pong/assets/resources/data/levels"
+        self.backup_dir = os.path.join(os.path.dirname(self.levels_dir), "backups", "levels")
+        
+        # 确保备份目录存在
+        os.makedirs(self.backup_dir, exist_ok=True)
+        
+        # 配置数据存储
+        self.basic_config = None
+        self.weapon_config = None
+        self.wave_config = None
+        self.enemy_config = None
+    
+    def read_excel_data(self, excel_path=None):
+        """
+        读取Excel文件中的所有工作表数据
+        
+        Args:
+            excel_path: Excel文件路径,如果不提供则使用初始化时的路径
+            
+        Returns:
+            bool: 是否成功读取数据
+        """
+        if excel_path:
+            self.excel_path = excel_path
+            
+        if not self.excel_path or not os.path.exists(self.excel_path):
+            print(f"错误: Excel文件不存在: {self.excel_path}")
+            return False
+            
+        try:
+            # 读取所有工作表
+            all_sheets = pd.read_excel(self.excel_path, sheet_name=None)
+            
+            # 解析各个工作表
+            self._parse_basic_config(all_sheets)
+            self._parse_weapon_config(all_sheets)
+            self._parse_wave_config(all_sheets)
+            self._parse_enemy_config(all_sheets)
+            
+            print(f"成功读取Excel数据: {self.excel_path}")
+            return True
+            
+        except Exception as e:
+            print(f"读取Excel文件失败: {e}")
+            return False
+    
+    def _parse_basic_config(self, all_sheets):
+        """
+        解析关卡基础配置工作表
+        """
+        sheet_names = ['关卡基础配置', 'Level Config', 'levels', '关卡配置']
+        
+        for sheet_name in sheet_names:
+            if sheet_name in all_sheets:
+                self.basic_config = all_sheets[sheet_name]
+                print(f"找到关卡基础配置工作表: {sheet_name}")
+                return
+                
+        print("警告: 未找到关卡基础配置工作表")
+    
+    def _parse_weapon_config(self, all_sheets):
+        """
+        解析关卡武器配置工作表
+        """
+        sheet_names = ['关卡武器配置', 'Level Weapon Config', 'level_weapons', '武器配置']
+        
+        for sheet_name in sheet_names:
+            if sheet_name in all_sheets:
+                self.weapon_config = all_sheets[sheet_name]
+                print(f"找到关卡武器配置工作表: {sheet_name}")
+                return
+                
+        print("警告: 未找到关卡武器配置工作表")
+    
+    def _parse_wave_config(self, all_sheets):
+        """
+        解析关卡波次配置工作表
+        """
+        sheet_names = ['关卡波次配置', 'Wave Config', 'waves', '波次配置']
+        
+        for sheet_name in sheet_names:
+            if sheet_name in all_sheets:
+                self.wave_config = all_sheets[sheet_name]
+                print(f"找到关卡波次配置工作表: {sheet_name}")
+                return
+                
+        print("警告: 未找到关卡波次配置工作表")
+    
+    def _parse_enemy_config(self, all_sheets):
+        """
+        解析敌人详细配置工作表
+        """
+        sheet_names = ['敌人详细配置', 'Enemy Detail Config', 'enemy_details', '敌人配置']
+        
+        for sheet_name in sheet_names:
+            if sheet_name in all_sheets:
+                self.enemy_config = all_sheets[sheet_name]
+                print(f"找到敌人详细配置工作表: {sheet_name}")
+                return
+                
+        print("警告: 未找到敌人详细配置工作表")
+    
+    def get_all_level_ids(self):
+        """
+        获取所有关卡ID
+        
+        Returns:
+            set: 所有关卡ID的集合
+        """
+        level_ids = set()
+        
+        # 从基础配置中获取关卡ID
+        if self.basic_config is not None:
+            for _, row in self.basic_config.iterrows():
+                if pd.notna(row['关卡ID']):
+                    level_ids.add(str(row['关卡ID']))
+        
+        # 从武器配置中获取关卡ID
+        if self.weapon_config is not None:
+            for _, row in self.weapon_config.iterrows():
+                if pd.notna(row['关卡ID']):
+                    level_ids.add(str(row['关卡ID']))
+        
+        # 从波次配置中获取关卡ID
+        if self.wave_config is not None:
+            for _, row in self.wave_config.iterrows():
+                if pd.notna(row['关卡ID']):
+                    level_ids.add(str(row['关卡ID']))
+        
+        return level_ids
+    
+    def merge_configurations(self):
+        """
+        合并Excel配置到现有JSON文件
+        
+        Returns:
+            dict: 合并结果统计
+        """
+        if not any([self.basic_config is not None, self.weapon_config is not None, 
+                   self.wave_config is not None, self.enemy_config is not None]):
+            print("错误: 没有可用的配置数据")
+            return {"success": False, "message": "没有可用的配置数据"}
+        
+        level_ids = self.get_all_level_ids()
+        if not level_ids:
+            print("错误: 没有找到任何关卡ID")
+            return {"success": False, "message": "没有找到任何关卡ID"}
+        
+        results = {
+            "success": True,
+            "processed_levels": [],
+            "created_levels": [],
+            "updated_levels": [],
+            "errors": []
+        }
+        
+        for level_id in level_ids:
+            try:
+                result = self._update_level_config(level_id)
+                results["processed_levels"].append(level_id)
+                
+                if result["created"]:
+                    results["created_levels"].append(level_id)
+                else:
+                    results["updated_levels"].append(level_id)
+                    
+            except Exception as e:
+                error_msg = f"处理关卡 {level_id} 时出错: {str(e)}"
+                print(error_msg)
+                results["errors"].append(error_msg)
+        
+        return results
+    
+    def _update_level_config(self, level_id):
+        """
+        更新单个关卡的配置
+        
+        Args:
+            level_id: 关卡ID
+            
+        Returns:
+            dict: 更新结果
+        """
+        json_path = os.path.join(self.levels_dir, f"{level_id}.json")
+        
+        # 读取现有配置或创建新配置
+        if os.path.exists(json_path):
+            with open(json_path, 'r', encoding='utf-8') as f:
+                existing_config = json.load(f)
+            created = False
+        else:
+            existing_config = {
+                "levelId": level_id,
+                "name": "",
+                "scene": "grassland",
+                "description": "",
+                "backgroundImage": "images/LevelBackground/BG1",
+                "availableWeapons": [],
+                "coinReward": 100,
+                "diamondReward": 0,
+                "timeLimit": 300,
+                "difficulty": "normal",
+                "healthMultiplier": 1.0,
+                "waves": []
+            }
+            created = True
+        
+        # 备份现有文件
+        if not created:
+            self._backup_level_file(json_path, level_id)
+        
+        # 更新基础配置
+        if self.basic_config is not None:
+            basic_row = self.basic_config[self.basic_config['关卡ID'] == level_id]
+            if not basic_row.empty:
+                row = basic_row.iloc[0]
+                
+                if pd.notna(row['关卡名称']):
+                    existing_config['name'] = str(row['关卡名称'])
+                if pd.notna(row['场景']):
+                    existing_config['scene'] = str(row['场景'])
+                if pd.notna(row['描述']):
+                    existing_config['description'] = str(row['描述'])
+                if pd.notna(row['关卡背景图路径']):
+                    existing_config['backgroundImage'] = str(row['关卡背景图路径'])
+                if pd.notna(row['钞票奖励']):
+                    existing_config['coinReward'] = int(row['钞票奖励'])
+                if pd.notna(row['钻石奖励']):
+                    existing_config['diamondReward'] = int(row['钻石奖励'])
+                if pd.notna(row['生命倍数']):
+                    existing_config['healthMultiplier'] = float(row['生命倍数'])
+                if pd.notna(row['难度']):
+                    existing_config['difficulty'] = str(row['难度'])
+        
+        # 更新武器配置
+        if self.weapon_config is not None:
+            weapon_rows = self.weapon_config[self.weapon_config['关卡ID'] == level_id]
+            available_weapons = []
+            
+            for _, weapon_row in weapon_rows.iterrows():
+                if pd.notna(weapon_row['可用武器']):
+                    weapons_str = str(weapon_row['可用武器'])
+                    # 支持多种分隔符
+                    weapons = re.split(r'[、,,;;]', weapons_str)
+                    available_weapons.extend([w.strip() for w in weapons if w.strip()])
+            
+            if available_weapons:
+                existing_config['availableWeapons'] = available_weapons
+        
+        # 更新波次配置
+        if self.wave_config is not None and self.enemy_config is not None:
+            level_waves = self.wave_config[self.wave_config['关卡ID'] == level_id]
+            waves_data = []
+            
+            for _, wave_row in level_waves.iterrows():
+                wave_id = int(wave_row['波次ID']) if pd.notna(wave_row['波次ID']) else 1
+                
+                # 获取该波次的敌人配置
+                wave_enemies = []
+                wave_enemy_data = self.enemy_config[
+                    (self.enemy_config['关卡ID'] == level_id) & 
+                    (self.enemy_config['波次ID'] == wave_id)
+                ]
+                
+                for _, enemy_row in wave_enemy_data.iterrows():
+                    enemy_data = {
+                        'enemyType': str(enemy_row['敌人类型']) if pd.notna(enemy_row['敌人类型']) else 'normal_zombie',
+                        'count': int(enemy_row['数量']) if pd.notna(enemy_row['数量']) else 1,
+                        'spawnInterval': float(enemy_row['生成间隔']) if pd.notna(enemy_row['生成间隔']) else 2.0,
+                        'spawnDelay': float(enemy_row['生成延迟']) if pd.notna(enemy_row['生成延迟']) else 0.0,
+                        'characteristics': str(enemy_row['特征描述']) if pd.notna(enemy_row['特征描述']) else ''
+                    }
+                    wave_enemies.append(enemy_data)
+                
+                wave_data = {
+                    'waveId': wave_id,
+                    'enemies': wave_enemies
+                }
+                waves_data.append(wave_data)
+            
+            if waves_data:
+                # 按波次ID排序
+                waves_data.sort(key=lambda x: x['waveId'])
+                existing_config['waves'] = waves_data
+        
+        # 保存更新后的配置
+        with open(json_path, 'w', encoding='utf-8') as f:
+            json.dump(existing_config, f, ensure_ascii=False, indent=2)
+        
+        print(f"{'创建' if created else '更新'}关卡配置: {level_id}")
+        return {"created": created, "updated": not created}
+    
+    def _backup_level_file(self, json_path, level_id):
+        """
+        备份关卡JSON文件
+        
+        Args:
+            json_path: JSON文件路径
+            level_id: 关卡ID
+        """
+        try:
+            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+            backup_filename = f"{level_id}_{timestamp}.json"
+            backup_path = os.path.join(self.backup_dir, backup_filename)
+            
+            with open(json_path, 'r', encoding='utf-8') as src:
+                with open(backup_path, 'w', encoding='utf-8') as dst:
+                    dst.write(src.read())
+            
+            print(f"备份关卡文件: {backup_path}")
+            
+        except Exception as e:
+            print(f"备份关卡文件失败: {e}")
+    
+    def import_from_excel(self, excel_path=None, levels_dir=None):
+        """
+        从Excel导入关卡配置的完整流程
+        
+        Args:
+            excel_path: Excel文件路径
+            levels_dir: 关卡JSON文件目录
+            
+        Returns:
+            dict: 导入结果
+        """
+        if excel_path:
+            self.excel_path = excel_path
+        if levels_dir:
+            self.levels_dir = levels_dir
+        
+        print("开始导入关卡配置...")
+        
+        # 读取Excel数据
+        if not self.read_excel_data():
+            return {"success": False, "message": "读取Excel数据失败"}
+        
+        # 合并配置
+        results = self.merge_configurations()
+        
+        if results["success"]:
+            print(f"关卡配置导入完成:")
+            print(f"  处理关卡数: {len(results['processed_levels'])}")
+            print(f"  新建关卡数: {len(results['created_levels'])}")
+            print(f"  更新关卡数: {len(results['updated_levels'])}")
+            if results["errors"]:
+                print(f"  错误数: {len(results['errors'])}")
+                for error in results["errors"]:
+                    print(f"    {error}")
+        
+        return results
+
+# 使用示例
+if __name__ == "__main__":
+    # 创建关卡配置管理器
+    manager = LevelConfigManager(
+        excel_path="d:/CocosGame/Pong/assets/resources/data/excel/关卡配置/关卡配置表.xlsx",
+        levels_dir="d:/CocosGame/Pong/assets/resources/data/levels"
+    )
+    
+    # 导入配置
+    result = manager.import_from_excel()
+    
+    if result["success"]:
+        print("关卡配置导入成功!")
+    else:
+        print(f"关卡配置导入失败: {result['message']}")