Przeglądaj źródła

部分美术优化

181404010226 4 miesięcy temu
rodzic
commit
67b4d88f25
37 zmienionych plików z 1765 dodań i 211 usunięć
  1. 177 0
      Pellet白色尾迹实现说明.md
  2. 181 172
      assets/Scenes/GameLevel.scene
  3. 188 10
      assets/assets/Prefabs/Pellet.prefab
  4. 2 0
      assets/resources/data/excel/config_manager.py
  5. BIN
      assets/resources/data/excel/关卡配置/关卡配置表.xlsx
  6. 1 0
      assets/resources/data/levels/Level1.json
  7. 1 0
      assets/resources/data/levels/Level2.json
  8. 1 0
      assets/resources/data/levels/Level3.json
  9. 1 0
      assets/resources/data/levels/Level4.json
  10. 1 0
      assets/resources/data/levels/Level5.json
  11. 1 0
      assets/resources/data/levels/Level6.json
  12. 1 0
      assets/resources/data/levels/Level7.json
  13. 1 0
      assets/resources/data/levels/Level8.json
  14. 1 0
      assets/resources/data/levels/Level9.json
  15. 9 0
      assets/resources/images/LevelBackground.meta
  16. BIN
      assets/resources/images/LevelBackground/BG1.jpg
  17. 134 0
      assets/resources/images/LevelBackground/BG1.jpg.meta
  18. BIN
      assets/resources/images/LevelBackground/BG2.jpg
  19. 134 0
      assets/resources/images/LevelBackground/BG2.jpg.meta
  20. BIN
      assets/resources/images/LevelBackground/BG3.jpg
  21. 134 0
      assets/resources/images/LevelBackground/BG3.jpg.meta
  22. BIN
      assets/resources/images/SkillUIImages/1.png
  23. 134 0
      assets/resources/images/SkillUIImages/1.png.meta
  24. BIN
      assets/resources/images/SkillUIImages/2.png
  25. 134 0
      assets/resources/images/SkillUIImages/2.png.meta
  26. 14 14
      assets/scripts/Animations/GameStartMove.ts
  27. 101 0
      assets/scripts/Animations/PelletTrailController.ts
  28. 9 0
      assets/scripts/Animations/PelletTrailController.ts.meta
  29. 24 15
      assets/scripts/CombatSystem/WeaponBullet.ts
  30. 175 0
      assets/scripts/LevelSystem/BackgroundManager.ts
  31. 9 0
      assets/scripts/LevelSystem/BackgroundManager.ts.meta
  32. 60 0
      assets/scripts/LevelSystem/BackgroundUsageExample.md
  33. 11 0
      assets/scripts/LevelSystem/BackgroundUsageExample.md.meta
  34. 33 0
      assets/scripts/LevelSystem/IN_game.ts
  35. 4 0
      assets/scripts/LevelSystem/LevelConfigManager.ts
  36. 80 0
      assets/scripts/TestScene/TestPelletTrail.ts
  37. 9 0
      assets/scripts/TestScene/TestPelletTrail.ts.meta

+ 177 - 0
Pellet白色尾迹实现说明.md

@@ -0,0 +1,177 @@
+# Pellet子弹白色尾迹实现说明
+
+## 概述
+
+本文档说明了如何为 `Pellet.prefab` 预制体添加白色尾迹效果的完整实现方案。通过粒子系统和自定义控制脚本,实现了动态的白色尾迹效果。
+
+## 实现方案
+
+### 1. 预制体结构修改
+
+**文件**: `d:\CocosGame\Pong\assets\assets\Prefabs\Pellet.prefab`
+
+- 在原有的 `ParticleSystem` 子节点中添加了完整的 `ParticleSystem2D` 组件配置
+- 配置了白色尾迹的粒子效果参数:
+  - 起始颜色:白色 (255, 255, 255, 255)
+  - 结束颜色:透明白色 (255, 255, 255, 0)
+  - 粒子生命周期:0.8秒
+  - 发射速度:80像素/秒
+  - 粒子大小:从8像素渐变到2像素
+
+### 2. 尾迹控制器脚本
+
+**文件**: `d:\CocosGame\Pong\assets\scripts\Animations\PelletTrailController.ts`
+
+**功能特性**:
+- 自动检测子弹移动方向并调整粒子发射角度
+- 根据子弹速度动态调整粒子发射率和速度
+- 提供颜色自定义接口
+- 支持启用/禁用尾迹效果
+
+**主要方法**:
+```typescript
+// 设置尾迹颜色
+setTrailColor(r: number, g: number, b: number, a: number = 255)
+
+// 启用/禁用尾迹效果
+setTrailEnabled(enabled: boolean)
+```
+
+### 3. 集成到现有子弹系统
+
+**文件**: `d:\CocosGame\Pong\assets\scripts\CombatSystem\WeaponBullet.ts`
+
+**修改内容**:
+- 导入 `PelletTrailController` 类
+- 在子弹初始化时自动添加尾迹控制器组件
+- 默认设置为白色尾迹效果
+
+**集成代码**:
+```typescript
+// 初始化尾迹控制器
+this.pelletTrailController = this.getComponent(PelletTrailController) || this.addComponent(PelletTrailController);
+// 设置白色尾迹
+this.pelletTrailController.setTrailColor(255, 255, 255, 255);
+this.pelletTrailController.setTrailEnabled(true);
+```
+
+### 4. 测试脚本
+
+**文件**: `d:\CocosGame\Pong\assets\scripts\TestScene\TestPelletTrail.ts`
+
+**功能**:
+- 每2秒自动发射一颗测试子弹
+- 验证白色尾迹效果是否正常工作
+- 提供手动测试接口
+
+## 使用方法
+
+### 自动应用(推荐)
+
+所有通过 `WeaponBullet` 系统创建的子弹都会自动应用白色尾迹效果,无需额外配置。
+
+### 手动控制
+
+如果需要自定义尾迹效果,可以获取 `PelletTrailController` 组件进行配置:
+
+```typescript
+const trailController = bulletNode.getComponent(PelletTrailController);
+if (trailController) {
+    // 设置红色尾迹
+    trailController.setTrailColor(255, 0, 0, 255);
+    
+    // 禁用尾迹
+    trailController.setTrailEnabled(false);
+}
+```
+
+### 测试验证
+
+1. 将 `TestPelletTrail` 脚本添加到场景中的任意节点
+2. 运行游戏,观察是否有带白色尾迹的测试子弹发射
+3. 或者在编辑器中调用 `fireTestBulletManual()` 方法手动测试
+
+## 技术细节
+
+### 粒子系统配置
+
+- **发射模式**: 重力模式 (emitterMode: 0)
+- **位置类型**: 相对位置 (positionType: 1)
+- **粒子总数**: 50个
+- **发射率**: 30个/秒(动态调整)
+- **角度**: 根据子弹移动方向动态计算
+
+### 性能优化
+
+- 粒子数量限制在50个以内
+- 子弹静止时自动停止粒子发射
+- 使用相对位置模式减少计算开销
+
+### 兼容性
+
+- 完全兼容现有的 `WeaponBullet` 系统
+- 不影响子弹的物理行为和碰撞检测
+- 支持所有类型的武器和子弹配置
+
+## 故障排除
+
+### 尾迹不显示
+
+1. 检查 `ParticleSystem2D` 组件是否正确配置
+2. 确认 `PelletTrailController` 组件已添加到子弹节点
+3. 验证粒子系统的 `enabled` 属性为 `true`
+
+### 尾迹方向错误
+
+1. 检查子弹的 `RigidBody2D` 组件是否正常工作
+2. 确认子弹有实际的移动速度
+3. 验证 `updateParticleDirection` 方法的角度计算
+
+### 性能问题
+
+1. 减少 `totalParticles` 数量
+2. 降低 `emissionRate` 发射率
+3. 缩短粒子 `life` 生命周期
+
+## 扩展功能
+
+### 多色尾迹
+
+可以根据子弹类型或武器等级设置不同颜色的尾迹:
+
+```typescript
+// 根据武器类型设置尾迹颜色
+switch (weaponType) {
+    case 'fire':
+        trailController.setTrailColor(255, 100, 0, 255); // 橙色
+        break;
+    case 'ice':
+        trailController.setTrailColor(100, 200, 255, 255); // 蓝色
+        break;
+    default:
+        trailController.setTrailColor(255, 255, 255, 255); // 白色
+}
+```
+
+### 动态尾迹强度
+
+根据子弹伤害或速度调整尾迹的强度:
+
+```typescript
+// 根据子弹速度调整尾迹强度
+const speed = velocity.length();
+const intensity = Math.min(1, speed / 200); // 最大速度200时达到满强度
+trailController.setTrailColor(255, 255, 255, 255 * intensity);
+```
+
+## 总结
+
+通过以上实现,成功为 `Pellet.prefab` 添加了白色尾迹效果。该方案具有以下优势:
+
+1. **自动化**: 所有子弹自动应用尾迹效果
+2. **可定制**: 支持颜色和强度的自定义
+3. **高性能**: 优化的粒子系统配置
+4. **兼容性**: 完全兼容现有系统
+5. **可扩展**: 易于添加新的视觉效果
+
+该实现为游戏的视觉效果提升奠定了良好的基础,可以根据需要进一步扩展和优化。

