181404010226 5 месяцев назад
Родитель
Сommit
657df8d361

+ 8 - 12
assets/Scenes/GameLevel.scene

@@ -140,7 +140,7 @@
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": 360.00000000000006,
+      "x": 360,
       "y": 667,
       "z": 0
     },
@@ -476,7 +476,7 @@
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": -5.684341886080802e-14,
+      "x": 0,
       "y": 0,
       "z": 0
     },
@@ -10699,7 +10699,7 @@
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": -310.00000000000006,
+      "x": -310,
       "y": 577.3409999999999,
       "z": 0
     },
@@ -10757,7 +10757,7 @@
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": 360.00000000000006,
+      "x": 360,
       "y": 667,
       "z": 0
     },
@@ -10887,7 +10887,7 @@
     "__prefab": null,
     "_contentSize": {
       "__type__": "cc.Size",
-      "width": 720.0000000000001,
+      "width": 720,
       "height": 1334
     },
     "_anchorPoint": {
@@ -14590,7 +14590,7 @@
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": -5.684341886080802e-14,
+      "x": 0,
       "y": 0,
       "z": 0
     },
@@ -22415,10 +22415,6 @@
     "panelUpgradeBtn": {
       "__id__": 592
     },
-    "weaponNodePrefab": {
-      "__uuid__": "c407e531-c29c-40bb-bb9e-9b214d4aaf9d",
-      "__expectedType__": "cc.Prefab"
-    },
     "lockedWeaponPrefab": {
       "__uuid__": "c407e531-c29c-40bb-bb9e-9b214d4aaf9d",
       "__expectedType__": "cc.Prefab"
@@ -23936,7 +23932,7 @@
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": -310.00000000000006,
+      "x": -310,
       "y": 617,
       "z": 0
     },
@@ -34966,7 +34962,7 @@
     "__prefab": null,
     "_contentSize": {
       "__type__": "cc.Size",
-      "width": 720.0000000000001,
+      "width": 720,
       "height": 1334
     },
     "_anchorPoint": {

+ 64 - 2
assets/resources/data/excel/config_manager.py

@@ -100,9 +100,15 @@ class ConfigManagerGUI:
                     '伤害': int,
                     '射速': float,
                     '射程': int,
-                    '子弹速度': int
+                    '子弹速度': int,
+                    '最大等级': int,
+                    '等级': int,
+                    '升级费用': int,
+                    '伤害增加': int
                 },
-                'format_type': 'horizontal'
+                'format_type': 'horizontal',
+                'multi_sheet': True,
+                'sheet_names': ['武器基础配置', '升级配置']
             },
             '关卡配置表_完整版_更新_v2.xlsx': {
                 'json_path': self.project_root / "assets/resources/data/levels",  # 目录路径,包含多个关卡JSON文件
@@ -611,6 +617,10 @@ class ConfigManagerGUI:
     
     def parse_multi_sheet_data(self, all_sheets_data, filename):
         """解析通用多工作表数据"""
+        # 处理武器配置表的多工作表
+        if '方块武器配置表' in filename:
+            return self.parse_weapon_multi_sheet_data(all_sheets_data, filename)
+        
         # 这里可以添加其他多工作表文件的处理逻辑
         # 目前只返回第一个工作表的数据
         if all_sheets_data:
@@ -726,6 +736,58 @@ class ConfigManagerGUI:
         
         return config
     
+    def parse_weapon_multi_sheet_data(self, all_sheets_data, filename):
+        """解析武器配置表的多工作表数据"""
+        weapons_config = {'weapons': []}
+        
+        try:
+            # 解析武器基础配置工作表
+            if '武器基础配置' in all_sheets_data:
+                base_config_data = all_sheets_data['武器基础配置']
+                base_config = self.parse_config_data(base_config_data, filename)
+                if 'items' in base_config:
+                    weapons_config['weapons'] = base_config['items']
+            
+            # 解析升级配置工作表
+            if '升级配置' in all_sheets_data:
+                upgrade_config_data = all_sheets_data['升级配置']
+                upgrade_config = self.parse_config_data(upgrade_config_data, filename)
+                
+                # 将升级配置合并到对应的武器中
+                if 'items' in upgrade_config:
+                    upgrade_items = upgrade_config['items']
+                    
+                    # 为每个武器添加升级配置
+                    for weapon in weapons_config['weapons']:
+                        weapon_id = weapon.get('ID')
+                        if weapon_id:
+                            # 查找对应的升级配置
+                            weapon_upgrades = [item for item in upgrade_items if item.get('ID') == weapon_id]
+                            if weapon_upgrades:
+                                # 构建升级配置结构
+                                upgrade_config_struct = {
+                                    'maxLevel': weapon.get('最大等级', 10),
+                                    'levels': {}
+                                }
+                                
+                                # 添加每个等级的升级配置
+                                for upgrade in weapon_upgrades:
+                                    level = upgrade.get('等级', 1)
+                                    if level:
+                                        upgrade_config_struct['levels'][str(level)] = {
+                                            'cost': upgrade.get('升级费用', 25),
+                                            'damageIncrease': upgrade.get('伤害增加', 1)
+                                        }
+                                
+                                weapon['upgradeConfig'] = upgrade_config_struct
+            
+            print(f"武器配置解析完成,共{len(weapons_config['weapons'])}个武器")
+            return weapons_config
+            
+        except Exception as e:
+            print(f"解析武器配置表时出错: {e}")
+            return {'weapons': []}
+    
     def clear_selection(self):
         """清空选择"""
         self.file_listbox.selection_clear(0, tk.END)

BIN
assets/resources/data/excel/方块武器配置/方块武器配置表_更新_v2.xlsx


+ 91 - 638
assets/resources/data/weapons.json

@@ -1,658 +1,111 @@
 {
   "weapons": [
     {
-      "id": "pea_shooter",
-      "name": "毛豆射手",
-      "type": "single_shot",
-      "rarity": "common",
-      "weight": 30,
-      "stats": {
-        "damage": 20,
-        "fireRate": 1.0,
-        "range": 300,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "straight",
-          "speed": 200,
-          "gravity": 0,
-          "arcHeight": 0,
-          "homingStrength": 0,
-          "homingDelay": 0
-        },
-        "hitEffects": [
-          {
-            "type": "normal_damage",
-            "priority": 1,
-            "params": {
-              "damage": 20
-            }
-          }
-        ],
-        "lifecycle": {
-          "type": "hit_destroy",
-          "maxLifetime": 5.0,
-          "penetration": 1,
-          "ricochetCount": 0,
-          "returnToOrigin": false
-        },
-        "visual": {
-          "bulletPrefab": "bullets/PeaBullet",
-          "hitEffect": "Animation/WeaponTx/tx0002/tx0002",
-          "trailEffect": null,
-          "muzzleFlash": "Animation/WeaponTx/tx0002/tx0002"
-        }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/001-1",
-          "H-I": "images/PlantsSprite/001-1",
-          "L": "images/PlantsSprite/001-1",
-          "S": "images/PlantsSprite/001-1",
-          "D-T": "images/PlantsSprite/001-1"
-        },
-        "fireSound": "audio/pea_shot"
-      }
-    },
-    {
-      "id": "sharp_carrot",
-      "name": "尖胡萝卜",
-      "type": "piercing",
-      "rarity": "common",
-      "weight": 25,
-      "stats": {
-        "damage": 15,
-        "fireRate": 0.8,
-        "range": 400,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "straight",
-          "speed": 250,
-          "gravity": 0,
-          "arcHeight": 0,
-          "homingStrength": 0,
-          "homingDelay": 0
-        },
-        "hitEffects": [
-          {
-            "type": "pierce_damage",
-            "priority": 1,
-            "params": {
-              "damage": 15,
-              "pierceCount": 999
-            }
-          }
-        ],
-        "lifecycle": {
-          "type": "range_limit",
-          "maxLifetime": 5.0,
-          "penetration": 999,
-          "ricochetCount": 0,
-          "returnToOrigin": false,
-          "maxRange": 1000
-        },
-        "visual": {
-          "bulletPrefab": "bullets/CarrotBullet",
-          "hitEffect": "",
-          "trailEffect": "Animation/WeaponTx/tx0001/tx0001",
-          "muzzleFlash": "Animation/WeaponTx/tx0001/tx0001"
-        }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/002",
-          "H-I": "images/PlantsSprite/002",
-          "L": "images/PlantsSprite/002",
-          "S": "images/PlantsSprite/002",
-          "D-T": "images/PlantsSprite/002"
-        },
-        "fireSound": "audio/carrot_shot"
-      }
-    },
-    {
-      "id": "saw_grass",
-      "name": "锯齿草",
-      "type": "ricochet_piercing",
-      "rarity": "uncommon",
-      "weight": 20,
-      "stats": {
-        "damage": 25,
-        "fireRate": 0.6,
-        "range": 350,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "straight",
-          "speed": 180,
-          "gravity": 0,
-          "arcHeight": 0,
-          "homingStrength": 0,
-          "homingDelay": 0
-        },
-        "hitEffects": [
-          {
-            "type": "ricochet_damage",
-            "priority": 1,
-            "params": {
-              "damage": 25,
-              "ricochetCount": 2,
-              "ricochetAngle": 45
-            }
+      "id": "weapon_001",
+      "name": "基础步枪",
+      "type": "步枪",
+      "rarity": "普通",
+      "weight": 100,
+      "baseDamage": 10,
+      "fireRate": 1.0,
+      "range": 300,
+      "bulletSpeed": 500,
+      "maxLevel": 10,
+      "upgradeConfig": {
+        "maxLevel": 10,
+        "levels": {
+          "1": {
+            "cost": 25,
+            "damageIncrease": 1
           },
-          {
-            "type": "pierce_damage",
-            "priority": 2,
-            "params": {
-              "damage": 25,
-              "pierceCount": 3
-            }
-          }
-        ],
-        "lifecycle": {
-          "type": "ricochet_counter",
-          "maxLifetime": 8.0,
-          "penetration": 3,
-          "ricochetCount": 3,
-          "returnToOrigin": false
-        },
-        "visual": {
-          "bulletPrefab": "bullets/SawBullet",
-          "hitEffect": "Animation/WeaponTx/tx0002/tx0002",
-          "trailEffect": null,
-          "muzzleFlash": "Animation/WeaponTx/tx0002/tx0002"
-        }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/003",
-          "H-I": "images/PlantsSprite/003",
-          "L": "images/PlantsSprite/003",
-          "S": "images/PlantsSprite/003",
-          "D-T": "images/PlantsSprite/003"
-        },
-        "fireSound": "audio/saw_shot"
-      }
-    },
-    {
-      "id": "watermelon_bomb",
-      "name": "西瓜炸弹",
-      "type": "explosive",
-      "rarity": "rare",
-      "weight": 15,
-      "stats": {
-        "damage": 50,
-        "fireRate": 0.4,
-        "range": 250,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "arc",
-          "speed": 20,
-          "gravity": 0,
-          "rotateSpeed": 0.5,
-          "homingStrength": 0,
-          "homingDelay": 0
-        },
-        "hitEffects": [
-          {
-            "type": "explosion",
-            "priority": 1,
-            "params": {
-              "damage": 80,
-              "radius": 100,
-              "delay": 0.1
-            }
-          }
-        ],
-        "lifecycle": {
-          "type": "ground_impact",
-          "maxLifetime": 5.0,
-          "penetration": 1,
-          "ricochetCount": 0,
-          "returnToOrigin": false
-        },
-        "visual": {
-          "bulletPrefab": "bullets/WatermelonBomb",
-          "hitEffect": "Animation/WeaponTx/tx0007/tx0007",
-          "trailEffect": null,
-          "muzzleFlash": "Animation/WeaponTx/tx0007/tx0007"
-        }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/007",
-          "H-I": "images/PlantsSprite/007",
-          "L": "images/PlantsSprite/007",
-          "S": "images/PlantsSprite/007",
-          "D-T": "images/PlantsSprite/007"
-        },
-        "fireSound": "audio/bomb_launch"
-      }
-    },
-    {
-      "id": "boomerang_plant",
-      "name": "回旋镖盆栽",
-      "type": "boomerang",
-      "rarity": "uncommon",
-      "weight": 18,
-      "stats": {
-        "damage": 30,
-        "fireRate": 0.5,
-        "range": 300,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "homing",
-          "speed": 15,
-          "gravity": 0,
-          "homingStrength": 0.5,
-          "homingDelay": 0.3
-        },
-        "hitEffects": [
-          {
-            "type": "pierce_damage",
-            "priority": 1,
-            "params": {
-              "damage": 30,
-              "pierceCount": 999
-            }
-          }
-        ],
-        "lifecycle": {
-          "type": "return_trip",
-          "maxLifetime": 10.0,
-          "penetration": 999,
-          "ricochetCount": 0,
-          "returnToOrigin": true,
-          "returnDelay": 1.0
-        },
-        "visual": {
-          "bulletPrefab": "bullets/BoomerangBullet",
-          "hitEffect": "Animation/WeaponTx/tx0003/tx0003",
-          "trailEffect": null,
-          "muzzleFlash": "Animation/WeaponTx/tx0003/tx0003"
-        }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/004",
-          "H-I": "images/PlantsSprite/004",
-          "L": "images/PlantsSprite/004",
-          "S": "images/PlantsSprite/004",
-          "D-T": "images/PlantsSprite/004"
-        },
-        "fireSound": "audio/boomerang_throw"
-      }
-    },
-    {
-      "id": "hot_pepper",
-      "name": "炙热辣椒",
-      "type": "area_burn",
-      "rarity": "rare",
-      "weight": 12,
-      "stats": {
-        "damage": 40,
-        "fireRate": 0.3,
-        "range": 280,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "straight",
-          "speed": 100,
-          "gravity": 0,
-          "arcHeight": 0,
-          "homingStrength": 0,
-          "homingDelay": 0
-        },
-        "hitEffects": [
-          {
-            "type": "explosion",
-            "priority": 1,
-            "params": {
-              "damage": 40,
-              "radius": 120,
-              "delay": 0.2
-            }
+          "2": {
+            "cost": 50,
+            "damageIncrease": 2
           },
-          {
-            "type": "ground_burn",
-            "priority": 2,
-            "params": {
-              "damage": 10,
-              "duration": 5.0,
-              "radius": 120,
-              "tickInterval": 0.5
-            }
-          }
-        ],
-        "lifecycle": {
-          "type": "ground_impact_with_effect",
-          "maxLifetime": 5.0,
-          "penetration": 1,
-          "ricochetCount": 0,
-          "returnToOrigin": false,
-          "effectDuration": 5.0
-        },
-        "visual": {
-          "bulletPrefab": "bullets/PepperBomb",
-          "hitEffect": "Animation/WeaponTx/tx0005/tx0005",
-          "trailEffect": null,
-          "burnEffect": "Animation/WeaponTx/tx0005/tx0005",
-          "muzzleFlash": "Animation/WeaponTx/tx0005/tx0005"
-        }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/005",
-          "H-I": "images/PlantsSprite/005",
-          "L": "images/PlantsSprite/005",
-          "S": "images/PlantsSprite/005",
-          "D-T": "images/PlantsSprite/005"
-        },
-        "fireSound": "audio/pepper_launch"
-      }
-    },
-    {
-      "id": "cactus_shotgun",
-      "name": "仙人散弹",
-      "type": "shotgun",
-      "rarity": "uncommon",
-      "weight": 22,
-      "stats": {
-        "damage": 12,
-        "fireRate": 0.7,
-        "range": 200,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "spread",
-          "amount": 5,
-          "spreadAngle": 30,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "straight",
-          "speed": 180,
-          "gravity": 0,
-          "arcHeight": 0,
-          "homingStrength": 0,
-          "homingDelay": 0
-        },
-        "hitEffects": [
-          {
-            "type": "normal_damage",
-            "priority": 1,
-            "params": {
-              "damage": 12
-            }
+          "3": {
+            "cost": 75,
+            "damageIncrease": 3
+          },
+          "4": {
+            "cost": 100,
+            "damageIncrease": 4
+          },
+          "5": {
+            "cost": 125,
+            "damageIncrease": 5
           }
-        ],
-        "lifecycle": {
-          "type": "range_limit",
-          "maxLifetime": 3.0,
-          "penetration": 1,
-          "ricochetCount": 0,
-          "returnToOrigin": false,
-          "maxRange": 2000
-        },
-        "visual": {
-          "bulletPrefab": "bullets/CactusBullet",
-          "hitEffect": "Animation/WeaponTx/tx0005/tx0005",
-          "trailEffect": null,
-          "muzzleFlash": "Animation/WeaponTx/tx0005/tx0005"
         }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/008",
-          "H-I": "images/PlantsSprite/008",
-          "L": "images/PlantsSprite/008",
-          "S": "images/PlantsSprite/008",
-          "D-T": "images/PlantsSprite/008"
-        },
-        "fireSound": "audio/cactus_shot"
       }
     },
     {
-      "id": "okra_missile",
-      "name": "秋葵导弹",
-      "type": "homing_missile",
-      "rarity": "epic",
-      "weight": 8,
-      "stats": {
-        "damage": 70,
-        "fireRate": 0.25,
-        "range": 500,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "homing",
-          "speed": 20,
-          "gravity": 0.2,
-          "arcHeight": 100,
-          "homingStrength": 0.8,
-          "homingDelay": 0.3
-        },
-        "hitEffects": [
-          {
-            "type": "explosion",
-            "priority": 1,
-            "params": {
-              "damage": 70,
-              "radius": 150,
-              "delay": 0
-            }
+      "id": "weapon_002",
+      "name": "狙击枪",
+      "type": "狙击枪",
+      "rarity": "稀有",
+      "weight": 50,
+      "baseDamage": 25,
+      "fireRate": 0.5,
+      "range": 600,
+      "bulletSpeed": 800,
+      "maxLevel": 8,
+      "upgradeConfig": {
+        "maxLevel": 8,
+        "levels": {
+          "1": {
+            "cost": 50,
+            "damageIncrease": 3
+          },
+          "2": {
+            "cost": 100,
+            "damageIncrease": 5
+          },
+          "3": {
+            "cost": 150,
+            "damageIncrease": 7
+          },
+          "4": {
+            "cost": 200,
+            "damageIncrease": 10
           }
-        ],
-        "lifecycle": {
-          "type": "target_impact",
-          "maxLifetime": 8.0,
-          "penetration": 1,
-          "ricochetCount": 0,
-          "returnToOrigin": false
-        },
-        "visual": {
-          "bulletPrefab": "bullets/OkraMissile",
-          "hitEffect": "Animation/WeaponTx/tx0006/tx0006",
-          "trailEffect": null,
-          "muzzleFlash": "Animation/WeaponTx/tx0006/tx0006"
         }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/006",
-          "H-I": "images/PlantsSprite/006",
-          "L": "images/PlantsSprite/006",
-          "S": "images/PlantsSprite/006",
-          "D-T": "images/PlantsSprite/006"
-        },
-        "fireSound": "audio/missile_launch"
       }
     },
     {
-      "id": "mace_club",
-      "name": "狼牙棒",
-      "type": "single_shot",
-      "rarity": "uncommon",
-      "weight": 20,
-      "stats": {
-        "damage": 40,
-        "fireRate": 1.0,
-        "range": 300,
-        "bulletSpeed": 30
-      },
-      "bulletConfig": {
-        "count": {
-          "type": "single",
-          "amount": 1,
-          "spreadAngle": 0,
-          "burstCount": 1,
-          "burstDelay": 0
-        },
-        "trajectory": {
-          "type": "straight",
-          "speed": 200,
-          "gravity": 0,
-          "arcHeight": 0,
-          "homingStrength": 0,
-          "homingDelay": 0
-        },
-        "hitEffects": [
-          {
-            "type": "normal_damage",
-            "priority": 1,
-            "params": {
-              "damage": 40
-            }
+      "id": "weapon_003",
+      "name": "霰弹枪",
+      "type": "霰弹枪",
+      "rarity": "普通",
+      "weight": 80,
+      "baseDamage": 15,
+      "fireRate": 0.8,
+      "range": 150,
+      "bulletSpeed": 400,
+      "maxLevel": 12,
+      "upgradeConfig": {
+        "maxLevel": 12,
+        "levels": {
+          "1": {
+            "cost": 30,
+            "damageIncrease": 2
+          },
+          "2": {
+            "cost": 60,
+            "damageIncrease": 3
+          },
+          "3": {
+            "cost": 90,
+            "damageIncrease": 4
+          },
+          "4": {
+            "cost": 120,
+            "damageIncrease": 5
+          },
+          "5": {
+            "cost": 150,
+            "damageIncrease": 6
           }
-        ],
-        "lifecycle": {
-          "type": "hit_destroy",
-          "maxLifetime": 5.0,
-          "penetration": 1,
-          "ricochetCount": 0,
-          "returnToOrigin": false
-        },
-        "visual": {
-          "bulletPrefab": "bullets/MaceBullet",
-          "hitEffect": "Animation/WeaponTx/tx0002/tx0002",
-          "trailEffect": null,
-          "muzzleFlash": "Animation/WeaponTx/tx0002/tx0002"
         }
-      },
-      "visualConfig": {
-        "weaponSprites": {
-          "I": "images/PlantsSprite/009",
-          "H-I": "images/PlantsSprite/009",
-          "L": "images/PlantsSprite/009",
-          "S": "images/PlantsSprite/009",
-          "D-T": "images/PlantsSprite/009"
-        },
-        "fireSound": "audio/mace_shot"
       }
     }
-  ],
-  "rarityWeights": {
-    "common": 60,
-    "uncommon": 25,
-    "rare": 12,
-    "epic": 3
-  },
-  "blockSizes": [
-    {
-      "id": "I",
-      "name": "竖条",
-      "shape": [
-        [1,0,0,0],
-        [1,0,0,0],
-        [0,0,0,0],
-        [0,0,0,0]
-      ]
-    },
-    {
-      "id": "H-I",
-      "name": "横I型",
-      "shape": [
-        [0,0,0,0],
-        [1,1,0,0],
-        [0,0,0,0],
-        [0,0,0,0]
-      ]
-    },
-    {
-      "id": "L",
-      "name": "L型",
-      "shape": [
-        [1,1,0,0],
-        [1,0,0,0],
-        [0,0,0,0],
-        [0,0,0,0]
-      ]
-    },
-    {
-      "id": "S",
-      "name": "S型",
-      "shape": [
-        [0,1,1,0],
-        [1,1,0,0],
-        [0,0,0,0],
-        [0,0,0,0]
-      ]
-    },
-    {
-      "id": "D-T",
-      "name": "倒T型",
-      "shape": [
-        [0,1,0,0],
-        [1,1,1,0],
-        [0,0,0,0],
-        [0,0,0,0]
-      ]
-    }
-  ],
-  "bulletEffectTypes": {
-    "count": ["single", "spread", "burst"],
-    "trajectory": ["straight", "arc", "homing_arc"],
-    "hitEffects": ["normal_damage", "pierce_damage", "explosion", "ground_burn", "ricochet_damage"],
-    "lifecycle": ["hit_destroy", "range_limit", "ricochet_counter", "ground_impact", "return_trip", "ground_impact_with_effect", "target_impact"]
-  }
+  ]
 }

+ 28 - 103
assets/scripts/FourUI/UpgradeSystem/UpgradeController.ts

@@ -52,7 +52,6 @@ export class UpgradeController extends Component {
     @property(Button) panelUpgradeBtn: Button = null;          // Canvas/UpgradeUI/UpgradePanel/UpgradeBtn
     
     // 武器节点预制体
-    @property(Prefab) weaponNodePrefab: Prefab = null;
     @property(Prefab) lockedWeaponPrefab: Prefab = null;    // Lock.prefab
     @property(Prefab) unlockedWeaponPrefab: Prefab = null;  // Unlock.prefab
     
@@ -317,29 +316,18 @@ export class UpgradeController extends Component {
             if (this.unlockedWeaponPrefab) {
                 weaponNode = instantiate(this.unlockedWeaponPrefab);
                 this.setupUnlockedWeaponNode(weaponNode, weaponConfig, weaponData);
-            } else if (this.weaponNodePrefab) {
-                weaponNode = instantiate(this.weaponNodePrefab);
-                this.convertToUnlockedNode(weaponNode, weaponConfig, weaponData, index);
             }
         } else {
             if (this.lockedWeaponPrefab) {
                 weaponNode = instantiate(this.lockedWeaponPrefab);
                 this.setupLockedWeaponNode(weaponNode, weaponConfig);
-            } else if (this.weaponNodePrefab) {
-                weaponNode = instantiate(this.weaponNodePrefab);
-                this.convertToLockedNode(weaponNode, weaponConfig, index);
             }
         }
         
-        // 如果没有任何预制体,创建基本节点
+        // 如果没有预制体,记录警告
         if (!weaponNode) {
-            weaponNode = new Node(`WeaponNode_${index}`);
-            weaponNode.addComponent(UIOpacity);
-            if (isUnlocked) {
-                this.convertToUnlockedNode(weaponNode, weaponConfig, weaponData, index);
-            } else {
-                this.convertToLockedNode(weaponNode, weaponConfig, index);
-            }
+            console.warn(`无法创建武器节点 ${weaponConfig.name}: 缺少对应的预制体`);
+            return;
         }
         
         // 设置节点名称
@@ -467,88 +455,7 @@ export class UpgradeController extends Component {
         }, this);
     }
     
-    /**
-     * 转换为锁定节点
-     */
-    private convertToLockedNode(weaponNode: Node, weaponConfig: WeaponConfig, index: number) {
-        // 隐藏正常武器节点的所有子节点
-        const spriteNode = weaponNode.getChildByName('WeaponIcon') || 
-                          weaponNode.getChildByName('Icon') ||
-                          weaponNode.getChildByName('WeaponSprite') ||
-                          weaponNode.getChildByName('Sprite');
-        if (spriteNode) {
-            spriteNode.active = false;
-        }
-        
-        const upgradeBtn = weaponNode.getChildByName('Upgrade');
-        if (upgradeBtn) {
-            upgradeBtn.active = false;
-        }
-        
-        // 创建或显示锁定状态的Label
-        let lockLabel = weaponNode.getChildByName('LockLabel');
-        if (!lockLabel) {
-            lockLabel = new Node('LockLabel');
-            const labelComp = lockLabel.addComponent(Label);
-            labelComp.fontSize = 24;
-            labelComp.color = Color.WHITE;
-            weaponNode.addChild(lockLabel);
-        }
-        
-        const labelComp = lockLabel.getComponent(Label);
-        if (labelComp) {
-            const unlockLevel = this.getWeaponUnlockLevel(weaponConfig.name);
-            labelComp.string = `通关第${unlockLevel}关解锁`;
-        }
-        
-        lockLabel.active = true;
-        
-        // 设置节点为锁定状态
-        let uiOpacity = weaponNode.getComponent(UIOpacity);
-        if (!uiOpacity) {
-            uiOpacity = weaponNode.addComponent(UIOpacity);
-        }
-        uiOpacity.opacity = 180;
-        weaponNode.active = true;
-        
-        // 锁定武器节点保持可点击状态以显示解锁提示
-    }
-    
-    /**
-     * 转换为解锁节点
-     */
-    private convertToUnlockedNode(weaponNode: Node, weaponConfig: WeaponConfig, weaponData: any, index: number) {
-        // 隐藏锁定状态的Label
-        const lockLabel = weaponNode.getChildByName('LockLabel');
-        if (lockLabel) {
-            lockLabel.active = false;
-        }
-        
-        // 显示正常武器节点的所有子节点
-        const spriteNode = weaponNode.getChildByName('WeaponIcon') || 
-                          weaponNode.getChildByName('Icon') ||
-                          weaponNode.getChildByName('WeaponSprite') ||
-                          weaponNode.getChildByName('Sprite');
-        if (spriteNode) {
-            spriteNode.active = true;
-        }
-        
-        const upgradeBtn = weaponNode.getChildByName('Upgrade');
-        if (upgradeBtn) {
-            upgradeBtn.active = true;
-        }
-        
-        // 恢复透明度
-        let uiOpacity = weaponNode.getComponent(UIOpacity);
-        if (uiOpacity) {
-            uiOpacity.opacity = 255;
-        }
-        
-        // 设置为解锁状态
-        this.setupUnlockedWeaponNode(weaponNode, weaponConfig, weaponData);
-        
-        // 解锁武器节点保持可点击状态
-    }
+
     
    
     /**
@@ -626,8 +533,8 @@ export class UpgradeController extends Component {
         
         // 计算当前伤害(基础伤害 + 等级加成)- Canvas/UpgradeUI/UpgradePanel/NumberBack/CurrentDamage
         const baseDamage = weaponConfig.stats.damage;
-        const currentDamage = this.calculateWeaponDamage(baseDamage, weaponData.level);
-        const nextLevelDamage = this.calculateWeaponDamage(baseDamage, weaponData.level + 1);
+        const currentDamage = this.calculateWeaponDamage(baseDamage, weaponData.level, this.currentSelectedWeapon);
+        const nextLevelDamage = this.calculateWeaponDamage(baseDamage, weaponData.level + 1, this.currentSelectedWeapon);
         const damageIncrease = nextLevelDamage - currentDamage;
         
         if (this.panelCurrentDamage) {
@@ -648,11 +555,29 @@ export class UpgradeController extends Component {
     /**
      * 计算武器伤害
      */
-    private calculateWeaponDamage(baseDamage: number, level: number): number {
+    private calculateWeaponDamage(baseDamage: number, level: number, weaponId?: string): number {
         if (level === 0) return 0; // 未解锁武器伤害为0
         
-        // 伤害增加:升级后伤害 = 升级前伤害 + 1(固定 + 1)
-        // 1级武器 = 基础伤害,每升1级增加1点伤害
+        // 从武器配置中获取伤害增加值
+        if (weaponId && this.weaponsConfig && this.weaponsConfig.weapons) {
+            const weaponConfig = this.weaponsConfig.weapons.find(w => w.id === weaponId);
+            // 由于WeaponConfig中没有upgradeConfig属性,直接使用基础伤害计算
+            if (weaponConfig && weaponConfig.stats && weaponConfig.stats.damage) {
+                let totalDamageIncrease = 0;
+                
+                // 累加从1级到当前级别的所有伤害增加
+                for (let i = 1; i < level; i++) {
+                    // 从武器配置的stats中获取每级伤害增加值
+                    if (this.levelConfigs[i] && this.levelConfigs[i].damageIncrease) {
+                        totalDamageIncrease += this.levelConfigs[i].damageIncrease;
+                    }
+                }
+                
+                return baseDamage + totalDamageIncrease;
+            }
+        }
+        
+        // 如果配置不存在,使用默认公式作为后备
         return baseDamage + (level - 1);
     }
     
@@ -830,7 +755,7 @@ export class UpgradeController extends Component {
         
         if (!weaponConfig || !weaponData) return 0;
         
-        return this.calculateWeaponDamage(weaponConfig.stats.damage, weaponData.level);
+        return this.calculateWeaponDamage(weaponConfig.stats.damage, weaponData.level, weaponId);
     }
     
     /**

+ 52 - 2
assets/scripts/LevelSystem/SaveDataManager.ts

@@ -3,6 +3,21 @@ import { LevelConfigManager } from './LevelConfigManager';
 import EventBus, { GameEvents } from '../Core/EventBus';
 const { ccclass, property } = _decorator;
 
+/**
+ * 武器配置数据接口
+ */
+interface WeaponConfig {
+    id: string;
+    name: string;
+    description: string;
+    rarity: string;
+    unlockLevel: number;
+    baseDamage: number;
+    baseSpeed: number;
+    upgradeCosts: number[];
+    maxLevel: number;
+}
+
 /**
  * 玩家数据结构
  */
@@ -142,6 +157,9 @@ export class SaveDataManager {
     private autoSaveInterval: number = 30; // 自动保存间隔(秒)
     private lastSaveTime: number = 0;
     
+    // 武器配置数据
+    private weaponsConfig: { weapons: any[] } = null;
+    
     // 最近的奖励记录(用于UI显示)
     private lastRewards: {money: number, diamonds: number} = {money: 0, diamonds: 0};
     
@@ -164,13 +182,34 @@ export class SaveDataManager {
     /**
      * 初始化存档管理器
      */
-    public initialize(): void {
+    public async initialize(): Promise<void> {
         if (this.initialized) return;
         
         this.loadPlayerData();
+        await this.loadWeaponsConfig();
         this.initialized = true;
     }
     
+    /**
+     * 加载武器配置
+     */
+    private async loadWeaponsConfig(): Promise<void> {
+        try {
+            const jsonAsset = await new Promise<any>((resolve, reject) => {
+                resources.load('data/weapons', (err, asset) => {
+                    if (err) reject(err);
+                    else resolve(asset);
+                });
+            });
+            
+            this.weaponsConfig = jsonAsset.json;
+            console.log('[SaveDataManager] 武器配置加载成功');
+        } catch (error) {
+            console.error('[SaveDataManager] 加载武器配置失败:', error);
+            this.weaponsConfig = { weapons: [] };
+        }
+    }
+    
     /**
      * 加载玩家数据
      */
@@ -775,7 +814,18 @@ export class SaveDataManager {
         const weapon = this.getWeapon(weaponId);
         if (!weapon || weapon.level === 0) return 0; // 0级武器需要解锁,不是升级
         
-        // 金币消耗:升级消耗金币 = 25 × 升级前武器等级
+        // 从武器配置中获取升级费用
+        if (this.weaponsConfig && this.weaponsConfig.weapons) {
+            const weaponConfig = this.weaponsConfig.weapons.find(w => w.id === weaponId);
+            if (weaponConfig && weaponConfig.upgradeConfig && weaponConfig.upgradeConfig.levels) {
+                const levelConfig = weaponConfig.upgradeConfig.levels[weapon.level.toString()];
+                if (levelConfig && levelConfig.cost) {
+                    return levelConfig.cost;
+                }
+            }
+        }
+        
+        // 如果配置不存在,使用默认公式作为后备
         return 25 * weapon.level;
     }
     

+ 1 - 1
assets/scripts/LevelSystem/StartGame.ts

@@ -120,7 +120,7 @@ export class StartGame extends Component {
         
         // 初始化存档管理器
         const saveDataManager = SaveDataManager.getInstance();
-        saveDataManager.initialize();
+        await saveDataManager.initialize();
         
         // 重新初始化LevelSessionManager,设置sessionCoins为45
         LevelSessionManager.inst.initialize(

+ 280 - 0
方块放置逻辑流程图.svg

@@ -0,0 +1,280 @@
+<svg width="1200" height="1600" xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <style>
+      .title { font-family: Arial, sans-serif; font-size: 20px; font-weight: bold; fill: #2c3e50; }
+      .subtitle { font-family: Arial, sans-serif; font-size: 14px; font-weight: bold; fill: #34495e; }
+      .text { font-family: Arial, sans-serif; font-size: 12px; fill: #2c3e50; }
+      .small-text { font-family: Arial, sans-serif; font-size: 10px; fill: #7f8c8d; }
+      .start-end { fill: #e74c3c; stroke: #c0392b; stroke-width: 2; }
+      .process { fill: #3498db; stroke: #2980b9; stroke-width: 2; }
+      .decision { fill: #f39c12; stroke: #e67e22; stroke-width: 2; }
+      .success { fill: #27ae60; stroke: #229954; stroke-width: 2; }
+      .error { fill: #e74c3c; stroke: #c0392b; stroke-width: 2; }
+      .arrow { stroke: #2c3e50; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
+      .yes-arrow { stroke: #27ae60; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
+      .no-arrow { stroke: #e74c3c; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
+    </style>
+    <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
+      <polygon points="0 0, 10 3.5, 0 7" fill="#2c3e50" />
+    </marker>
+  </defs>
+  
+  <!-- 标题 -->
+  <text x="600" y="30" text-anchor="middle" class="title">方块放置逻辑流程图</text>
+  <text x="600" y="50" text-anchor="middle" class="small-text">Block Placement Logic Flowchart</text>
+  
+  <!-- 开始 -->
+  <ellipse cx="600" cy="90" rx="60" ry="25" class="start-end"/>
+  <text x="600" y="95" text-anchor="middle" class="text">开始拖拽方块</text>
+  
+  <!-- 箭头1 -->
+  <line x1="600" y1="115" x2="600" y2="140" class="arrow"/>
+  
+  <!-- 设置拖拽事件 -->
+  <rect x="520" y="140" width="160" height="40" rx="5" class="process"/>
+  <text x="600" y="155" text-anchor="middle" class="text">setupBlockDragEvents</text>
+  <text x="600" y="170" text-anchor="middle" class="small-text">设置触摸事件监听</text>
+  
+  <!-- 箭头2 -->
+  <line x1="600" y1="180" x2="600" y2="205" class="arrow"/>
+  
+  <!-- 拖拽开始 -->
+  <rect x="520" y="205" width="160" height="40" rx="5" class="process"/>
+  <text x="600" y="220" text-anchor="middle" class="text">onTouchStart</text>
+  <text x="600" y="235" text-anchor="middle" class="small-text">记录初始位置,禁用碰撞</text>
+  
+  <!-- 箭头3 -->
+  <line x1="600" y1="245" x2="600" y2="270" class="arrow"/>
+  
+  <!-- 拖拽移动 -->
+  <rect x="520" y="270" width="160" height="40" rx="5" class="process"/>
+  <text x="600" y="285" text-anchor="middle" class="text">onTouchMove</text>
+  <text x="600" y="300" text-anchor="middle" class="small-text">更新方块位置,显示调试信息</text>
+  
+  <!-- 箭头4 -->
+  <line x1="600" y1="310" x2="600" y2="335" class="arrow"/>
+  
+  <!-- 拖拽结束 -->
+  <rect x="520" y="335" width="160" height="40" rx="5" class="process"/>
+  <text x="600" y="350" text-anchor="middle" class="text">onTouchEnd</text>
+  <text x="600" y="365" text-anchor="middle" class="small-text">调用handleBlockDrop</text>
+  
+  <!-- 箭头5 -->
+  <line x1="600" y1="375" x2="600" y2="400" class="arrow"/>
+  
+  <!-- 处理方块放置 -->
+  <rect x="520" y="400" width="160" height="40" rx="5" class="process"/>
+  <text x="600" y="415" text-anchor="middle" class="text">handleBlockDrop</text>
+  <text x="600" y="430" text-anchor="middle" class="small-text">核心放置逻辑处理</text>
+  
+  <!-- 箭头6 -->
+  <line x1="600" y1="440" x2="600" y2="480" class="arrow"/>
+  
+  <!-- 判断是否在kuang区域 -->
+  <polygon points="600,480 680,510 600,540 520,510" class="decision"/>
+  <text x="600" y="505" text-anchor="middle" class="text">是否在kuang</text>
+  <text x="600" y="520" text-anchor="middle" class="text">区域内?</text>
+  
+  <!-- kuang区域处理分支 -->
+  <line x1="680" y1="510" x2="780" y2="510" class="yes-arrow"/>
+  <text x="730" y="505" text-anchor="middle" class="small-text">是</text>
+  
+  <!-- 检查标签 -->
+  <polygon points="780,480 860,510 780,540 700,510" class="decision"/>
+  <text x="780" y="505" text-anchor="middle" class="text">BlockTag</text>
+  <text x="780" y="520" text-anchor="middle" class="text">hasTag?</text>
+  
+  <!-- 有标签 -->
+  <line x1="860" y1="510" x2="960" y2="510" class="yes-arrow"/>
+  <text x="910" y="505" text-anchor="middle" class="small-text">有标签</text>
+  
+  <rect x="880" y="490" width="160" height="40" rx="5" class="success"/>
+  <text x="960" y="505" text-anchor="middle" class="text">放回kuang区域</text>
+  <text x="960" y="520" text-anchor="middle" class="small-text">移除标签,恢复原位置</text>
+  
+  <!-- 无标签 -->
+  <line x1="780" y1="540" x2="780" y2="580" class="no-arrow"/>
+  <text x="790" y="565" text-anchor="middle" class="small-text">无标签</text>
+  
+  <rect x="700" y="580" width="160" height="40" rx="5" class="error"/>
+  <text x="780" y="595" text-anchor="middle" class="text">拒绝放置</text>
+  <text x="780" y="610" text-anchor="middle" class="small-text">恢复到原位置</text>
+  
+  <!-- 网格区域处理分支 -->
+  <line x1="520" y1="510" x2="420" y2="510" class="no-arrow"/>
+  <text x="470" y="505" text-anchor="middle" class="small-text">否</text>
+  
+  <!-- 尝试放置到网格 -->
+  <rect x="340" y="490" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="505" text-anchor="middle" class="text">tryPlaceBlockToGrid</text>
+  <text x="420" y="520" text-anchor="middle" class="small-text">BlockManager处理</text>
+  
+  <!-- 箭头到网格检查 -->
+  <line x1="420" y1="530" x2="420" y2="570" class="arrow"/>
+  
+  <!-- 检查网格初始化 -->
+  <polygon points="420,570 500,600 420,630 340,600" class="decision"/>
+  <text x="420" y="595" text-anchor="middle" class="text">网格是否</text>
+  <text x="420" y="610" text-anchor="middle" class="text">初始化?</text>
+  
+  <!-- 网格未初始化 -->
+  <line x1="340" y1="600" x2="240" y2="600" class="no-arrow"/>
+  <text x="290" y="595" text-anchor="middle" class="small-text">否</text>
+  
+  <rect x="160" y="580" width="160" height="40" rx="5" class="error"/>
+  <text x="240" y="595" text-anchor="middle" class="text">放置失败</text>
+  <text x="240" y="610" text-anchor="middle" class="small-text">网格未初始化</text>
+  
+  <!-- 网格已初始化 -->
+  <line x1="420" y1="630" x2="420" y2="670" class="yes-arrow"/>
+  <text x="430" y="655" text-anchor="middle" class="small-text">是</text>
+  
+  <!-- 查找B1节点 -->
+  <rect x="340" y="670" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="685" text-anchor="middle" class="text">查找B1节点</text>
+  <text x="420" y="700" text-anchor="middle" class="small-text">获取方块基准位置</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="710" x2="420" y2="750" class="arrow"/>
+  
+  <!-- 坐标转换 -->
+  <rect x="340" y="750" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="765" text-anchor="middle" class="text">坐标转换</text>
+  <text x="420" y="780" text-anchor="middle" class="small-text">世界坐标→网格本地坐标</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="790" x2="420" y2="830" class="arrow"/>
+  
+  <!-- 边界检查 -->
+  <polygon points="420,830 500,860 420,890 340,860" class="decision"/>
+  <text x="420" y="855" text-anchor="middle" class="text">是否在网格</text>
+  <text x="420" y="870" text-anchor="middle" class="text">边界内?</text>
+  
+  <!-- 超出边界 -->
+  <line x1="340" y1="860" x2="240" y2="860" class="no-arrow"/>
+  <text x="290" y="855" text-anchor="middle" class="small-text">否</text>
+  
+  <rect x="160" y="840" width="160" height="40" rx="5" class="error"/>
+  <text x="240" y="855" text-anchor="middle" class="text">超出边界</text>
+  <text x="240" y="870" text-anchor="middle" class="small-text">放置失败</text>
+  
+  <!-- 在边界内 -->
+  <line x1="420" y1="890" x2="420" y2="930" class="yes-arrow"/>
+  <text x="430" y="915" text-anchor="middle" class="small-text">是</text>
+  
+  <!-- 查找最近网格 -->
+  <rect x="340" y="930" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="945" text-anchor="middle" class="text">findNearestGridNode</text>
+  <text x="420" y="960" text-anchor="middle" class="small-text">找到最近的网格节点</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="970" x2="420" y2="1010" class="arrow"/>
+  
+  <!-- 尝试放置到特定网格 -->
+  <rect x="340" y="1010" width="160" height="50" rx="5" class="process"/>
+  <text x="420" y="1025" text-anchor="middle" class="text">tryPlaceBlockTo</text>
+  <text x="420" y="1040" text-anchor="middle" class="text">SpecificGrid</text>
+  <text x="420" y="1055" text-anchor="middle" class="small-text">精确网格放置</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="1060" x2="420" y2="1100" class="arrow"/>
+  
+  <!-- 检查是否可以放置 -->
+  <polygon points="420,1100 500,1130 420,1160 340,1130" class="decision"/>
+  <text x="420" y="1125" text-anchor="middle" class="text">canPlaceBlockAt</text>
+  <text x="420" y="1140" text-anchor="middle" class="text">检查?</text>
+  
+  <!-- 不能放置 -->
+  <line x1="340" y1="1130" x2="240" y2="1130" class="no-arrow"/>
+  <text x="290" y="1125" text-anchor="middle" class="small-text">否</text>
+  
+  <rect x="160" y="1110" width="160" height="40" rx="5" class="error"/>
+  <text x="240" y="1125" text-anchor="middle" class="text">网格被占用</text>
+  <text x="240" y="1140" text-anchor="middle" class="small-text">或形状不匹配</text>
+  
+  <!-- 可以放置 -->
+  <line x1="420" y1="1160" x2="420" y2="1200" class="yes-arrow"/>
+  <text x="430" y="1185" text-anchor="middle" class="small-text">是</text>
+  
+  <!-- 成功放置处理 -->
+  <rect x="340" y="1200" width="160" height="50" rx="5" class="process"/>
+  <text x="420" y="1215" text-anchor="middle" class="text">handleSuccessful</text>
+  <text x="420" y="1230" text-anchor="middle" class="text">Placement</text>
+  <text x="420" y="1245" text-anchor="middle" class="small-text">成功放置后处理</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="1250" x2="420" y2="1290" class="arrow"/>
+  
+  <!-- 标记占用位置 -->
+  <rect x="340" y="1290" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="1305" text-anchor="middle" class="text">markOccupiedPositions</text>
+  <text x="420" y="1320" text-anchor="middle" class="small-text">更新网格占用状态</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="1330" x2="420" y2="1370" class="arrow"/>
+  
+  <!-- 尝试合并 -->
+  <rect x="340" y="1370" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="1385" text-anchor="middle" class="text">tryMergeOnOverlap</text>
+  <text x="420" y="1400" text-anchor="middle" class="small-text">检查是否可以合并</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="1410" x2="420" y2="1450" class="arrow"/>
+  
+  <!-- 添加锁定提示 -->
+  <rect x="340" y="1450" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="1465" text-anchor="middle" class="text">addLockedVisualHint</text>
+  <text x="420" y="1480" text-anchor="middle" class="small-text">添加视觉锁定效果</text>
+  
+  <!-- 箭头 -->
+  <line x1="420" y1="1490" x2="420" y2="1530" class="arrow"/>
+  
+  <!-- 移除标签 -->
+  <rect x="340" y="1530" width="160" height="40" rx="5" class="process"/>
+  <text x="420" y="1545" text-anchor="middle" class="text">BlockTag.removeTag</text>
+  <text x="420" y="1560" text-anchor="middle" class="small-text">移除方块标签</text>
+  
+  <!-- 所有错误路径汇聚到恢复位置 -->
+  <line x1="240" y1="620" x2="240" y2="1400" class="arrow"/>
+  <line x1="240" y1="880" x2="240" y2="1400" class="arrow"/>
+  <line x1="240" y1="1150" x2="240" y2="1400" class="arrow"/>
+  <line x1="780" y1="620" x2="780" y2="1400" class="arrow"/>
+  
+  <!-- 恢复原位置 -->
+  <rect x="160" y="1400" width="160" height="40" rx="5" class="error"/>
+  <text x="240" y="1415" text-anchor="middle" class="text">恢复原位置</text>
+  <text x="240" y="1430" text-anchor="middle" class="small-text">放置失败,恢复到拖拽前位置</text>
+  
+  <!-- 成功结束 -->
+  <line x1="420" y1="1570" x2="600" y2="1570" class="arrow"/>
+  <line x1="960" y1="530" x2="960" y2="1570" class="arrow"/>
+  <line x1="960" y1="1570" x2="600" y2="1570" class="arrow"/>
+  
+  <ellipse cx="600" cy="1570" rx="60" ry="25" class="success"/>
+  <text x="600" y="1575" text-anchor="middle" class="text">放置完成</text>
+  
+  <!-- 图例 -->
+  <rect x="50" y="50" width="200" height="180" fill="none" stroke="#bdc3c7" stroke-width="1"/>
+  <text x="150" y="70" text-anchor="middle" class="subtitle">图例</text>
+  
+  <ellipse cx="80" cy="90" rx="25" ry="12" class="start-end"/>
+  <text x="130" y="95" class="small-text">开始/结束</text>
+  
+  <rect x="55" y="105" width="50" height="20" class="process"/>
+  <text x="130" y="118" class="small-text">处理过程</text>
+  
+  <polygon points="80,130 95,140 80,150 65,140" class="decision"/>
+  <text x="130" y="143" class="small-text">判断条件</text>
+  
+  <rect x="55" y="155" width="50" height="20" class="success"/>
+  <text x="130" y="168" class="small-text">成功操作</text>
+  
+  <rect x="55" y="180" width="50" height="20" class="error"/>
+  <text x="130" y="193" class="small-text">错误/失败</text>
+  
+  <line x1="55" y1="205" x2="105" y2="205" class="yes-arrow"/>
+  <text x="130" y="208" class="small-text">是/成功</text>
+  
+  <line x1="55" y1="220" x2="105" y2="220" class="no-arrow"/>
+  <text x="130" y="223" class="small-text">否/失败</text>
+</svg>