Plik diff jest za duży
+ 181 - 172
assets/Scenes/GameLevel.scene


+ 188 - 10
assets/assets/Prefabs/Pellet.prefab

@@ -17,24 +17,28 @@
     "_objFlags": 0,
     "__editorExtras__": {},
     "_parent": null,
-    "_children": [],
+    "_children": [
+      {
+        "__id__": 2
+      }
+    ],
     "_active": true,
     "_components": [
       {
-        "__id__": 2
+        "__id__": 6
       },
       {
-        "__id__": 4
+        "__id__": 8
       },
       {
-        "__id__": 6
+        "__id__": 10
       },
       {
-        "__id__": 8
+        "__id__": 12
       }
     ],
     "_prefab": {
-      "__id__": 10
+      "__id__": 14
     },
     "_lpos": {
       "__type__": "cc.Vec3",
@@ -65,6 +69,180 @@
     },
     "_id": ""
   },
+  {
+    "__type__": "cc.Node",
+    "_name": "ParticleSystem",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      },
+      {
+        "__id__": 4
+      }
+    ],
+    "_prefab": {
+      "__id__": 5
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.ParticleSystem2D",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_custom": true,
+    "_file": null,
+    "_spriteFrame": null,
+    "_totalParticles": 50,
+    "_duration": -1,
+    "_emissionRate": 30,
+    "_life": 0.8,
+    "_lifeVar": 0.2,
+    "_startColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_startColorVar": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 0
+    },
+    "_endColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 0
+    },
+    "_endColorVar": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 0
+    },
+    "_angle": 180,
+    "_angleVar": 10,
+    "_startSize": 8,
+    "_startSizeVar": 2,
+    "_endSize": 2,
+    "_endSizeVar": 1,
+    "_startSpin": 0,
+    "_startSpinVar": 0,
+    "_endSpin": 0,
+    "_endSpinVar": 0,
+    "_sourcePos": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_posVar": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_positionType": 1,
+    "_emitterMode": 0,
+    "_gravity": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_speed": 80,
+    "_speedVar": 20,
+    "_tangentialAccel": 0,
+    "_tangentialAccelVar": 0,
+    "_radialAccel": 0,
+    "_radialAccelVar": 0,
+    "_rotationIsDir": false,
+    "_startRadius": 0,
+    "_startRadiusVar": 0,
+    "_endRadius": 0,
+    "_endRadiusVar": 0,
+    "_rotatePerS": 0,
+    "_rotatePerSVar": 0,
+    "_N$preview": true,
+    "playOnLoad": true,
+    "autoRemoveOnFinish": false,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 100
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "f1z+yQ8yNNY6MreVM/9LUs",
+    "nestedPrefabInstanceRoots": null
+  },
   {
     "__type__": "cc.UITransform",
     "_name": "",
@@ -75,7 +253,7 @@
     },
     "_enabled": true,
     "__prefab": {
-      "__id__": 3
+      "__id__": 7
     },
     "_contentSize": {
       "__type__": "cc.Size",
@@ -103,7 +281,7 @@
     },
     "_enabled": true,
     "__prefab": {
-      "__id__": 5
+      "__id__": 9
     },
     "_customMaterial": null,
     "_srcBlendFactor": 2,
@@ -145,7 +323,7 @@
     },
     "_enabled": true,
     "__prefab": {
-      "__id__": 7
+      "__id__": 11
     },
     "enabledContactListener": true,
     "bullet": true,
@@ -179,7 +357,7 @@
     },
     "_enabled": true,
     "__prefab": {
-      "__id__": 9
+      "__id__": 13
     },
     "tag": 3,
     "_group": 8,

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

@@ -1008,6 +1008,7 @@ class ConfigManagerGUI:
                     '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,
@@ -3132,6 +3133,7 @@ class ConfigManagerGUI:
                 "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')))),

BIN
assets/resources/data/excel/关卡配置/关卡配置表.xlsx


+ 1 - 0
assets/resources/data/levels/Level1.json

@@ -3,6 +3,7 @@
   "name": "新手关卡(草地平原)",
   "scene": "grassland",
   "description": "新手引导关卡,学习基础塔防玩法",
+  "backgroundImage": "images/LevelBackground/BG1",
   "availableWeapons": [
     "毛豆射手"
   ],

+ 1 - 0
assets/resources/data/levels/Level2.json

@@ -3,6 +3,7 @@
   "name": "丛林冒险(森林场景)",
   "scene": "forest",
   "description": "森林场景的塔防挑战,引入新的敌人类型和武器组合",
+  "backgroundImage": "images/LevelBackground/BG2",
   "availableWeapons": [
     "尖胡萝卜",
     "毛豆射手"

+ 1 - 0
assets/resources/data/levels/Level3.json

@@ -3,6 +3,7 @@
   "name": "魔法废墟(魔幻场景)",
   "scene": "magic_ruins",
   "description": "魔幻场景的塔防挑战,引入远程攻击敌人和隐身机制",
+  "backgroundImage": "images/LevelBackground/BG3",
   "availableWeapons": [
     "毛豆射手",
     "锯齿草",

+ 1 - 0
assets/resources/data/levels/Level4.json

@@ -3,6 +3,7 @@
   "name": "钢铁堡垒(工业场景)",
   "scene": "industrial",
   "description": "工业场景的高难度挑战,引入BOSS战和超高防御敌人",
+  "backgroundImage": "images/LevelBackground/BG1",
   "availableWeapons": [
     "毛豆射手",
     "锯齿草",

+ 1 - 0
assets/resources/data/levels/Level5.json

@@ -3,6 +3,7 @@
   "name": "终极挑战(赛博都市)",
   "scene": "cyberpunk",
   "description": "终极挑战关卡,包含多个BOSS和复杂的敌人组合",
+  "backgroundImage": "images/LevelBackground/BG1",
   "availableWeapons": [
     "毛豆射手",
     "尖胡萝卜",

+ 1 - 0
assets/resources/data/levels/Level6.json

@@ -3,6 +3,7 @@
   "name": "沙漠绿洲(沙漠场景)",
   "scene": "desert",
   "description": "沙漠场景的挑战,炎热环境下的生存战斗",
+  "backgroundImage": "images/LevelBackground/BG1",
   "availableWeapons": [
     "毛豆射手",
     "尖胡萝卜",

+ 1 - 0
assets/resources/data/levels/Level7.json

@@ -3,6 +3,7 @@
   "name": "冰雪王国(冰雪场景)",
   "scene": "ice",
   "description": "冰雪场景的极地挑战,寒冷环境下的防御战",
+  "backgroundImage": "images/LevelBackground/BG1",
   "availableWeapons": [
     "毛豆射手",
     "尖胡萝卜",

+ 1 - 0
assets/resources/data/levels/Level8.json

@@ -3,6 +3,7 @@
   "name": "火山熔岩(火山场景)",
   "scene": "volcano",
   "description": "火山场景的极限挑战,熔岩环境下的终极考验",
+  "backgroundImage": "images/LevelBackground/BG1",
   "availableWeapons": [
     "毛豆射手",
     "尖胡萝卜",

+ 1 - 0
assets/resources/data/levels/Level9.json

@@ -3,6 +3,7 @@
   "name": "终极试炼(终极场景)",
   "scene": "ultimate",
   "description": "终极试炼关卡,解锁最后的植物武器,面对最强挑战",
+  "backgroundImage": "images/LevelBackground/BG1",
   "availableWeapons": [
     "毛豆射手",
     "尖胡萝卜",

+ 9 - 0
assets/resources/images/LevelBackground.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "1f334ba9-7d97-4bb2-990b-b7f5988000ff",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

BIN
assets/resources/images/LevelBackground/BG1.jpg


+ 134 - 0
assets/resources/images/LevelBackground/BG1.jpg.meta

@@ -0,0 +1,134 @@
+{
+  "ver": "1.0.27",
+  "importer": "image",
+  "imported": true,
+  "uuid": "8faf17d5-7269-4774-b6b0-cc99969ffe99",
+  "files": [
+    ".jpg",
+    ".json"
+  ],
+  "subMetas": {
+    "6c48a": {
+      "importer": "texture",
+      "uuid": "8faf17d5-7269-4774-b6b0-cc99969ffe99@6c48a",
+      "displayName": "BG1",
+      "id": "6c48a",
+      "name": "texture",
+      "userData": {
+        "wrapModeS": "clamp-to-edge",
+        "wrapModeT": "clamp-to-edge",
+        "imageUuidOrDatabaseUri": "8faf17d5-7269-4774-b6b0-cc99969ffe99",
+        "isUuid": true,
+        "visible": false,
+        "minfilter": "linear",
+        "magfilter": "linear",
+        "mipfilter": "none",
+        "anisotropy": 0
+      },
+      "ver": "1.0.22",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    },
+    "f9941": {
+      "importer": "sprite-frame",
+      "uuid": "8faf17d5-7269-4774-b6b0-cc99969ffe99@f9941",
+      "displayName": "BG1",
+      "id": "f9941",
+      "name": "spriteFrame",
+      "userData": {
+        "trimThreshold": 1,
+        "rotated": false,
+        "offsetX": 0,
+        "offsetY": 0,
+        "trimX": 0,
+        "trimY": 0,
+        "width": 720,
+        "height": 1334,
+        "rawWidth": 720,
+        "rawHeight": 1334,
+        "borderTop": 0,
+        "borderBottom": 0,
+        "borderLeft": 0,
+        "borderRight": 0,
+        "packable": true,
+        "pixelsToUnit": 100,
+        "pivotX": 0.5,
+        "pivotY": 0.5,
+        "meshType": 0,
+        "vertices": {
+          "rawPosition": [
+            -360,
+            -667,
+            0,
+            360,
+            -667,
+            0,
+            -360,
+            667,
+            0,
+            360,
+            667,
+            0
+          ],
+          "indexes": [
+            0,
+            1,
+            2,
+            2,
+            1,
+            3
+          ],
+          "uv": [
+            0,
+            1334,
+            720,
+            1334,
+            0,
+            0,
+            720,
+            0
+          ],
+          "nuv": [
+            0,
+            0,
+            1,
+            0,
+            0,
+            1,
+            1,
+            1
+          ],
+          "minPos": [
+            -360,
+            -667,
+            0
+          ],
+          "maxPos": [
+            360,
+            667,
+            0
+          ]
+        },
+        "isUuid": true,
+        "imageUuidOrDatabaseUri": "8faf17d5-7269-4774-b6b0-cc99969ffe99@6c48a",
+        "atlasUuid": "",
+        "trimType": "auto"
+      },
+      "ver": "1.0.12",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    }
+  },
+  "userData": {
+    "type": "sprite-frame",
+    "hasAlpha": false,
+    "fixAlphaTransparencyArtifacts": false,
+    "redirect": "8faf17d5-7269-4774-b6b0-cc99969ffe99@6c48a"
+  }
+}

BIN
assets/resources/images/LevelBackground/BG2.jpg


+ 134 - 0
assets/resources/images/LevelBackground/BG2.jpg.meta

@@ -0,0 +1,134 @@
+{
+  "ver": "1.0.27",
+  "importer": "image",
+  "imported": true,
+  "uuid": "998627cc-798d-4645-8e9b-d9b08a05f610",
+  "files": [
+    ".jpg",
+    ".json"
+  ],
+  "subMetas": {
+    "6c48a": {
+      "importer": "texture",
+      "uuid": "998627cc-798d-4645-8e9b-d9b08a05f610@6c48a",
+      "displayName": "BG2",
+      "id": "6c48a",
+      "name": "texture",
+      "userData": {
+        "wrapModeS": "clamp-to-edge",
+        "wrapModeT": "clamp-to-edge",
+        "imageUuidOrDatabaseUri": "998627cc-798d-4645-8e9b-d9b08a05f610",
+        "isUuid": true,
+        "visible": false,
+        "minfilter": "linear",
+        "magfilter": "linear",
+        "mipfilter": "none",
+        "anisotropy": 0
+      },
+      "ver": "1.0.22",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    },
+    "f9941": {
+      "importer": "sprite-frame",
+      "uuid": "998627cc-798d-4645-8e9b-d9b08a05f610@f9941",
+      "displayName": "BG2",
+      "id": "f9941",
+      "name": "spriteFrame",
+      "userData": {
+        "trimThreshold": 1,
+        "rotated": false,
+        "offsetX": 0,
+        "offsetY": 0,
+        "trimX": 0,
+        "trimY": 0,
+        "width": 720,
+        "height": 1334,
+        "rawWidth": 720,
+        "rawHeight": 1334,
+        "borderTop": 0,
+        "borderBottom": 0,
+        "borderLeft": 0,
+        "borderRight": 0,
+        "packable": true,
+        "pixelsToUnit": 100,
+        "pivotX": 0.5,
+        "pivotY": 0.5,
+        "meshType": 0,
+        "vertices": {
+          "rawPosition": [
+            -360,
+            -667,
+            0,
+            360,
+            -667,
+            0,
+            -360,
+            667,
+            0,
+            360,
+            667,
+            0
+          ],
+          "indexes": [
+            0,
+            1,
+            2,
+            2,
+            1,
+            3
+          ],
+          "uv": [
+            0,
+            1334,
+            720,
+            1334,
+            0,
+            0,
+            720,
+            0
+          ],
+          "nuv": [
+            0,
+            0,
+            1,
+            0,
+            0,
+            1,
+            1,
+            1
+          ],
+          "minPos": [
+            -360,
+            -667,
+            0
+          ],
+          "maxPos": [
+            360,
+            667,
+            0
+          ]
+        },
+        "isUuid": true,
+        "imageUuidOrDatabaseUri": "998627cc-798d-4645-8e9b-d9b08a05f610@6c48a",
+        "atlasUuid": "",
+        "trimType": "auto"
+      },
+      "ver": "1.0.12",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    }
+  },
+  "userData": {
+    "type": "sprite-frame",
+    "hasAlpha": false,
+    "fixAlphaTransparencyArtifacts": false,
+    "redirect": "998627cc-798d-4645-8e9b-d9b08a05f610@6c48a"
+  }
+}

BIN
assets/resources/images/LevelBackground/BG3.jpg


+ 134 - 0
assets/resources/images/LevelBackground/BG3.jpg.meta

@@ -0,0 +1,134 @@
+{
+  "ver": "1.0.27",
+  "importer": "image",
+  "imported": true,
+  "uuid": "2aaa84b9-ecad-4390-b5b4-ed800d51a947",
+  "files": [
+    ".jpg",
+    ".json"
+  ],
+  "subMetas": {
+    "6c48a": {
+      "importer": "texture",
+      "uuid": "2aaa84b9-ecad-4390-b5b4-ed800d51a947@6c48a",
+      "displayName": "BG3",
+      "id": "6c48a",
+      "name": "texture",
+      "userData": {
+        "wrapModeS": "clamp-to-edge",
+        "wrapModeT": "clamp-to-edge",
+        "imageUuidOrDatabaseUri": "2aaa84b9-ecad-4390-b5b4-ed800d51a947",
+        "isUuid": true,
+        "visible": false,
+        "minfilter": "linear",
+        "magfilter": "linear",
+        "mipfilter": "none",
+        "anisotropy": 0
+      },
+      "ver": "1.0.22",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    },
+    "f9941": {
+      "importer": "sprite-frame",
+      "uuid": "2aaa84b9-ecad-4390-b5b4-ed800d51a947@f9941",
+      "displayName": "BG3",
+      "id": "f9941",
+      "name": "spriteFrame",
+      "userData": {
+        "trimThreshold": 1,
+        "rotated": false,
+        "offsetX": 0,
+        "offsetY": 0,
+        "trimX": 0,
+        "trimY": 0,
+        "width": 720,
+        "height": 1334,
+        "rawWidth": 720,
+        "rawHeight": 1334,
+        "borderTop": 0,
+        "borderBottom": 0,
+        "borderLeft": 0,
+        "borderRight": 0,
+        "packable": true,
+        "pixelsToUnit": 100,
+        "pivotX": 0.5,
+        "pivotY": 0.5,
+        "meshType": 0,
+        "vertices": {
+          "rawPosition": [
+            -360,
+            -667,
+            0,
+            360,
+            -667,
+            0,
+            -360,
+            667,
+            0,
+            360,
+            667,
+            0
+          ],
+          "indexes": [
+            0,
+            1,
+            2,
+            2,
+            1,
+            3
+          ],
+          "uv": [
+            0,
+            1334,
+            720,
+            1334,
+            0,
+            0,
+            720,
+            0
+          ],
+          "nuv": [
+            0,
+            0,
+            1,
+            0,
+            0,
+            1,
+            1,
+            1
+          ],
+          "minPos": [
+            -360,
+            -667,
+            0
+          ],
+          "maxPos": [
+            360,
+            667,
+            0
+          ]
+        },
+        "isUuid": true,
+        "imageUuidOrDatabaseUri": "2aaa84b9-ecad-4390-b5b4-ed800d51a947@6c48a",
+        "atlasUuid": "",
+        "trimType": "auto"
+      },
+      "ver": "1.0.12",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    }
+  },
+  "userData": {
+    "type": "sprite-frame",
+    "hasAlpha": false,
+    "fixAlphaTransparencyArtifacts": false,
+    "redirect": "2aaa84b9-ecad-4390-b5b4-ed800d51a947@6c48a"
+  }
+}

BIN
assets/resources/images/SkillUIImages/1.png


+ 134 - 0
assets/resources/images/SkillUIImages/1.png.meta

@@ -0,0 +1,134 @@
+{
+  "ver": "1.0.27",
+  "importer": "image",
+  "imported": true,
+  "uuid": "553580b1-e94b-4d28-82fa-bfa70cff1178",
+  "files": [
+    ".json",
+    ".png"
+  ],
+  "subMetas": {
+    "6c48a": {
+      "importer": "texture",
+      "uuid": "553580b1-e94b-4d28-82fa-bfa70cff1178@6c48a",
+      "displayName": "1",
+      "id": "6c48a",
+      "name": "texture",
+      "userData": {
+        "wrapModeS": "clamp-to-edge",
+        "wrapModeT": "clamp-to-edge",
+        "imageUuidOrDatabaseUri": "553580b1-e94b-4d28-82fa-bfa70cff1178",
+        "isUuid": true,
+        "visible": false,
+        "minfilter": "linear",
+        "magfilter": "linear",
+        "mipfilter": "none",
+        "anisotropy": 0
+      },
+      "ver": "1.0.22",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    },
+    "f9941": {
+      "importer": "sprite-frame",
+      "uuid": "553580b1-e94b-4d28-82fa-bfa70cff1178@f9941",
+      "displayName": "1",
+      "id": "f9941",
+      "name": "spriteFrame",
+      "userData": {
+        "trimThreshold": 1,
+        "rotated": false,
+        "offsetX": 0,
+        "offsetY": 0,
+        "trimX": 0,
+        "trimY": 0,
+        "width": 215,
+        "height": 46,
+        "rawWidth": 215,
+        "rawHeight": 46,
+        "borderTop": 0,
+        "borderBottom": 0,
+        "borderLeft": 0,
+        "borderRight": 0,
+        "packable": true,
+        "pixelsToUnit": 100,
+        "pivotX": 0.5,
+        "pivotY": 0.5,
+        "meshType": 0,
+        "vertices": {
+          "rawPosition": [
+            -107.5,
+            -23,
+            0,
+            107.5,
+            -23,
+            0,
+            -107.5,
+            23,
+            0,
+            107.5,
+            23,
+            0
+          ],
+          "indexes": [
+            0,
+            1,
+            2,
+            2,
+            1,
+            3
+          ],
+          "uv": [
+            0,
+            46,
+            215,
+            46,
+            0,
+            0,
+            215,
+            0
+          ],
+          "nuv": [
+            0,
+            0,
+            1,
+            0,
+            0,
+            1,
+            1,
+            1
+          ],
+          "minPos": [
+            -107.5,
+            -23,
+            0
+          ],
+          "maxPos": [
+            107.5,
+            23,
+            0
+          ]
+        },
+        "isUuid": true,
+        "imageUuidOrDatabaseUri": "553580b1-e94b-4d28-82fa-bfa70cff1178@6c48a",
+        "atlasUuid": "",
+        "trimType": "auto"
+      },
+      "ver": "1.0.12",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    }
+  },
+  "userData": {
+    "type": "sprite-frame",
+    "hasAlpha": true,
+    "fixAlphaTransparencyArtifacts": false,
+    "redirect": "553580b1-e94b-4d28-82fa-bfa70cff1178@6c48a"
+  }
+}

BIN
assets/resources/images/SkillUIImages/2.png


+ 134 - 0
assets/resources/images/SkillUIImages/2.png.meta

@@ -0,0 +1,134 @@
+{
+  "ver": "1.0.27",
+  "importer": "image",
+  "imported": true,
+  "uuid": "18471d5a-34bc-455e-946c-0eaa51f30b3c",
+  "files": [
+    ".json",
+    ".png"
+  ],
+  "subMetas": {
+    "6c48a": {
+      "importer": "texture",
+      "uuid": "18471d5a-34bc-455e-946c-0eaa51f30b3c@6c48a",
+      "displayName": "2",
+      "id": "6c48a",
+      "name": "texture",
+      "userData": {
+        "wrapModeS": "clamp-to-edge",
+        "wrapModeT": "clamp-to-edge",
+        "imageUuidOrDatabaseUri": "18471d5a-34bc-455e-946c-0eaa51f30b3c",
+        "isUuid": true,
+        "visible": false,
+        "minfilter": "linear",
+        "magfilter": "linear",
+        "mipfilter": "none",
+        "anisotropy": 0
+      },
+      "ver": "1.0.22",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    },
+    "f9941": {
+      "importer": "sprite-frame",
+      "uuid": "18471d5a-34bc-455e-946c-0eaa51f30b3c@f9941",
+      "displayName": "2",
+      "id": "f9941",
+      "name": "spriteFrame",
+      "userData": {
+        "trimThreshold": 1,
+        "rotated": false,
+        "offsetX": 0,
+        "offsetY": 0,
+        "trimX": 0,
+        "trimY": 0,
+        "width": 663,
+        "height": 152,
+        "rawWidth": 663,
+        "rawHeight": 152,
+        "borderTop": 0,
+        "borderBottom": 0,
+        "borderLeft": 0,
+        "borderRight": 0,
+        "packable": true,
+        "pixelsToUnit": 100,
+        "pivotX": 0.5,
+        "pivotY": 0.5,
+        "meshType": 0,
+        "vertices": {
+          "rawPosition": [
+            -331.5,
+            -76,
+            0,
+            331.5,
+            -76,
+            0,
+            -331.5,
+            76,
+            0,
+            331.5,
+            76,
+            0
+          ],
+          "indexes": [
+            0,
+            1,
+            2,
+            2,
+            1,
+            3
+          ],
+          "uv": [
+            0,
+            152,
+            663,
+            152,
+            0,
+            0,
+            663,
+            0
+          ],
+          "nuv": [
+            0,
+            0,
+            1,
+            0,
+            0,
+            1,
+            1,
+            1
+          ],
+          "minPos": [
+            -331.5,
+            -76,
+            0
+          ],
+          "maxPos": [
+            331.5,
+            76,
+            0
+          ]
+        },
+        "isUuid": true,
+        "imageUuidOrDatabaseUri": "18471d5a-34bc-455e-946c-0eaa51f30b3c@6c48a",
+        "atlasUuid": "",
+        "trimType": "auto"
+      },
+      "ver": "1.0.12",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    }
+  },
+  "userData": {
+    "type": "sprite-frame",
+    "hasAlpha": true,
+    "fixAlphaTransparencyArtifacts": false,
+    "redirect": "18471d5a-34bc-455e-946c-0eaa51f30b3c@6c48a"
+  }
+}

+ 14 - 14
assets/scripts/Animations/GameStartMove.ts

@@ -42,8 +42,8 @@ export class GameStartMove extends Component {
     public dibanNode: Node = null;
 
     /** Gray遮罩节点 */
-    @property({ type: Node, tooltip: 'Canvas/GameLevelUI/Gray节点' })
-    public grayNode: Node = null;
+    // @property({ type: Node, tooltip: 'Canvas/GameLevelUI/Gray节点' })
+    // public grayNode: Node = null;
 
     /** 目标线节点,diban下滑结束后相机将移动到此线的位置 */
     @property({ 
@@ -117,9 +117,9 @@ export class GameStartMove extends Component {
             .call(() => {
                 console.log('GameStartMove.resetCameraToOriginalPosition 镜头重置完成');
                 // 隐藏Gray遮罩
-                if (this.grayNode) {
-                    this.grayNode.active = false;
-                }
+                // if (this.grayNode) {
+                //     this.grayNode.active = false;
+                // }
             })
             .start();
     }
@@ -143,9 +143,9 @@ export class GameStartMove extends Component {
         this.cameraNode.setPosition(this._originalPos.clone());
         
         // 隐藏Gray遮罩
-        if (this.grayNode) {
-            this.grayNode.active = false;
-        }
+        // if (this.grayNode) {
+        //     this.grayNode.active = false;
+        // }
         
         console.log('GameStartMove.resetCameraToOriginalPositionImmediate 镜头立即重置完成');
     }
@@ -183,9 +183,9 @@ export class GameStartMove extends Component {
             .call(() => {
                 console.log('GameStartMove.moveDownSmooth 镜头平滑下移完成');
                 // 镜头下移完成时显示Gray遮罩
-                if (this.grayNode) {
-                    this.grayNode.active = true;
-                }
+                // if (this.grayNode) {
+                //     this.grayNode.active = true;
+                // }
             })
             .start();
     }
@@ -429,9 +429,9 @@ export class GameStartMove extends Component {
             .call(() => {
                 console.log('GameStartMove.slideDibanDownAndHide diban下滑动画完成');
                 // 动画完成时隐藏Gray遮罩
-                if (this.grayNode) {
-                    this.grayNode.active = false;
-                }
+                // if (this.grayNode) {
+                //     this.grayNode.active = false;
+                // }
                 // 动画完成后隐藏diban节点
                 this.dibanNode.active = false;
                 // 动画完成后发送进入战斗状态事件,恢复游戏

+ 101 - 0
assets/scripts/Animations/PelletTrailController.ts

@@ -0,0 +1,101 @@
+import { _decorator, Component, Node, ParticleSystem2D, Vec2, RigidBody2D } from 'cc';
+const { ccclass, property } = _decorator;
+
+/**
+ * 子弹尾迹控制器
+ * 控制子弹的粒子系统尾迹效果
+ */
+@ccclass('PelletTrailController')
+export class PelletTrailController extends Component {
+    @property(ParticleSystem2D)
+    particleSystem: ParticleSystem2D = null;
+    
+    @property(RigidBody2D)
+    rigidBody: RigidBody2D = null;
+    
+    private lastVelocity: Vec2 = new Vec2();
+    
+    onLoad() {
+        // 自动获取组件引用
+        if (!this.particleSystem) {
+            this.particleSystem = this.node.getComponentInChildren(ParticleSystem2D);
+        }
+        if (!this.rigidBody) {
+            this.rigidBody = this.node.getComponent(RigidBody2D);
+        }
+    }
+    
+    start() {
+        // 启动粒子系统
+        if (this.particleSystem) {
+            this.particleSystem.resetSystem();
+        }
+    }
+    
+    update(deltaTime: number) {
+        if (!this.particleSystem || !this.rigidBody) return;
+        
+        // 获取当前速度
+        const velocity = this.rigidBody.linearVelocity;
+        
+        // 如果速度发生变化,更新粒子发射角度
+        if (!velocity.equals(this.lastVelocity)) {
+            this.updateParticleDirection(velocity);
+            this.lastVelocity.set(velocity);
+        }
+        
+        // 根据速度调整粒子发射率
+        const speed = velocity.length();
+        if (speed > 0) {
+            // 速度越快,尾迹越明显
+            this.particleSystem.emissionRate = Math.max(20, speed * 0.5);
+            this.particleSystem.enabled = true;
+        } else {
+            // 静止时停止发射粒子
+            this.particleSystem.enabled = false;
+        }
+    }
+    
+    /**
+     * 根据子弹移动方向更新粒子发射方向
+     * @param velocity 子弹速度向量
+     */
+    private updateParticleDirection(velocity: Vec2) {
+        if (velocity.length() === 0) return;
+        
+        // 计算速度方向角度(弧度转角度)
+        const angle = Math.atan2(velocity.y, velocity.x) * 180 / Math.PI;
+        
+        // 粒子向相反方向发射,形成尾迹效果
+        this.particleSystem.angle = angle + 180;
+        
+        // 根据速度调整粒子初始速度
+        const speed = velocity.length();
+        this.particleSystem.speed = Math.min(100, speed * 0.8);
+        this.particleSystem.speedVar = Math.min(30, speed * 0.2);
+    }
+    
+    /**
+     * 设置尾迹颜色
+     * @param color 颜色值 (0-255)
+     */
+    public setTrailColor(r: number, g: number, b: number, a: number = 255) {
+        if (!this.particleSystem) return;
+        
+        this.particleSystem.startColor.set(r, g, b, a);
+        // 结束颜色保持透明
+        this.particleSystem.endColor.set(r, g, b, 0);
+    }
+    
+    /**
+     * 启用/禁用尾迹效果
+     */
+    public setTrailEnabled(enabled: boolean) {
+        if (this.particleSystem) {
+            this.particleSystem.enabled = enabled;
+            if (enabled) {
+                this.particleSystem.resetSystem();
+            }
+        }
+    }
+}

+ 9 - 0
assets/scripts/Animations/PelletTrailController.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "ff3eeb3e-7555-42ed-b405-813f8285229e",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 24 - 15
assets/scripts/CombatSystem/WeaponBullet.ts

@@ -7,6 +7,7 @@ import { ConfigManager, WeaponConfig, BulletCountConfig, BulletTrajectoryConfig,
 import  EventBus,{ GameEvents } from '../Core/EventBus';
 import { PersistentSkillManager } from '../FourUI/SkillSystem/PersistentSkillManager';
 import { SaveDataManager } from '../LevelSystem/SaveDataManager';
+import { PelletTrailController } from '../Animations/PelletTrailController';
 
 const { ccclass, property } = _decorator;
 
@@ -42,6 +43,7 @@ export class WeaponBullet extends Component {
     private bulletTrajectory: BulletTrajectory = null;
     private bulletHitEffect: BulletHitEffect = null;
     private bulletLifecycle: BulletLifecycle = null;
+    private pelletTrailController: PelletTrailController = null;
     
     // 武器配置和状态
     private weaponConfig: WeaponConfig = null;
@@ -304,6 +306,12 @@ export class WeaponBullet extends Component {
         this.bulletLifecycle = this.getComponent(BulletLifecycle) || this.addComponent(BulletLifecycle);
         this.bulletLifecycle.init(config.lifecycle, initData.firePosition);
         
+        // 初始化尾迹控制器
+        this.pelletTrailController = this.getComponent(PelletTrailController) || this.addComponent(PelletTrailController);
+        // 设置白色尾迹
+        this.pelletTrailController.setTrailColor(255, 255, 255, 255);
+        this.pelletTrailController.setTrailEnabled(true);
+        
         // 设置碰撞监听
         this.setupCollisionListener();
         
@@ -566,22 +574,23 @@ export class WeaponBullet extends Component {
                 spriteFrame && spriteFrame.isValid) {
                 sprite.spriteFrame = spriteFrame;
 
-                // === 缩小至原始尺寸的 0.5 倍 ===
-                const uiTransform = sprite.node.getComponent(UITransform);
-                if (uiTransform) {
-                    const originalSize = spriteFrame.originalSize || null;
-                    if (originalSize) {
-                        uiTransform.setContentSize(originalSize.width * 0.5, originalSize.height * 0.5);
-                    } else {
-                        // 若无法获取原尺寸,退化为缩放节点
-                        sprite.node.setScale(sprite.node.scale.x * 0.5, sprite.node.scale.y * 0.5, sprite.node.scale.z);
-                    }
-                } else {
-                    // 没有 UITransform,直接缩放节点
-                    sprite.node.setScale(sprite.node.scale.x * 0.5, sprite.node.scale.y * 0.5, sprite.node.scale.z);
-                }
+                // // === 子弹大小1比1 ===
+                // const uiTransform = sprite.node.getComponent(UITransform);
+                // if (uiTransform) {
+                //     const originalSize = spriteFrame.originalSize || null;
+                //     if (originalSize) {
+                //         uiTransform.setContentSize(originalSize.width * 0.5, originalSize.height * 0.5);
+                //     } else {
+                //         // 若无法获取原尺寸,退化为缩放节点
+                //         sprite.node.setScale(sprite.node.scale.x * 0.5, sprite.node.scale.y * 0.5, sprite.node.scale.z);
+                //     }
+                // } else {
+                //     // 没有 UITransform,直接缩放节点
+                //     sprite.node.setScale(sprite.node.scale.x * 0.5, sprite.node.scale.y * 0.5, sprite.node.scale.z);
+                // }
             }
-        });
+        }
+    );
     }
     
     /**

+ 175 - 0
assets/scripts/LevelSystem/BackgroundManager.ts

@@ -0,0 +1,175 @@
+import { _decorator, Component, Node, Sprite, SpriteFrame, resources, find, assetManager } from 'cc';
+import { LevelConfigManager } from './LevelConfigManager';
+import { SaveDataManager } from './SaveDataManager';
+import EventBus, { GameEvents } from '../Core/EventBus';
+
+const { ccclass, property } = _decorator;
+
+/**
+ * 背景管理器 - 负责根据关卡配置动态设置游戏背景
+ */
+@ccclass('BackgroundManager')
+export class BackgroundManager extends Component {
+    @property(Node)
+    backgroundNode: Node = null; // Canvas/GameLevelUI/Background节点
+
+    private backgroundSprite: Sprite = null;
+    private levelConfigManager: LevelConfigManager = null;
+    private saveDataManager: SaveDataManager = null;
+
+    onLoad() {
+        // 获取关卡配置管理器
+        this.levelConfigManager = LevelConfigManager.getInstance();
+        // 获取SaveDataManager实例
+        this.saveDataManager = SaveDataManager.getInstance();
+        // 监听关卡开始事件
+        EventBus.getInstance().on(GameEvents.GAME_START, this.onGameStart, this);
+    }
+
+    start() {
+        this.initBackgroundSprite();
+    }
+
+    /**
+     * 初始化背景Sprite组件
+     */
+    private initBackgroundSprite() {
+        // 如果编辑器中没有设置backgroundNode,尝试自动查找
+        if (!this.backgroundNode) {
+            this.backgroundNode = find('Canvas/GameLevelUI/Background');
+            if (!this.backgroundNode) {
+                console.warn('[BackgroundManager] 未找到Canvas/GameLevelUI/Background节点,请检查节点路径');
+                return;
+            }
+        }
+
+        // 获取Sprite组件
+        this.backgroundSprite = this.backgroundNode.getComponent(Sprite);
+        if (!this.backgroundSprite) {
+            console.warn('[BackgroundManager] 背景节点上未找到Sprite组件,请为节点添加Sprite组件');
+        } else {
+            console.log('[BackgroundManager] 背景Sprite组件初始化成功');
+        }
+    }
+
+
+
+    onDestroy() {
+        // 移除事件监听
+        EventBus.getInstance().off(GameEvents.GAME_START, this.onGameStart, this);
+    }
+
+    /**
+     * 游戏开始时设置背景
+     */
+    private async onGameStart() {
+        await this.setBackgroundForCurrentLevel();
+    }
+
+    /**
+     * 根据当前关卡设置背景图片
+     */
+    public async setBackgroundForCurrentLevel() {
+        if (!this.levelConfigManager || !this.saveDataManager) {
+            console.warn('[BackgroundManager] LevelConfigManager或SaveDataManager未初始化');
+            return;
+        }
+
+        const currentLevel = this.saveDataManager.getCurrentLevel();
+        const levelConfig = await this.levelConfigManager.getLevelConfig(currentLevel);
+        
+        console.log(`[BackgroundManager] 当前关卡: ${currentLevel}`);
+        console.log(`[BackgroundManager] 关卡配置:`, levelConfig);
+        
+        if (levelConfig && levelConfig.backgroundImage) {
+            console.log(`[BackgroundManager] 关卡${currentLevel}配置的背景图片: ${levelConfig.backgroundImage}`);
+            this.setBackground(levelConfig.backgroundImage);
+        } else {
+            // 使用默认背景
+            this.setBackground('images/LevelBackground/BG1');
+            console.log(`[BackgroundManager] 关卡${currentLevel}未配置背景图片,使用默认背景`);
+            if (levelConfig) {
+                console.log(`[BackgroundManager] 关卡配置中backgroundImage字段值:`, levelConfig.backgroundImage);
+            }
+        }
+    }
+
+    /**
+     * 设置背景图片
+     * @param imagePath 图片路径(相对于resources目录)
+     */
+    public setBackground(imagePath: string) {
+        if (!this.backgroundSprite) {
+            console.warn('[BackgroundManager] 背景Sprite组件未找到,无法设置背景');
+            return;
+        }
+
+        console.log(`[BackgroundManager] 开始加载背景图片: ${imagePath}`);
+        
+        // 确保resources bundle已加载
+        const resourcesBundle = assetManager.getBundle('resources');
+        if (!resourcesBundle) {
+            console.warn('[BackgroundManager] resources bundle未找到,尝试加载...');
+            assetManager.loadBundle('resources', (err, bundle) => {
+                if (err) {
+                    console.error('[BackgroundManager] 加载resources bundle失败:', err);
+                    return;
+                }
+                this.loadBackgroundImage(bundle, imagePath);
+            });
+        } else {
+            this.loadBackgroundImage(resourcesBundle, imagePath);
+        }
+    }
+
+    /**
+     * 加载背景图片
+     */
+    private loadBackgroundImage(bundle: any, imagePath: string) {
+        // 正确的SpriteFrame子资源路径
+        const spriteFramePath = `${imagePath}/spriteFrame`;
+        
+        bundle.load(spriteFramePath, SpriteFrame, (err: any, spriteFrame: SpriteFrame) => {
+            if (!err && spriteFrame && this.backgroundSprite && this.backgroundSprite.isValid) {
+                this.backgroundSprite.spriteFrame = spriteFrame;
+                console.log(`[BackgroundManager] 背景图片加载成功: ${imagePath}`);
+            } else if (err) {
+                console.warn(`[BackgroundManager] 背景图片加载失败: ${spriteFramePath}`, err);
+                // 尝试使用resources.load作为备用方案
+                resources.load(spriteFramePath, SpriteFrame, (fallbackErr, fallbackSpriteFrame) => {
+                    if (!fallbackErr && fallbackSpriteFrame && this.backgroundSprite && this.backgroundSprite.isValid) {
+                        this.backgroundSprite.spriteFrame = fallbackSpriteFrame;
+                        console.log(`[BackgroundManager] 使用备用方案加载背景成功: ${imagePath}`);
+                    } else {
+                        // 尝试加载默认背景
+                        if (imagePath !== 'images/LevelBackground/BG1') {
+                            console.log('[BackgroundManager] 尝试加载默认背景');
+                            this.setBackground('images/LevelBackground/BG1');
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+    /**
+     * 根据指定关卡设置背景图片
+     * @param levelId 关卡ID
+     */
+    public async setBackgroundForLevel(levelId: number) {
+        if (!this.levelConfigManager) {
+            console.warn('[BackgroundManager] LevelConfigManager未初始化');
+            return;
+        }
+
+        const levelConfig = await this.levelConfigManager.getLevelConfig(levelId);
+        
+        if (levelConfig && levelConfig.backgroundImage) {
+            this.setBackground(levelConfig.backgroundImage);
+        } else {
+            // 使用默认背景
+            this.setBackground('images/LevelBackground/BG1');
+            console.log(`[BackgroundManager] 关卡${levelId}未配置背景图片,使用默认背景`);
+        }
+    }
+}

+ 9 - 0
assets/scripts/LevelSystem/BackgroundManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "29573f9b-6992-4509-acd5-55924c79e722",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 60 - 0
assets/scripts/LevelSystem/BackgroundUsageExample.md

@@ -0,0 +1,60 @@
+# 背景管理器使用说明
+
+## 概述
+`BackgroundManager` 组件用于动态设置游戏关卡的背景图片。它可以根据关卡配置自动加载不同的背景图片到 `Canvas/GameLevelUI/Background` 节点。
+
+## 设置步骤
+
+### 1. 在场景中添加 BackgroundManager 组件
+1. 在 Cocos Creator 编辑器中打开 `GameLevel.scene`
+2. 创建一个新的空节点,命名为 `BackgroundManager`
+3. 为该节点添加 `BackgroundManager` 组件
+4. 在 `BackgroundManager` 组件的属性面板中,将 `Canvas/GameLevelUI/Background` 节点拖拽到 `backgroundNode` 属性
+
+### 2. 在 InGameManager 中配置
+1. 在 `InGameManager` 组件的属性面板中,将 `BackgroundManager` 节点拖拽到 `backgroundManagerNode` 属性
+
+### 3. 关卡配置
+在关卡配置文件中添加 `backgroundImage` 字段:
+
+```typescript
+const levelConfig = {
+    levelId: 1,
+    levelName: "第一关",
+    backgroundImage: "images/LevelBackground/BG2", // 背景图片路径
+    // 其他配置...
+};
+```
+
+## 背景图片资源
+
+### 默认背景图片
+- `images/LevelBackground/BG1` - 默认背景
+- `images/LevelBackground/BG2` - 第二个背景
+- `images/LevelBackground/BG3` - 第三个背景
+
+### 添加新背景图片
+1. 将背景图片放置在 `assets/resources/images/LevelBackground/` 目录下
+2. 确保图片格式为 Cocos Creator 支持的格式(PNG、JPG等)
+3. 在关卡配置中使用相对路径引用,例如:`images/LevelBackground/NewBackground`
+
+## 工作原理
+
+1. **初始化**:`InGameManager` 在 `start()` 方法中初始化 `BackgroundManager` 组件
+2. **配置应用**:当调用 `applyLevelConfig()` 方法时,会检查关卡配置中的 `backgroundImage` 字段
+3. **背景加载**:`BackgroundManager` 使用 `resources.load()` 动态加载指定的背景图片
+4. **背景设置**:将加载的 `SpriteFrame` 应用到 `Canvas/GameLevelUI/Background` 节点的 `Sprite` 组件
+
+## 错误处理
+
+- 如果指定的背景图片加载失败,会在控制台输出错误信息
+- 如果没有配置 `backgroundImage`,会自动使用默认背景 `images/LevelBackground/BG1`
+- 如果 `BackgroundManager` 组件未正确配置,会在控制台输出警告信息
+
+## 调试信息
+
+在游戏运行时,可以在控制台查看以下日志信息:
+- `[BackgroundManager] 背景管理器初始化成功`
+- `[BackgroundManager] 设置背景: {backgroundPath}`
+- `[BackgroundManager] 背景加载成功: {backgroundPath}`
+- `[InGameManager] 应用背景配置: {backgroundImage}`

+ 11 - 0
assets/scripts/LevelSystem/BackgroundUsageExample.md.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "1.0.1",
+  "importer": "text",
+  "imported": true,
+  "uuid": "6e6a97d3-ce38-47d2-8c14-1e27d469b6bb",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {}
+}

+ 33 - 0
assets/scripts/LevelSystem/IN_game.ts

@@ -7,6 +7,7 @@ import { LevelSessionManager } from '../Core/LevelSessionManager';
 import { SaveDataManager } from './SaveDataManager';
 import { SkillManager } from '../CombatSystem/SkillSelection/SkillManager';
 import { StartGame } from './StartGame';
+import { BackgroundManager } from './BackgroundManager';
 
 const { ccclass, property } = _decorator;
 
@@ -98,6 +99,9 @@ export class InGameManager extends Component {
     private levelTotalEnemies: number = 0;
     private enemiesKilled: number = 0;
     
+    // === 背景管理器组件 ===
+    private backgroundManager: BackgroundManager = null;
+    
     // 游戏计时器
     private gameStartTime: number = 0;
     private gameEndTime: number = 0;
@@ -132,6 +136,13 @@ export class InGameManager extends Component {
     })
     public selectSkillUINode: Node = null;
 
+    // === 背景管理器 ===
+    @property({
+        type: Node,
+        tooltip: '拖拽BackgroundManager节点到这里'
+    })
+    public backgroundManagerNode: Node = null;
+
     // GameBlockSelection组件
     private blockSelectionComponent: GameBlockSelection = null;
 
@@ -590,6 +601,18 @@ export class InGameManager extends Component {
         } else {
             console.error('[InGameManager] 技能选择UI节点未通过装饰器挂载,请在Inspector中拖拽SelectSkillUI节点');
         }
+        
+        // 初始化背景管理器
+        if (this.backgroundManagerNode) {
+            this.backgroundManager = this.backgroundManagerNode.getComponent(BackgroundManager);
+            if (this.backgroundManager) {
+                console.log('[InGameManager] 背景管理器组件初始化成功');
+            } else {
+                console.error('[InGameManager] 背景管理器节点存在但BackgroundManager组件未找到');
+            }
+        } else {
+            console.error('[InGameManager] 背景管理器节点未通过装饰器挂载,请在Inspector中拖拽BackgroundManager节点');
+        }
     }
     
     /**
@@ -1039,6 +1062,16 @@ export class InGameManager extends Component {
             // 通过事件系统调用setCurrentWave
             this.setCurrentWave(1, firstWaveEnemies);
         }
+        
+        // 应用背景图片配置
+        if (this.backgroundManager && levelConfig.backgroundImage) {
+            this.backgroundManager.setBackground(levelConfig.backgroundImage);
+            console.log(`[InGameManager] 应用背景配置: ${levelConfig.backgroundImage}`);
+        } else if (this.backgroundManager) {
+            // 如果没有指定背景图片,使用默认背景
+            this.backgroundManager.setBackground('images/LevelBackground/BG1');
+            console.log('[InGameManager] 使用默认背景: images/LevelBackground/BG1');
+        }
     }
     
 

+ 4 - 0
assets/scripts/LevelSystem/LevelConfigManager.ts

@@ -9,6 +9,7 @@ interface LevelConfig {
     name: string;
     scene: string;
     description?: string;
+    backgroundImage?: string; // 背景图片路径
     weapons: string[];
     waves: WaveConfig[];
     levelSettings?: {
@@ -190,6 +191,7 @@ export class LevelConfigManager extends Component {
                 name: jsonData.name,
                 scene: jsonData.scene,
                 description: jsonData.description,
+                backgroundImage: jsonData.backgroundImage, // 添加背景图片字段
                 weapons: weapons,
                 waves: [],
                 levelSettings: {
@@ -281,6 +283,7 @@ export class LevelConfigManager extends Component {
             1: {
                 name: '新手引导(草地平原)',
                 scene: 'grassland',
+                backgroundImage: 'images/LevelBackground/BG1',
                 weapons: ['毛豆射手', '尖胡萝卜'],
                 waves: [
                     {
@@ -306,6 +309,7 @@ export class LevelConfigManager extends Component {
             2: {
                 name: '丛林探险(森林场景)',
                 scene: 'forest',
+                backgroundImage: 'images/LevelBackground/BG2',
                 weapons: ['锯齿草', '西瓜炸弹', '毛豆射手'],
                 waves: [
                     {

+ 80 - 0
assets/scripts/TestScene/TestPelletTrail.ts

@@ -0,0 +1,80 @@
+import { _decorator, Component, Node, Vec3, find, instantiate, Prefab, resources } from 'cc';
+import { WeaponBullet, BulletInitData } from '../CombatSystem/WeaponBullet';
+
+const { ccclass, property } = _decorator;
+
+/**
+ * 测试子弹尾迹效果的脚本
+ */
+@ccclass('TestPelletTrail')
+export class TestPelletTrail extends Component {
+    
+    @property(Prefab)
+    pelletPrefab: Prefab = null;
+    
+    private testInterval: number = 2; // 每2秒发射一次测试子弹
+    private timer: number = 0;
+    
+    start() {
+        // 如果没有设置预制体,尝试从resources加载
+        if (!this.pelletPrefab) {
+            this.loadPelletPrefab();
+        }
+    }
+    
+    update(deltaTime: number) {
+        this.timer += deltaTime;
+        
+        if (this.timer >= this.testInterval && this.pelletPrefab) {
+            this.timer = 0;
+            this.fireTestBullet();
+        }
+    }
+    
+    private loadPelletPrefab() {
+        resources.load('prefabs/Pellet', Prefab, (err, prefab) => {
+            if (!err && prefab) {
+                this.pelletPrefab = prefab;
+                console.log('[TestPelletTrail] Pellet预制体加载成功');
+            } else {
+                console.warn('[TestPelletTrail] 无法加载Pellet预制体:', err);
+            }
+        });
+    }
+    
+    private fireTestBullet() {
+        if (!this.pelletPrefab) return;
+        
+        // 创建测试子弹初始化数据
+        const initData: BulletInitData = {
+            weaponId: 'pea_shooter', // 使用默认武器配置
+            firePosition: new Vec3(0, 0, 0), // 从屏幕中心发射
+            direction: new Vec3(1, 0.5, 0).normalize(), // 向右上方发射
+            autoTarget: false
+        };
+        
+        // 创建子弹实例
+        const bulletNode = instantiate(this.pelletPrefab);
+        
+        // 添加到场景中
+        const gameArea = find('Canvas/GameLevelUI/GameArea') || find('Canvas');
+        if (gameArea) {
+            gameArea.addChild(bulletNode);
+        } else {
+            this.node.addChild(bulletNode);
+        }
+        
+        // 初始化子弹
+        const weaponBullet = bulletNode.getComponent(WeaponBullet) || bulletNode.addComponent(WeaponBullet);
+        weaponBullet.init(initData);
+        
+        console.log('[TestPelletTrail] 发射测试子弹,带白色尾迹效果');
+    }
+    
+    /**
+     * 手动触发测试子弹发射(可在编辑器中调用)
+     */
+    public fireTestBulletManual() {
+        this.fireTestBullet();
+    }
+}

+ 9 - 0
assets/scripts/TestScene/TestPelletTrail.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "02abff67-f7bd-4edb-940c-ffbfd1b0ce5a",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików