diff --git a/DungeonShooting_Godot/excel/excelFile/ActivityObject.xlsx b/DungeonShooting_Godot/excel/excelFile/ActivityObject.xlsx
index 8c505f0..d929d56 100644
--- a/DungeonShooting_Godot/excel/excelFile/ActivityObject.xlsx
+++ b/DungeonShooting_Godot/excel/excelFile/ActivityObject.xlsx
Binary files differ
diff --git a/DungeonShooting_Godot/excel/excelFile/Sound.xlsx b/DungeonShooting_Godot/excel/excelFile/Sound.xlsx
index 11ed22b..f8dd720 100644
--- a/DungeonShooting_Godot/excel/excelFile/Sound.xlsx
+++ b/DungeonShooting_Godot/excel/excelFile/Sound.xlsx
Binary files differ
diff --git a/DungeonShooting_Godot/excel/excelFile/Weapon.xlsx b/DungeonShooting_Godot/excel/excelFile/Weapon.xlsx
index b7e8df3..dd5760f 100644
--- a/DungeonShooting_Godot/excel/excelFile/Weapon.xlsx
+++ b/DungeonShooting_Godot/excel/excelFile/Weapon.xlsx
Binary files differ
diff --git a/DungeonShooting_Godot/prefab/prop/buff/Prop0001.tscn b/DungeonShooting_Godot/prefab/prop/buff/Prop0001.tscn
new file mode 100644
index 0000000..d1a1f24
--- /dev/null
+++ b/DungeonShooting_Godot/prefab/prop/buff/Prop0001.tscn
@@ -0,0 +1,40 @@
+[gd_scene load_steps=7 format=3 uid="uid://cb4k0wmt3rhjc"]
+
+[ext_resource type="Script" path="res://src/game/activity/prop/buff/MoveSpeedBuff.cs" id="1_haxff"]
+[ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="2_ao13f"]
+[ext_resource type="SpriteFrames" uid="uid://wtvfyprel72y" path="res://resource/spriteFrames/Buff0001.tres" id="3_jv1el"]
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_mrkt4"]
+resource_local_to_scene = true
+shader = ExtResource("2_ao13f")
+shader_parameter/blend = Color(0, 0, 0, 0.470588)
+shader_parameter/schedule = 0.0
+shader_parameter/alpha = 0.0
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_b6ii6"]
+resource_local_to_scene = true
+shader = ExtResource("2_ao13f")
+shader_parameter/blend = Color(1, 1, 1, 1)
+shader_parameter/schedule = 0.0
+shader_parameter/alpha = 1.0
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_cpqup"]
+size = Vector2(12, 10)
+
+[node name="Prop0001" type="CharacterBody2D" node_paths=PackedStringArray("ShadowSprite", "AnimatedSprite", "Collision")]
+collision_layer = 4
+script = ExtResource("1_haxff")
+ShadowSprite = NodePath("ShadowSprite")
+AnimatedSprite = NodePath("AnimatedSprite")
+Collision = NodePath("Collision")
+
+[node name="ShadowSprite" type="Sprite2D" parent="."]
+z_index = -1
+material = SubResource("ShaderMaterial_mrkt4")
+
+[node name="AnimatedSprite" type="AnimatedSprite2D" parent="."]
+material = SubResource("ShaderMaterial_b6ii6")
+sprite_frames = ExtResource("3_jv1el")
+
+[node name="Collision" type="CollisionShape2D" parent="."]
+shape = SubResource("RectangleShape2D_cpqup")
diff --git a/DungeonShooting_Godot/prefab/role/Enemy0001.tscn b/DungeonShooting_Godot/prefab/role/Enemy0001.tscn
index 8673633..d0e2f25 100644
--- a/DungeonShooting_Godot/prefab/role/Enemy0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/Enemy0001.tscn
@@ -1,7 +1,7 @@
 [gd_scene load_steps=7 format=3 uid="uid://dbrig6dq441wo"]
 
 [ext_resource type="PackedScene" uid="uid://cyrcv2jdgr8cf" path="res://prefab/role/RoleTemplate.tscn" id="1_5po38"]
-[ext_resource type="Script" path="res://src/game/role/enemy/Enemy.cs" id="2_1plrq"]
+[ext_resource type="Script" path="res://src/game/activity/role/enemy/Enemy.cs" id="2_1plrq"]
 [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="3_x8agd"]
 [ext_resource type="SpriteFrames" uid="uid://cnctpyrn02rhd" path="res://resource/spriteFrames/Role1001.tres" id="4_qv8w5"]
 
diff --git a/DungeonShooting_Godot/prefab/role/Role0001.tscn b/DungeonShooting_Godot/prefab/role/Role0001.tscn
index 4717b1d..0ecb088 100644
--- a/DungeonShooting_Godot/prefab/role/Role0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/Role0001.tscn
@@ -1,7 +1,7 @@
 [gd_scene load_steps=7 format=3 uid="uid://cxhrcytrx0kcf"]
 
 [ext_resource type="PackedScene" uid="uid://cyrcv2jdgr8cf" path="res://prefab/role/RoleTemplate.tscn" id="1_10c2n"]
-[ext_resource type="Script" path="res://src/game/role/Player.cs" id="2_7dmp4"]
+[ext_resource type="Script" path="res://src/game/activity/role/Player.cs" id="2_i08u4"]
 [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="3_rk4gg"]
 [ext_resource type="SpriteFrames" uid="uid://n11thtali6es" path="res://resource/spriteFrames/Role0001.tres" id="4_galcc"]
 
@@ -21,7 +21,7 @@
 
 [node name="Role0001" node_paths=PackedStringArray("HurtArea", "MountPoint", "BackMountPoint", "InteractiveArea", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_10c2n")]
 collision_layer = 8
-script = ExtResource("2_7dmp4")
+script = ExtResource("2_i08u4")
 HurtArea = NodePath("HurtArea")
 MountPoint = NodePath("MountPoint")
 BackMountPoint = NodePath("BackMountPoint")
@@ -37,3 +37,5 @@
 material = SubResource("ShaderMaterial_8hgu2")
 sprite_frames = ExtResource("4_galcc")
 frame_progress = 0.0995217
+
+[node name="MountPoint2" type="Marker2D" parent="." index="7"]
diff --git a/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn b/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn
index 31c3ab7..e665ff2 100644
--- a/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn
+++ b/DungeonShooting_Godot/prefab/role/RoleTemplate.tscn
@@ -1,7 +1,8 @@
 [gd_scene load_steps=8 format=3 uid="uid://cyrcv2jdgr8cf"]
 
 [ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="1_xk5yk"]
-[ext_resource type="Script" path="res://src/game/role/MountRotation.cs" id="2_5ddpw"]
+[ext_resource type="Script" path="res://src/game/activity/role/MountRotation.cs" id="2_5ddpw"]
+
 
 [sub_resource type="ShaderMaterial" id="ShaderMaterial_v2kfw"]
 resource_local_to_scene = true
diff --git a/DungeonShooting_Godot/project.godot b/DungeonShooting_Godot/project.godot
index 3e12ec5..20e8ef6 100644
--- a/DungeonShooting_Godot/project.godot
+++ b/DungeonShooting_Godot/project.godot
@@ -177,7 +177,7 @@
 
 2d_physics/layer_1="wall"
 2d_physics/layer_2="bullet"
-2d_physics/layer_3="props"
+2d_physics/layer_3="prop"
 2d_physics/layer_4="player"
 2d_physics/layer_5="enemy"
 2d_physics/layer_6="affiliation"
diff --git a/DungeonShooting_Godot/resource/config/ActivityObject.json b/DungeonShooting_Godot/resource/config/ActivityObject.json
index 8551ca6..69732fb 100644
--- a/DungeonShooting_Godot/resource/config/ActivityObject.json
+++ b/DungeonShooting_Godot/resource/config/ActivityObject.json
@@ -3,108 +3,152 @@
     "Id": "role0001",
     "Type": 3,
     "Prefab": "res://prefab/role/Role0001.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": "\u73A9\u5BB6"
   },
   {
     "Id": "enemy0001",
     "Type": 4,
     "Prefab": "res://prefab/role/Enemy0001.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": "\u654C\u4EBA"
   },
   {
     "Id": "weapon0001",
     "Type": 5,
     "Prefab": "res://prefab/weapon/Weapon0001.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "weapon0002",
     "Type": 5,
     "Prefab": "res://prefab/weapon/Weapon0002.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "weapon0003",
     "Type": 5,
     "Prefab": "res://prefab/weapon/Weapon0003.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "weapon0004",
     "Type": 5,
     "Prefab": "res://prefab/weapon/Weapon0004.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "weapon0005",
     "Type": 5,
     "Prefab": "res://prefab/weapon/Weapon0005.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "weapon0006",
     "Type": 5,
     "Prefab": "res://prefab/weapon/Weapon0006.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "bullet0001",
     "Type": 6,
     "Prefab": "res://prefab/bullet/Bullet0001.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "bullet0002",
     "Type": 6,
     "Prefab": "res://prefab/bullet/Bullet0002.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "shell0001",
     "Type": 7,
     "Prefab": "res://prefab/shell/Shell0001.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "shell0002",
     "Type": 7,
     "Prefab": "res://prefab/shell/Shell0002.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "shell0003",
     "Type": 7,
     "Prefab": "res://prefab/shell/Shell0003.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": ""
   },
   {
     "Id": "effect0001",
     "Type": 8,
     "Prefab": "res://prefab/effect/activityObject/Effect0001.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": "\u654C\u4EBA\u6B7B\u4EA1\u788E\u7247"
   },
   {
-    "Id": "other_door_e",
+    "Id": "prop0001",
     "Type": 9,
+    "Prefab": "res://prefab/prop/buff/Prop0001.tscn",
+    "ItemName": "\u978B\u5B50",
+    "ItemDescription": "\u589E\u52A0\u79FB\u52A8\u901F\u5EA6",
+    "Remark": "\u589E\u52A0\u79FB\u901F\u7684buff"
+  },
+  {
+    "Id": "other_door_e",
+    "Type": 99,
     "Prefab": "res://prefab/map/RoomDoor_E.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": "\u5730\u7262\u623F\u95F4\u7684\u95E8(\u4E1C\u4FA7)"
   },
   {
     "Id": "other_door_w",
-    "Type": 9,
+    "Type": 99,
     "Prefab": "res://prefab/map/RoomDoor_W.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": "\u5730\u7262\u623F\u95F4\u7684\u95E8(\u897F\u4FA7)"
   },
   {
     "Id": "other_door_s",
-    "Type": 9,
+    "Type": 99,
     "Prefab": "res://prefab/map/RoomDoor_S.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": "\u5730\u7262\u623F\u95F4\u7684\u95E8(\u5357\u4FA7)"
   },
   {
     "Id": "other_door_n",
-    "Type": 9,
+    "Type": 99,
     "Prefab": "res://prefab/map/RoomDoor_N.tscn",
+    "ItemName": "",
+    "ItemDescription": "",
     "Remark": "\u5730\u7262\u623F\u95F4\u7684\u95E8(\u5317\u4FA7)"
   }
 ]
\ No newline at end of file
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/testGroup/inlet/Room1.tscn b/DungeonShooting_Godot/resource/map/tileMaps/testGroup/inlet/Room1.tscn
index b971027..df5af1d 100644
--- a/DungeonShooting_Godot/resource/map/tileMaps/testGroup/inlet/Room1.tscn
+++ b/DungeonShooting_Godot/resource/map/tileMaps/testGroup/inlet/Room1.tscn
@@ -22,3 +22,10 @@
 Type = 5
 ItemExpression = "0003"
 WaveNumber = 2
+
+[node name="ActivityMark8" type="Node2D" parent="."]
+position = Vector2(126, 41)
+script = ExtResource("3_m4jrh")
+Type = 9
+ItemExpression = "0001"
+WaveNumber = 2
diff --git a/DungeonShooting_Godot/resource/map/tiledata/testGroup/inlet/Room1.json b/DungeonShooting_Godot/resource/map/tiledata/testGroup/inlet/Room1.json
index 952528a..6c3fba1 100644
--- a/DungeonShooting_Godot/resource/map/tiledata/testGroup/inlet/Room1.json
+++ b/DungeonShooting_Godot/resource/map/tiledata/testGroup/inlet/Room1.json
@@ -1,38 +1,38 @@
 {
   "Position": {
-	"X": -1,
-	"Y": -1
+    "X": -1,
+    "Y": -1
   },
   "Size": {
-	"X": 12,
-	"Y": 8
+    "X": 12,
+    "Y": 8
   },
   "DoorAreaInfos": [],
   "NavigationList": [
-	{
-	  "Type": 0,
-	  "Points": [
-		{
-		  "X": 8,
-		  "Y": 8
-		},
-		{
-		  "X": 152,
-		  "Y": 8
-		},
-		{
-		  "X": 152,
-		  "Y": 96
-		},
-		{
-		  "X": 8,
-		  "Y": 96
-		}
-	  ]
-	}
+    {
+      "Type": 0,
+      "Points": [
+        {
+          "X": 8,
+          "Y": 8
+        },
+        {
+          "X": 152,
+          "Y": 8
+        },
+        {
+          "X": 152,
+          "Y": 96
+        },
+        {
+          "X": 8,
+          "Y": 96
+        }
+      ]
+    }
   ],
   "GroupName": "testGroup",
   "RoomType": 1,
   "FileName": "Room1",
   "Weight": 100
-}
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/resource/sprite/prop/buff/Buff0001.png b/DungeonShooting_Godot/resource/sprite/prop/buff/Buff0001.png
new file mode 100644
index 0000000..61303db
--- /dev/null
+++ b/DungeonShooting_Godot/resource/sprite/prop/buff/Buff0001.png
Binary files differ
diff --git a/DungeonShooting_Godot/resource/sprite/prop/buff/Buff0001.png.import b/DungeonShooting_Godot/resource/sprite/prop/buff/Buff0001.png.import
new file mode 100644
index 0000000..93bddc7
--- /dev/null
+++ b/DungeonShooting_Godot/resource/sprite/prop/buff/Buff0001.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bls55gj8h3mgv"
+path="res://.godot/imported/Buff0001.png-2d51f6e8c41b1c1eaee342d36314d326.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://resource/sprite/prop/buff/Buff0001.png"
+dest_files=["res://.godot/imported/Buff0001.png-2d51f6e8c41b1c1eaee342d36314d326.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/DungeonShooting_Godot/resource/spriteFrames/Buff0001.tres b/DungeonShooting_Godot/resource/spriteFrames/Buff0001.tres
new file mode 100644
index 0000000..6a0ec5f
--- /dev/null
+++ b/DungeonShooting_Godot/resource/spriteFrames/Buff0001.tres
@@ -0,0 +1,14 @@
+[gd_resource type="SpriteFrames" load_steps=2 format=3 uid="uid://wtvfyprel72y"]
+
+[ext_resource type="Texture2D" uid="uid://bls55gj8h3mgv" path="res://resource/sprite/prop/buff/Buff0001.png" id="1_scm06"]
+
+[resource]
+animations = [{
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("1_scm06")
+}],
+"loop": true,
+"name": &"default",
+"speed": 5.0
+}]
diff --git a/DungeonShooting_Godot/src/config/ExcelConfig_ActivityObject.cs b/DungeonShooting_Godot/src/config/ExcelConfig_ActivityObject.cs
index 12e9730..4c2bcc5 100644
--- a/DungeonShooting_Godot/src/config/ExcelConfig_ActivityObject.cs
+++ b/DungeonShooting_Godot/src/config/ExcelConfig_ActivityObject.cs
@@ -22,7 +22,8 @@
         /// Bullet(子弹): 6 <br/>
         /// Shell(弹壳): 7 <br/>
         /// Effect(特效): 8 <br/>
-        /// Other(其它类型): 9
+        /// Prop(道具): 9 <br/>
+        /// Other(其它类型): 99
         /// </summary>
         [JsonInclude]
         public int Type;
@@ -34,6 +35,18 @@
         public string Prefab;
 
         /// <summary>
+        /// 物体名称
+        /// </summary>
+        [JsonInclude]
+        public string ItemName;
+
+        /// <summary>
+        /// 物体描述
+        /// </summary>
+        [JsonInclude]
+        public string ItemDescription;
+
+        /// <summary>
         /// 物体备注
         /// </summary>
         [JsonInclude]
@@ -48,6 +61,8 @@
             inst.Id = Id;
             inst.Type = Type;
             inst.Prefab = Prefab;
+            inst.ItemName = ItemName;
+            inst.ItemDescription = ItemDescription;
             inst.Remark = Remark;
             return inst;
         }
diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
index 920f5b4..a689872 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
@@ -2,6 +2,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using Config;
 using Godot;
 
 /// <summary>
@@ -17,9 +18,9 @@
     public static bool IsDebug { get; set; }
 
     /// <summary>
-    /// 当前物体类型id, 用于区分是否是同一种物体, 如果不是通过 ActivityObject.Create() 函数创建出来的对象那么 ItemId 为 null
+    /// 当前物体对应的配置数据, 如果不是通过 ActivityObject.Create() 函数创建出来的对象那么 ItemConfig 为 null
     /// </summary>
-    public string ItemId { get; private set; }
+    public ExcelConfig.ActivityObject ItemConfig { get; private set; }
 
     /// <summary>
     /// 是否是静态物体, 如果为true, 则会禁用移动处理
@@ -264,7 +265,7 @@
     private static long _instanceIndex = 0;
 
     //初始化节点
-    private void _InitNode(string itemId, World world)
+    private void _InitNode(RegisterActivityData activityData, World world)
     {
 #if TOOLS
         if (!Engine.IsEditorHint())
@@ -276,7 +277,7 @@
         }
 #endif
         World = world;
-        ItemId = itemId;
+        ItemConfig = activityData.Config;
         Name = GetType().Name + (_instanceIndex++);
         _blendShaderMaterial = AnimatedSprite.Material as ShaderMaterial;
         _shadowBlendShaderMaterial = ShadowSprite.Material as ShaderMaterial;
diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject_Init.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject_Init.cs
index 5e7e2a9..de9bda7 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityObject_Init.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject_Init.cs
@@ -1,3 +1,5 @@
+using Config;
+
 /// <summary>
 /// 根据配置表注册物体, 该类是自动生成的, 请不要手动编辑!
 /// </summary>
@@ -9,64 +11,121 @@
     public static class Ids
     {
         /// <summary>
-        /// 玩家
+        /// 名称:  <br/>
+        /// 备注: 玩家
         /// </summary>
         public const string Id_role0001 = "role0001";
         /// <summary>
-        /// 敌人
+        /// 名称:  <br/>
+        /// 备注: 敌人
         /// </summary>
         public const string Id_enemy0001 = "enemy0001";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_weapon0001 = "weapon0001";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_weapon0002 = "weapon0002";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_weapon0003 = "weapon0003";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_weapon0004 = "weapon0004";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_weapon0005 = "weapon0005";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_weapon0006 = "weapon0006";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_bullet0001 = "bullet0001";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_bullet0002 = "bullet0002";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_shell0001 = "shell0001";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_shell0002 = "shell0002";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 
+        /// </summary>
         public const string Id_shell0003 = "shell0003";
         /// <summary>
-        /// 敌人死亡碎片
+        /// 名称:  <br/>
+        /// 备注: 敌人死亡碎片
         /// </summary>
         public const string Id_effect0001 = "effect0001";
         /// <summary>
-        /// 地牢房间的门(东侧)
+        /// 名称: 鞋子 <br/>
+        /// 备注: 增加移速的buff
+        /// </summary>
+        public const string Id_prop0001 = "prop0001";
+        /// <summary>
+        /// 名称:  <br/>
+        /// 备注: 地牢房间的门(东侧)
         /// </summary>
         public const string Id_other_door_e = "other_door_e";
         /// <summary>
-        /// 地牢房间的门(西侧)
+        /// 名称:  <br/>
+        /// 备注: 地牢房间的门(西侧)
         /// </summary>
         public const string Id_other_door_w = "other_door_w";
         /// <summary>
-        /// 地牢房间的门(南侧)
+        /// 名称:  <br/>
+        /// 备注: 地牢房间的门(南侧)
         /// </summary>
         public const string Id_other_door_s = "other_door_s";
         /// <summary>
-        /// 地牢房间的门(北侧)
+        /// 名称:  <br/>
+        /// 备注: 地牢房间的门(北侧)
         /// </summary>
         public const string Id_other_door_n = "other_door_n";
     }
     private static void _InitRegister()
     {
-        _activityRegisterMap.Add("role0001", "res://prefab/role/Role0001.tscn");
-        _activityRegisterMap.Add("enemy0001", "res://prefab/role/Enemy0001.tscn");
-        _activityRegisterMap.Add("weapon0001", "res://prefab/weapon/Weapon0001.tscn");
-        _activityRegisterMap.Add("weapon0002", "res://prefab/weapon/Weapon0002.tscn");
-        _activityRegisterMap.Add("weapon0003", "res://prefab/weapon/Weapon0003.tscn");
-        _activityRegisterMap.Add("weapon0004", "res://prefab/weapon/Weapon0004.tscn");
-        _activityRegisterMap.Add("weapon0005", "res://prefab/weapon/Weapon0005.tscn");
-        _activityRegisterMap.Add("weapon0006", "res://prefab/weapon/Weapon0006.tscn");
-        _activityRegisterMap.Add("bullet0001", "res://prefab/bullet/Bullet0001.tscn");
-        _activityRegisterMap.Add("bullet0002", "res://prefab/bullet/Bullet0002.tscn");
-        _activityRegisterMap.Add("shell0001", "res://prefab/shell/Shell0001.tscn");
-        _activityRegisterMap.Add("shell0002", "res://prefab/shell/Shell0002.tscn");
-        _activityRegisterMap.Add("shell0003", "res://prefab/shell/Shell0003.tscn");
-        _activityRegisterMap.Add("effect0001", "res://prefab/effect/activityObject/Effect0001.tscn");
-        _activityRegisterMap.Add("other_door_e", "res://prefab/map/RoomDoor_E.tscn");
-        _activityRegisterMap.Add("other_door_w", "res://prefab/map/RoomDoor_W.tscn");
-        _activityRegisterMap.Add("other_door_s", "res://prefab/map/RoomDoor_S.tscn");
-        _activityRegisterMap.Add("other_door_n", "res://prefab/map/RoomDoor_N.tscn");
+        _activityRegisterMap.Add("role0001", new RegisterActivityData("res://prefab/role/Role0001.tscn", ExcelConfig.ActivityObject_Map["role0001"]));
+        _activityRegisterMap.Add("enemy0001", new RegisterActivityData("res://prefab/role/Enemy0001.tscn", ExcelConfig.ActivityObject_Map["enemy0001"]));
+        _activityRegisterMap.Add("weapon0001", new RegisterActivityData("res://prefab/weapon/Weapon0001.tscn", ExcelConfig.ActivityObject_Map["weapon0001"]));
+        _activityRegisterMap.Add("weapon0002", new RegisterActivityData("res://prefab/weapon/Weapon0002.tscn", ExcelConfig.ActivityObject_Map["weapon0002"]));
+        _activityRegisterMap.Add("weapon0003", new RegisterActivityData("res://prefab/weapon/Weapon0003.tscn", ExcelConfig.ActivityObject_Map["weapon0003"]));
+        _activityRegisterMap.Add("weapon0004", new RegisterActivityData("res://prefab/weapon/Weapon0004.tscn", ExcelConfig.ActivityObject_Map["weapon0004"]));
+        _activityRegisterMap.Add("weapon0005", new RegisterActivityData("res://prefab/weapon/Weapon0005.tscn", ExcelConfig.ActivityObject_Map["weapon0005"]));
+        _activityRegisterMap.Add("weapon0006", new RegisterActivityData("res://prefab/weapon/Weapon0006.tscn", ExcelConfig.ActivityObject_Map["weapon0006"]));
+        _activityRegisterMap.Add("bullet0001", new RegisterActivityData("res://prefab/bullet/Bullet0001.tscn", ExcelConfig.ActivityObject_Map["bullet0001"]));
+        _activityRegisterMap.Add("bullet0002", new RegisterActivityData("res://prefab/bullet/Bullet0002.tscn", ExcelConfig.ActivityObject_Map["bullet0002"]));
+        _activityRegisterMap.Add("shell0001", new RegisterActivityData("res://prefab/shell/Shell0001.tscn", ExcelConfig.ActivityObject_Map["shell0001"]));
+        _activityRegisterMap.Add("shell0002", new RegisterActivityData("res://prefab/shell/Shell0002.tscn", ExcelConfig.ActivityObject_Map["shell0002"]));
+        _activityRegisterMap.Add("shell0003", new RegisterActivityData("res://prefab/shell/Shell0003.tscn", ExcelConfig.ActivityObject_Map["shell0003"]));
+        _activityRegisterMap.Add("effect0001", new RegisterActivityData("res://prefab/effect/activityObject/Effect0001.tscn", ExcelConfig.ActivityObject_Map["effect0001"]));
+        _activityRegisterMap.Add("prop0001", new RegisterActivityData("res://prefab/prop/buff/Prop0001.tscn", ExcelConfig.ActivityObject_Map["prop0001"]));
+        _activityRegisterMap.Add("other_door_e", new RegisterActivityData("res://prefab/map/RoomDoor_E.tscn", ExcelConfig.ActivityObject_Map["other_door_e"]));
+        _activityRegisterMap.Add("other_door_w", new RegisterActivityData("res://prefab/map/RoomDoor_W.tscn", ExcelConfig.ActivityObject_Map["other_door_w"]));
+        _activityRegisterMap.Add("other_door_s", new RegisterActivityData("res://prefab/map/RoomDoor_S.tscn", ExcelConfig.ActivityObject_Map["other_door_s"]));
+        _activityRegisterMap.Add("other_door_n", new RegisterActivityData("res://prefab/map/RoomDoor_N.tscn", ExcelConfig.ActivityObject_Map["other_door_n"]));
     }
 }
diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject_Register.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject_Register.cs
index a08c0e6..9c82e49 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityObject_Register.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject_Register.cs
@@ -1,12 +1,25 @@
 
 using System;
 using System.Collections.Generic;
+using Config;
 using Godot;
 
 public partial class ActivityObject
 {
+    private class RegisterActivityData
+    {
+        public RegisterActivityData(string path, ExcelConfig.ActivityObject config)
+        {
+            Path = path;
+            Config = config;
+        }
+
+        public string Path;
+        public ExcelConfig.ActivityObject Config;
+    }
+    
     //负责存放所有注册对象数据
-    private static Dictionary<string, string> _activityRegisterMap = new Dictionary<string, string>();
+    private static Dictionary<string, RegisterActivityData> _activityRegisterMap = new Dictionary<string, RegisterActivityData>();
     private static bool _initState = false;
 
     /// <summary>
@@ -34,10 +47,10 @@
             throw new Exception("实例化 ActivityObject 前请先调用 'GameApplication.Instance.CreateNewWorld()' 初始化 World 对象");
         }
 
-        if (_activityRegisterMap.TryGetValue(itemId, out var path))
+        if (_activityRegisterMap.TryGetValue(itemId, out var config))
         {
-            var instance = ResourceManager.LoadAndInstantiate<ActivityObject>(path);
-            instance._InitNode(itemId, world);
+            var instance = ResourceManager.LoadAndInstantiate<ActivityObject>(config.Path);
+            instance._InitNode(config, world);
             return instance;
         }
         GD.PrintErr("创建实例失败, 未找到id为'" + itemId + "'的物体!");
diff --git a/DungeonShooting_Godot/src/framework/activity/CheckInteractiveResult.cs b/DungeonShooting_Godot/src/framework/activity/CheckInteractiveResult.cs
index eb8676b..c528baa 100644
--- a/DungeonShooting_Godot/src/framework/activity/CheckInteractiveResult.cs
+++ b/DungeonShooting_Godot/src/framework/activity/CheckInteractiveResult.cs
@@ -25,4 +25,18 @@
     {
         Target = target;
     }
+    
+    public CheckInteractiveResult(ActivityObject target, bool canInteractive)
+    {
+        Target = target;
+        CanInteractive = canInteractive;
+    }
+    
+    public CheckInteractiveResult(ActivityObject target, bool canInteractive, string message, string showIcon)
+    {
+        Target = target;
+        CanInteractive = canInteractive;
+        Message = message;
+        ShowIcon = showIcon;
+    }
 }
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs b/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs
index 26d9357..86f1516 100644
--- a/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs
+++ b/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs
@@ -43,18 +43,18 @@
         foreach (var item in array)
         {
             var id = item["Id"];
+            var name = item["ItemName"] + "";
             var remark = item["Remark"] + "";
-            if (!string.IsNullOrEmpty(remark))
-            {
-                code1 += $"        /// <summary>\n";
-                code1 += $"        /// {remark}\n";
-                code1 += $"        /// </summary>\n";
-            }
+            code1 += $"        /// <summary>\n";
+            code1 += $"        /// 名称: {name} <br/>\n";
+            code1 += $"        /// 备注: {remark.Replace("\n", " <br/>\n        /// ")}\n";
+            code1 += $"        /// </summary>\n";
             code1 += $"        public const string Id_{id} = \"{id}\";\n";
-            code2 += $"        _activityRegisterMap.Add(\"{id}\", \"{item["Prefab"]}\");\n";
+            code2 += $"        _activityRegisterMap.Add(\"{id}\", new RegisterActivityData(\"{item["Prefab"]}\", ExcelConfig.ActivityObject_Map[\"{id}\"]));\n";
         }
         
-        var str = $"/// <summary>\n";
+        var str = $"using Config;\n\n";
+        str += $"/// <summary>\n";
         str += $"/// 根据配置表注册物体, 该类是自动生成的, 请不要手动编辑!\n";
         str += $"/// </summary>\n";
         str += $"public partial class ActivityObject\n";
diff --git a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs
index 89cf6e0..337dab2 100644
--- a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs
+++ b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs
@@ -52,7 +52,7 @@
         Monitoring = true;
         Monitorable = false;
         CollisionLayer = PhysicsLayer.None;
-        CollisionMask = PhysicsLayer.Props | PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Shell | PhysicsLayer.Throwing;
+        CollisionMask = PhysicsLayer.Prop | PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Shell | PhysicsLayer.Throwing;
 
         BodyEntered += OnBodyEntered;
     }
diff --git a/DungeonShooting_Godot/src/game/PhysicsLayer.cs b/DungeonShooting_Godot/src/game/PhysicsLayer.cs
index c1c53ea..a96e34d 100644
--- a/DungeonShooting_Godot/src/game/PhysicsLayer.cs
+++ b/DungeonShooting_Godot/src/game/PhysicsLayer.cs
@@ -18,7 +18,7 @@
     /// <summary>
     /// 道具
     /// </summary>
-    public const uint Props = 0b100;
+    public const uint Prop = 0b100;
     /// <summary>
     /// 玩家
     /// </summary>
diff --git a/DungeonShooting_Godot/src/game/activity/package/Holster.cs b/DungeonShooting_Godot/src/game/activity/package/Holster.cs
index a487f64..df5dc56 100644
--- a/DungeonShooting_Godot/src/game/activity/package/Holster.cs
+++ b/DungeonShooting_Godot/src/game/activity/package/Holster.cs
@@ -141,7 +141,7 @@
         for (var i = 0; i < Weapons.Length; i++)
         {
             var item = Weapons[i];
-            if (item != null && item.ItemId == id)
+            if (item != null && item.ItemConfig.Id == id)
             {
                 return i;
             }
diff --git a/DungeonShooting_Godot/src/game/activity/prop/Prop.cs b/DungeonShooting_Godot/src/game/activity/prop/Prop.cs
new file mode 100644
index 0000000..5962d3b
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/prop/Prop.cs
@@ -0,0 +1,8 @@
+
+/// <summary>
+/// 道具基类
+/// </summary>
+public abstract partial class Prop : ActivityObject
+{
+    
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/prop/buff/Buff.cs b/DungeonShooting_Godot/src/game/activity/prop/buff/Buff.cs
new file mode 100644
index 0000000..1ca6d54
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/prop/buff/Buff.cs
@@ -0,0 +1,43 @@
+
+/// <summary>
+/// 增益被动道具
+/// </summary>
+public abstract partial class Buff : Prop
+{
+    /// <summary>
+    /// buff的拥有者
+    /// </summary>
+    public Role Master { get; private set; }
+    
+    /// <summary>
+    /// 当被动被道具被拾起时调用
+    /// </summary>
+    /// <param name="master">拾起该buff的角色</param>
+    protected abstract void OnPickUp(Role master);
+
+    /// <summary>
+    /// 当被动道具被移除时调用
+    /// </summary>
+    /// <param name="master">移除该buff的角色</param>
+    protected abstract void OnRemove(Role master);
+
+    public override void Interactive(ActivityObject master)
+    {
+        if (master is Role role)
+        {
+            Pickup();
+            Master = role;
+            role.PushBuff(this);
+            OnPickUp(role);
+        }
+    }
+
+    public override CheckInteractiveResult CheckInteractive(ActivityObject master)
+    {
+        if (master is Player)
+        {
+            return new CheckInteractiveResult(this, true, "拾起道具", ResourcePath.resource_sprite_ui_icon_icon_pickup_png);
+        }
+        return base.CheckInteractive(master);
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/prop/buff/MoveSpeedBuff.cs b/DungeonShooting_Godot/src/game/activity/prop/buff/MoveSpeedBuff.cs
new file mode 100644
index 0000000..7c4eb06
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/prop/buff/MoveSpeedBuff.cs
@@ -0,0 +1,19 @@
+
+using Godot;
+
+/// <summary>
+/// 移速 buff
+/// </summary>
+[GlobalClass, Tool]
+public partial class MoveSpeedBuff : Buff
+{
+    protected override void OnPickUp(Role master)
+    {
+        master.RoleState.MoveSpeed += 100;
+    }
+
+    protected override void OnRemove(Role master)
+    {
+        master.RoleState.MoveSpeed -= 100;
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/CampEnum.cs b/DungeonShooting_Godot/src/game/activity/role/CampEnum.cs
new file mode 100644
index 0000000..6954070
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/CampEnum.cs
@@ -0,0 +1,10 @@
+
+public enum CampEnum
+{
+    // 阵营1, 玩家
+    Camp1,
+    // 阵营2, 敌人
+    Camp2,
+    // 阵营3, 中立单位
+    Camp3
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/FaceDirection.cs b/DungeonShooting_Godot/src/game/activity/role/FaceDirection.cs
new file mode 100644
index 0000000..5be28ef
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/FaceDirection.cs
@@ -0,0 +1,8 @@
+/// <summary>
+/// 脸的朝向
+/// </summary>
+public enum FaceDirection
+{
+    Left = -1,
+    Right = 1,
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/MountRotation.cs b/DungeonShooting_Godot/src/game/activity/role/MountRotation.cs
new file mode 100644
index 0000000..e265b10
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/MountRotation.cs
@@ -0,0 +1,67 @@
+
+using Godot;
+
+/// <summary>
+/// 用于限定 Marker2D 节点的旋转角度
+/// </summary>
+[Tool]
+public partial class MountRotation : Marker2D
+{
+    /// <summary>
+    /// 吸附角度
+    /// </summary>
+    private int _adsorption = 6;
+    
+    /// <summary>
+    /// 所在的角色
+    /// </summary>
+    public Role Master { get; set; }
+
+    /// <summary>
+    /// 当前节点真实的旋转角度, 角度制
+    /// </summary>
+    public float RealRotationDegrees { get; private set; }
+    
+    /// <summary>
+    /// 当前节点真实的旋转角度, 弧度制
+    /// </summary>
+    public float RealRotation => Mathf.DegToRad(RealRotationDegrees);
+
+    /// <summary>
+    /// 设置看向的目标点
+    /// </summary>
+    public void SetLookAt(Vector2 target)
+    {
+        var myPos = GlobalPosition;
+        var angle = Mathf.RadToDeg((target - myPos).Angle());
+
+        if (Master.Face == FaceDirection.Left)
+        {
+            if (angle < 0 && angle > -80)
+            {
+                angle = -80;
+            }
+            else if (angle >= 0 && angle < 80)
+            {
+                angle = 80;
+            }
+        }
+        else
+        {
+            angle = Mathf.Clamp(angle, -100, 100);
+        }
+
+        RealRotationDegrees = angle;
+
+        // if (Master.GlobalPosition.X >= target.X)
+        // {
+        //     angle = -angle;
+        // }
+        GlobalRotationDegrees = AdsorptionAngle(angle);
+    }
+
+    private float AdsorptionAngle(float angle)
+    {
+        return Mathf.Round(angle / _adsorption) * _adsorption;
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/Player.cs b/DungeonShooting_Godot/src/game/activity/role/Player.cs
new file mode 100644
index 0000000..5da029d
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/Player.cs
@@ -0,0 +1,249 @@
+using Godot;
+
+
+/// <summary>
+/// 玩家角色基类, 所有角色都必须继承该类
+/// </summary>
+[Tool, GlobalClass]
+public partial class Player : Role
+{
+    /// <summary>
+    /// 获取当前操作的角色
+    /// </summary>
+    public static Player Current { get; private set; }
+    
+    /// <summary>
+    /// 移动加速度
+    /// </summary>
+    public float Acceleration { get; set; } = 1500f;
+    
+    /// <summary>
+    /// 移动摩擦力
+    /// </summary>
+    public float Friction { get; set; } = 800f;
+
+    /// <summary>
+    /// 设置当前操作的玩家对象
+    /// </summary>
+    public static void SetCurrentPlayer(Player player)
+    {
+        Current = player;
+        //设置相机和鼠标跟随玩家
+        GameCamera.Main.SetFollowTarget(player);
+        GameApplication.Instance.Cursor.SetMountRole(player);
+    }
+    
+    public override void OnInit()
+    {
+        base.OnInit();
+        
+        AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Prop | PhysicsLayer.Enemy;
+        Camp = CampEnum.Camp1;
+
+        //让相机跟随玩家
+        // var remoteTransform = new RemoteTransform2D();
+        // AddChild(remoteTransform);
+        // MainCamera.Main.GlobalPosition = GlobalPosition;
+        // MainCamera.Main.ResetSmoothing();
+        // remoteTransform.RemotePath = remoteTransform.GetPathTo(MainCamera.Main);
+
+        MaxHp = 6;
+        Hp = 6;
+        MaxShield = 2;
+        Shield = 2;
+
+        // debug用
+        // Acceleration = 3000;
+        // Friction = 3000;
+        // MoveSpeed = 500;
+        // CollisionLayer = 0;
+        // CollisionMask = 0;
+        // GameCamera.Main.Zoom = new Vector2(0.5f, 0.5f);
+    }
+
+    protected override void Process(float delta)
+    {
+        if (IsDie)
+        {
+            return;
+        }
+        base.Process(delta);
+        //脸的朝向
+        if (LookTarget == null)
+        {
+            var gPos = GlobalPosition;
+            Vector2 mousePos = InputManager.CursorPosition;
+            if (mousePos.X > gPos.X && Face == FaceDirection.Left)
+            {
+                Face = FaceDirection.Right;
+            }
+            else if (mousePos.X < gPos.X && Face == FaceDirection.Right)
+            {
+                Face = FaceDirection.Left;
+            }
+            //枪口跟随鼠标
+            MountPoint.SetLookAt(mousePos);
+        }
+
+        if (InputManager.Exchange) //切换武器
+        {
+            ExchangeNext();
+        }
+        else if (InputManager.Throw) //扔掉武器
+        {
+            ThrowWeapon();
+
+            // //测试用的, 所有敌人也扔掉武器
+            // if (Affiliation != null)
+            // {
+            //     var enemies = Affiliation.FindIncludeItems(o =>
+            //     {
+            //         return o.CollisionWithMask(PhysicsLayer.Enemy);
+            //     });
+            //     foreach (var activityObject in enemies)
+            //     {
+            //         if (activityObject is Enemy enemy)
+            //         {
+            //             enemy.ThrowWeapon();
+            //         }
+            //     }
+            // }
+        }
+        else if (InputManager.Interactive) //互动物体
+        {
+            TriggerInteractive();
+        }
+        else if (InputManager.Reload) //换弹
+        {
+            Reload();
+        }
+        if (InputManager.Fire) //开火
+        {
+            Attack();
+        }
+
+        if (Input.IsKeyPressed(Key.P))
+        {
+            Hurt(1000, 0);
+        }
+    }
+
+    protected override void PhysicsProcess(float delta)
+    {
+        if (IsDie)
+        {
+            return;
+        }
+
+        base.PhysicsProcess(delta);
+        HandleMoveInput(delta);
+        //播放动画
+        PlayAnim();
+    }
+
+    protected override int OnHandlerHurt(int damage)
+    {
+        //修改受到的伤害, 每次只受到1点伤害
+        return 1;
+    }
+
+    protected override void OnHit(int damage, bool realHarm)
+    {
+        //进入无敌状态
+        if (realHarm) //真实伤害
+        {
+            PlayInvincibleFlashing(1.5f);
+        }
+        else //护盾抵消掉的
+        {
+            PlayInvincibleFlashing(0.5f);
+        }
+    }
+
+    protected override void OnChangeHp(int hp)
+    {
+        //GameApplication.Instance.Ui.SetHp(hp);
+        EventManager.EmitEvent(EventEnum.OnPlayerHpChange, hp);
+    }
+
+    protected override void OnChangeMaxHp(int maxHp)
+    {
+        //GameApplication.Instance.Ui.SetMaxHp(maxHp);
+        EventManager.EmitEvent(EventEnum.OnPlayerMaxHpChange, maxHp);
+    }
+
+    protected override void ChangeInteractiveItem(CheckInteractiveResult result)
+    {
+        //派发互动对象改变事件
+        EventManager.EmitEvent(EventEnum.OnPlayerChangeInteractiveItem, result);
+    }
+
+    protected override void OnChangeShield(int shield)
+    {
+        //GameApplication.Instance.Ui.SetShield(shield);
+        EventManager.EmitEvent(EventEnum.OnPlayerShieldChange, shield);
+    }
+
+    protected override void OnChangeMaxShield(int maxShield)
+    {
+        //GameApplication.Instance.Ui.SetMaxShield(maxShield);
+        EventManager.EmitEvent(EventEnum.OnPlayerMaxShieldChange, maxShield);
+    }
+
+    protected override void OnDie()
+    {
+        GameCamera.Main.SetFollowTarget(null);
+        BasisVelocity = Vector2.Zero;
+        MoveController.ClearForce();
+        UiManager.Open_Settlement();
+        //GameApplication.Instance.World.ProcessMode = ProcessModeEnum.WhenPaused;
+    }
+
+    //处理角色移动的输入
+    private void HandleMoveInput(float delta)
+    {
+        //角色移动
+        Vector2 dir = InputManager.MoveAxis;
+        // 移动. 如果移动的数值接近0(是用 摇杆可能出现 方向 可能会出现浮点),就friction的值 插值 到 0
+        // 如果 有输入 就以当前速度,用acceleration 插值到 对应方向 * 最大速度
+        if (Mathf.IsZeroApprox(dir.X))
+        {
+            BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, 0, Friction * delta), BasisVelocity.Y);
+        }
+        else
+        {
+            BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, dir.X * RoleState.MoveSpeed, Acceleration * delta),
+                BasisVelocity.Y);
+        }
+
+        if (Mathf.IsZeroApprox(dir.Y))
+        {
+            BasisVelocity = new Vector2(BasisVelocity.X, Mathf.MoveToward(BasisVelocity.Y, 0, Friction * delta));
+        }
+        else
+        {
+            BasisVelocity = new Vector2(BasisVelocity.X,
+                Mathf.MoveToward(BasisVelocity.Y, dir.Y * RoleState.MoveSpeed, Acceleration * delta));
+        }
+    }
+
+    // 播放动画
+    private void PlayAnim()
+    {
+        if (BasisVelocity != Vector2.Zero)
+        {
+            if ((Face == FaceDirection.Right && BasisVelocity.X >= 0) || Face == FaceDirection.Left && BasisVelocity.X <= 0) //向前走
+            {
+                AnimatedSprite.Play(AnimatorNames.Run);
+            }
+            else if ((Face == FaceDirection.Right && BasisVelocity.X < 0) || Face == FaceDirection.Left && BasisVelocity.X > 0) //向后走
+            {
+                AnimatedSprite.Play(AnimatorNames.ReverseRun);
+            }
+        }
+        else
+        {
+            AnimatedSprite.Play(AnimatorNames.Idle);
+        }
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/Role.cs b/DungeonShooting_Godot/src/game/activity/role/Role.cs
new file mode 100644
index 0000000..bc091b0
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs
@@ -0,0 +1,742 @@
+using System.Collections;
+using System.Collections.Generic;
+using Godot;
+
+/// <summary>
+/// 角色基类
+/// </summary>
+public abstract partial class Role : ActivityObject
+{
+    /// <summary>
+    /// 是否是 Ai
+    /// </summary>
+    public bool IsAi { get; protected set; } = false;
+
+    /// <summary>
+    /// 角色属性
+    /// </summary>
+    public RoleState RoleState { get; } = new RoleState();
+    
+    /// <summary>
+    /// 默认攻击对象层级
+    /// </summary>
+    public const uint DefaultAttackLayer = PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Wall | PhysicsLayer.Prop;
+    
+    /// <summary>
+    /// 伤害区域
+    /// </summary>
+    [Export, ExportFillNode]
+    public Area2D HurtArea { get; set; }
+
+    /// <summary>
+    /// 所属阵营
+    /// </summary>
+    public CampEnum Camp;
+
+    /// <summary>
+    /// 攻击目标的碰撞器所属层级, 数据源自于: PhysicsLayer
+    /// </summary>
+    public uint AttackLayer { get; set; } = PhysicsLayer.Wall;
+
+    // /// <summary>
+    // /// 携带的道具包裹
+    // /// </summary>
+    // public List<object> PropsPack { get; } = new List<object>();
+
+    /// <summary>
+    /// 角色携带的武器袋
+    /// </summary>
+    public Holster Holster { get; private set; }
+
+    /// <summary>
+    /// 武器挂载点
+    /// </summary>
+    [Export, ExportFillNode]
+    public MountRotation MountPoint { get; set; }
+    /// <summary>
+    /// 背后武器的挂载点
+    /// </summary>
+    [Export, ExportFillNode]
+    public Marker2D BackMountPoint { get; set; }
+
+    /// <summary>
+    /// 互动碰撞区域
+    /// </summary>
+    [Export, ExportFillNode]
+    public Area2D InteractiveArea { get; set; }
+    
+    /// <summary>
+    /// 脸的朝向
+    /// </summary>
+    public FaceDirection Face { get => _face; set => SetFace(value); }
+    private FaceDirection _face;
+
+    /// <summary>
+    /// 是否死亡
+    /// </summary>
+    public bool IsDie { get; private set; }
+    
+    /// <summary>
+    /// 血量
+    /// </summary>
+    public int Hp
+    {
+        get => _hp;
+        protected set
+        {
+            int temp = _hp;
+            _hp = value;
+            if (temp != _hp) OnChangeHp(_hp);
+        }
+    }
+    private int _hp = 20;
+
+    /// <summary>
+    /// 最大血量
+    /// </summary>
+    public int MaxHp
+    {
+        get => _maxHp;
+        protected set
+        {
+            int temp = _maxHp;
+            _maxHp = value;
+            //护盾值改变
+            if (temp != _maxHp) OnChangeMaxHp(_maxHp);
+        }
+    }
+    private int _maxHp = 20;
+    
+    /// <summary>
+    /// 当前护盾值
+    /// </summary>
+    public int Shield
+    {
+        get => _shield;
+        protected set
+        {
+            int temp = _shield;
+            _shield = value;
+            //护盾被破坏
+            if (temp > 0 && _shield <= 0) OnShieldDestroy();
+            //护盾值改变
+            if (temp != _shield) OnChangeShield(_shield);
+        }
+    }
+    private int _shield = 0;
+
+    /// <summary>
+    /// 最大护盾值
+    /// </summary>
+    public int MaxShield
+    {
+        get => _maxShield;
+        protected set
+        {
+            int temp = _maxShield;
+            _maxShield = value;
+            if (temp != _maxShield) OnChangeMaxShield(_maxShield);
+        }
+    }
+    private int _maxShield = 0;
+
+    /// <summary>
+    /// 单格护盾恢复时间
+    /// </summary>
+    private float ShieldRecoveryTime { get; set; } = 8;
+    
+    /// <summary>
+    /// 无敌状态
+    /// </summary>
+    public bool Invincible
+    {
+        get => _invincible;
+        set
+        {
+            if (_invincible != value)
+            {
+                if (value) //无敌状态
+                {
+                    HurtArea.CollisionLayer = _currentLayer;
+                    _flashingInvincibleTimer = -1;
+                    _flashingInvincibleFlag = false;
+                }
+                else //正常状态
+                {
+                    HurtArea.CollisionLayer = _currentLayer;
+                    SetBlendAlpha(1);
+                }
+            }
+
+            _invincible = value;
+        }
+    }
+
+    private bool _invincible = false;
+    
+    /// <summary>
+    /// 当前角色所看向的对象, 也就是枪口指向的对象
+    /// </summary>
+    public ActivityObject LookTarget { get; set; }
+
+    //初始缩放
+    private Vector2 _startScale;
+    //所有角色碰撞的道具
+    private readonly List<ActivityObject> _interactiveItemList = new List<ActivityObject>();
+
+    private CheckInteractiveResult _tempResultData;
+    private uint _currentLayer;
+    //闪烁计时器
+    private float _flashingInvincibleTimer = -1;
+    //闪烁状态
+    private bool _flashingInvincibleFlag = false;
+    //闪烁动画协程id
+    private long _invincibleFlashingId = -1;
+    //护盾恢复计时器
+    private float _shieldRecoveryTimer = 0;
+
+    /// <summary>
+    /// 可以互动的道具
+    /// </summary>
+    public ActivityObject InteractiveItem { get; private set; }
+
+    /// <summary>
+    /// 当血量改变时调用
+    /// </summary>
+    protected virtual void OnChangeHp(int hp)
+    {
+    }
+
+    /// <summary>
+    /// 当最大血量改变时调用
+    /// </summary>
+    protected virtual void OnChangeMaxHp(int maxHp)
+    {
+    }
+    
+    /// <summary>
+    /// 护盾值改变时调用
+    /// </summary>
+    protected virtual void OnChangeShield(int shield)
+    {
+    }
+
+    /// <summary>
+    /// 最大护盾值改变时调用
+    /// </summary>
+    protected virtual void OnChangeMaxShield(int maxShield)
+    {
+    }
+
+    /// <summary>
+    /// 当护盾被破坏时调用
+    /// </summary>
+    protected virtual void OnShieldDestroy()
+    {
+    }
+
+    /// <summary>
+    /// 当受伤时调用
+    /// </summary>
+    /// <param name="damage">受到的伤害</param>
+    /// <param name="realHarm">是否受到真实伤害, 如果为false, 则表示该伤害被互动格挡掉了</param>
+    protected virtual void OnHit(int damage, bool realHarm)
+    {
+    }
+
+    /// <summary>
+    /// 受到伤害时调用, 用于改变受到的伤害值
+    /// </summary>
+    /// <param name="damage">受到的伤害</param>
+    protected virtual int OnHandlerHurt(int damage)
+    {
+        return damage;
+    }
+    
+    /// <summary>
+    /// 当可互动的物体改变时调用, result 参数为 null 表示变为不可互动
+    /// </summary>
+    /// <param name="result">检测是否可互动时的返回值</param>
+    protected virtual void ChangeInteractiveItem(CheckInteractiveResult result)
+    {
+    }
+
+    /// <summary>
+    /// 死亡时调用
+    /// </summary>
+    protected virtual void OnDie()
+    {
+    }
+
+    public override void OnInit()
+    {
+        Holster = new Holster(this);
+        _startScale = Scale;
+        MountPoint.Master = this;
+        
+        HurtArea.CollisionLayer = CollisionLayer;
+        HurtArea.CollisionMask = 0;
+        _currentLayer = HurtArea.CollisionLayer;
+        
+        Face = FaceDirection.Right;
+        
+        //连接互动物体信号
+        InteractiveArea.BodyEntered += _OnPropsEnter;
+        InteractiveArea.BodyExited += _OnPropsExit;
+    }
+
+    protected override void Process(float delta)
+    {
+        //看向目标
+        if (LookTarget != null)
+        {
+            Vector2 pos = LookTarget.GlobalPosition;
+            //脸的朝向
+            var gPos = GlobalPosition;
+            if (pos.X > gPos.X && Face == FaceDirection.Left)
+            {
+                Face = FaceDirection.Right;
+            }
+            else if (pos.X < gPos.X && Face == FaceDirection.Right)
+            {
+                Face = FaceDirection.Left;
+            }
+            //枪口跟随目标
+            MountPoint.SetLookAt(pos);
+        }
+        
+        //检查可互动的道具
+        bool findFlag = false;
+        for (int i = 0; i < _interactiveItemList.Count; i++)
+        {
+            var item = _interactiveItemList[i];
+            if (item == null || item.IsDestroyed)
+            {
+                _interactiveItemList.RemoveAt(i--);
+            }
+            else
+            {
+                //找到可互动的道具了
+                if (!findFlag)
+                {
+                    var result = item.CheckInteractive(this);
+                    if (result.CanInteractive) //可以互动
+                    {
+                        findFlag = true;
+                        if (InteractiveItem != item) //更改互动物体
+                        {
+                            InteractiveItem = item;
+                            ChangeInteractiveItem(result);
+                        }
+                        else if (result.ShowIcon != _tempResultData.ShowIcon) //切换状态
+                        {
+                            ChangeInteractiveItem(result);
+                        }
+                    }
+                    _tempResultData = result;
+                }
+            }
+        }
+        //没有可互动的道具
+        if (!findFlag && InteractiveItem != null)
+        {
+            InteractiveItem = null;
+            ChangeInteractiveItem(null);
+        }
+
+        //无敌状态, 播放闪烁动画
+        if (Invincible)
+        {
+            _flashingInvincibleTimer -= delta;
+            if (_flashingInvincibleTimer <= 0)
+            {
+                _flashingInvincibleTimer = 0.15f;
+                if (_flashingInvincibleFlag)
+                {
+                    _flashingInvincibleFlag = false;
+                    SetBlendAlpha(0.7f);
+                }
+                else
+                {
+                    _flashingInvincibleFlag = true;
+                    SetBlendAlpha(0);
+                }
+            }
+
+            _shieldRecoveryTimer = 0;
+        }
+        else //恢复护盾
+        {
+            if (Shield < MaxShield)
+            {
+                _shieldRecoveryTimer += delta;
+                if (_shieldRecoveryTimer >= ShieldRecoveryTime) //时间到, 恢复
+                {
+                    Shield++;
+                    _shieldRecoveryTimer = 0;
+                }
+            }
+            else
+            {
+                _shieldRecoveryTimer = 0;
+            }
+        }
+    }
+
+    /// <summary>
+    /// 当武器放到后背时调用, 用于设置武器位置和角度
+    /// </summary>
+    /// <param name="weapon">武器实例</param>
+    /// <param name="index">放入武器袋的位置</param>
+    public virtual void OnPutBackMount(Weapon weapon, int index)
+    {
+        if (index < 8)
+        {
+            if (index % 2 == 0)
+            {
+                weapon.Position = new Vector2(-4, 3);
+                weapon.RotationDegrees = 90 - (index / 2f) * 20;
+                weapon.Scale = new Vector2(-1, 1);
+            }
+            else
+            {
+                weapon.Position = new Vector2(4, 3);
+                weapon.RotationDegrees = 270 + (index - 1) / 2f * 20;
+                weapon.Scale = new Vector2(1, 1);
+            }
+        }
+        else
+        {
+            weapon.Visible = false;
+        }
+    }
+    
+    protected override void OnAffiliationChange()
+    {
+        //身上的武器的所属区域也得跟着变
+        Holster.ForEach((weapon, i) =>
+        {
+            if (AffiliationArea != null)
+            {
+                AffiliationArea.InsertItem(weapon);
+            }
+            else if (weapon.AffiliationArea != null)
+            {
+                weapon.AffiliationArea.RemoveItem(weapon);
+            }
+        });
+    }
+
+    /// <summary>
+    /// 获取当前角色的中心点坐标
+    /// </summary>
+    public Vector2 GetCenterPosition()
+    {
+        return MountPoint.GlobalPosition;
+    }
+
+    /// <summary>
+    /// 使角色看向指定的坐标,
+    /// 注意, 调用该函数会清空 LookTarget, 因为拥有 LookTarget 时也会每帧更新玩家视野位置
+    /// </summary>
+    /// <param name="pos"></param>
+    public void LookTargetPosition(Vector2 pos)
+    {
+        LookTarget = null;
+        //脸的朝向
+        var gPos = GlobalPosition;
+        if (pos.X > gPos.X && Face == FaceDirection.Left)
+        {
+            Face = FaceDirection.Right;
+        }
+        else if (pos.X < gPos.X && Face == FaceDirection.Right)
+        {
+            Face = FaceDirection.Left;
+        }
+        //枪口跟随目标
+        MountPoint.SetLookAt(pos);
+    }
+    
+    /// <summary>
+    /// 判断指定坐标是否在角色视野方向
+    /// </summary>
+    public bool IsPositionInForward(Vector2 pos)
+    {
+        var gps = GlobalPosition;
+        return (Face == FaceDirection.Left && pos.X <= gps.X) ||
+               (Face == FaceDirection.Right && pos.X >= gps.X);
+    }
+
+    /// <summary>
+    /// 返回所有武器是否弹药都打光了
+    /// </summary>
+    public bool IsAllWeaponTotalAmmoEmpty()
+    {
+        foreach (var weapon in Holster.Weapons)
+        {
+            if (weapon != null && !weapon.IsTotalAmmoEmpty())
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    
+    /// <summary>
+    /// 拾起一个武器, 返回是否成功拾取, 如果不想立刻切换到该武器, exchange 请传 false
+    /// </summary>
+    /// <param name="weapon">武器对象</param>
+    /// <param name="exchange">是否立即切换到该武器, 默认 true </param>
+    public virtual bool PickUpWeapon(Weapon weapon, bool exchange = true)
+    {
+        if (Holster.PickupWeapon(weapon, exchange) != -1)
+        {
+            //从可互动队列中移除
+            _interactiveItemList.Remove(weapon);
+            return true;
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    /// 切换到下一个武器
+    /// </summary>
+    public virtual void ExchangeNext()
+    {
+        Holster.ExchangeNext();
+    }
+
+    /// <summary>
+    /// 切换到上一个武器
+    /// </summary>
+    public virtual void ExchangePrev()
+    {
+        Holster.ExchangePrev();
+    }
+
+    /// <summary>
+    /// 扔掉当前使用的武器, 切换到上一个武器
+    /// </summary>
+    public virtual void ThrowWeapon()
+    {
+        ThrowWeapon(Holster.ActiveIndex);
+    }
+
+    /// <summary>
+    /// 扔掉指定位置的武器
+    /// </summary>
+    /// <param name="index">武器在武器袋中的位置</param>
+    public virtual void ThrowWeapon(int index)
+    {
+        var weapon = Holster.GetWeapon(index);
+        if (weapon == null)
+        {
+            return;
+        }
+
+        var temp = weapon.AnimatedSprite.Position;
+        if (Face == FaceDirection.Left)
+        {
+            temp.Y = -temp.Y;
+        }
+        //var pos = GlobalPosition + temp.Rotated(weapon.GlobalRotation);
+        Holster.RemoveWeapon(index);
+        //播放抛出效果
+        weapon.ThrowWeapon(this, GlobalPosition);
+    }
+
+    /// <summary>
+    /// 返回是否存在可互动的物体
+    /// </summary>
+    public bool HasInteractive()
+    {
+        return InteractiveItem != null;
+    }
+
+    /// <summary>
+    /// 触发与碰撞的物体互动, 并返回与其互动的物体
+    /// </summary>
+    public ActivityObject TriggerInteractive()
+    {
+        if (HasInteractive())
+        {
+            var item = InteractiveItem;
+            item.Interactive(this);
+            return item;
+        }
+
+        return null;
+    }
+
+    /// <summary>
+    /// 触发换弹
+    /// </summary>
+    public virtual void Reload()
+    {
+        if (Holster.ActiveWeapon != null)
+        {
+            Holster.ActiveWeapon.Reload();
+        }
+    }
+
+    /// <summary>
+    /// 触发攻击
+    /// </summary>
+    public virtual void Attack()
+    {
+        if (Holster.ActiveWeapon != null)
+        {
+            Holster.ActiveWeapon.Trigger();
+        }
+    }
+
+    /// <summary>
+    /// 受到伤害, 如果是在碰撞信号处理函数中调用该函数, 请使用 CallDeferred 来延时调用, 否则很有可能导致报错
+    /// </summary>
+    /// <param name="damage">伤害的量</param>
+    /// <param name="angle">角度</param>
+    public virtual void Hurt(int damage, float angle)
+    {
+        //受伤闪烁, 无敌状态
+        if (Invincible)
+        {
+            return;
+        }
+        
+        //计算真正受到的伤害
+        damage = OnHandlerHurt(damage);
+        if (damage <= 0)
+        {
+            return;
+        }
+
+        var flag = Shield > 0;
+        if (flag)
+        {
+            Shield -= damage;
+        }
+        else
+        {
+            Hp -= damage;
+            //播放血液效果
+            // var packedScene = ResourceManager.Load<PackedScene>(ResourcePath.prefab_effect_Blood_tscn);
+            // var blood = packedScene.Instance<Blood>();
+            // blood.GlobalPosition = GlobalPosition;
+            // blood.Rotation = angle;
+            // GameApplication.Instance.Node3D.GetRoot().AddChild(blood);
+        }
+        OnHit(damage, !flag);
+        
+        //受伤特效
+        PlayHitAnimation();
+        
+        //死亡判定
+        if (Hp <= 0)
+        {
+            //死亡
+            if (!IsDie)
+            {
+                IsDie = true;
+                OnDie();
+            }
+        }
+    }
+
+    /// <summary>
+    /// 播放无敌状态闪烁动画
+    /// </summary>
+    /// <param name="time">持续时间</param>
+    public void PlayInvincibleFlashing(float time)
+    {
+        Invincible = true;
+        if (_invincibleFlashingId >= 0) //上一个还没结束
+        {
+            StopCoroutine(_invincibleFlashingId);
+        }
+
+        _invincibleFlashingId = StartCoroutine(RunInvincibleFlashing(time));
+    }
+
+    /// <summary>
+    /// 停止无敌状态闪烁动画
+    /// </summary>
+    public void StopInvincibleFlashing()
+    {
+        Invincible = false;
+        if (_invincibleFlashingId >= 0)
+        {
+            StopCoroutine(_invincibleFlashingId);
+            _invincibleFlashingId = -1;
+        }
+    }
+
+    private IEnumerator RunInvincibleFlashing(float time)
+    {
+        yield return new WaitForSeconds(time);
+        _invincibleFlashingId = -1;
+        Invincible = false;
+    }
+
+    /// <summary>
+    /// 设置脸的朝向
+    /// </summary>
+    private void SetFace(FaceDirection face)
+    {
+        if (_face != face)
+        {
+            _face = face;
+            if (face == FaceDirection.Right)
+            {
+                RotationDegrees = 0;
+                Scale = _startScale;
+            }
+            else
+            {
+                RotationDegrees = 180;
+                Scale = new Vector2(_startScale.X, -_startScale.Y);
+            }
+        }
+    }
+    
+    /// <summary>
+    /// 连接信号: InteractiveArea.BodyEntered
+    /// 与物体碰撞
+    /// </summary>
+    private void _OnPropsEnter(Node2D other)
+    {
+        if (other is ActivityObject propObject && !propObject.CollisionWithMask(PhysicsLayer.OnHand))
+        {
+            if (!_interactiveItemList.Contains(propObject))
+            {
+                _interactiveItemList.Add(propObject);
+            }
+        }
+    }
+
+    /// <summary>
+    /// 连接信号: InteractiveArea.BodyExited
+    /// 物体离开碰撞区域
+    /// </summary>
+    private void _OnPropsExit(Node2D other)
+    {
+        if (other is ActivityObject propObject)
+        {
+            if (_interactiveItemList.Contains(propObject))
+            {
+                _interactiveItemList.Remove(propObject);
+            }
+            if (InteractiveItem == propObject)
+            {
+                InteractiveItem = null;
+                ChangeInteractiveItem(null);
+            }
+        }
+    }
+
+    public void PushBuff(Buff buff)
+    {
+        
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/RoleState.cs b/DungeonShooting_Godot/src/game/activity/role/RoleState.cs
new file mode 100644
index 0000000..08d3338
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/RoleState.cs
@@ -0,0 +1,11 @@
+
+/// <summary>
+/// 角色属性类
+/// </summary>
+public class RoleState
+{
+    /// <summary>
+    /// 移动速度
+    /// </summary>
+    public float MoveSpeed = 120f;
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
new file mode 100644
index 0000000..d2200c6
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
@@ -0,0 +1,459 @@
+#region 基础敌人设计思路
+/*
+敌人有三种状态: 
+状态1: 未发现玩家, 视野不可穿墙, 该状态下敌人移动比较规律, 移动速度较慢, 一旦玩家进入视野或者听到玩家枪声, 立刻切换至状态3, 该房间的敌人不能再回到状态1
+状态2: 发现有玩家, 但不知道在哪, 视野不可穿墙, 该情况下敌人移动速度明显加快, 移动不规律, 一旦玩家进入视野或者听到玩家枪声, 立刻切换至状态3
+状态3: 明确知道玩家的位置, 视野允许穿墙, 移动速度与状态2一致, 进入该状态时, 敌人之间会相互告知玩家所在位置, 并朝着玩家位置开火,
+       如果有墙格挡, 则有一定概率继续开火, 一旦玩家立刻敌人视野超哥一段时间, 敌人自动切换为状态2
+
+敌人状态1只存在于少数房间内, 比如特殊房间, 大部分情况下敌人应该是状态2, 或者玩家进入房间时就被敌人发现
+*/
+#endregion
+
+
+using Godot;
+
+/// <summary>
+/// 基础敌人
+/// </summary>
+[Tool, GlobalClass]
+public partial class Enemy : Role
+{
+    /// <summary>
+    /// 敌人身上的状态机控制器
+    /// </summary>
+    public StateController<Enemy, AiStateEnum> StateController { get; private set; }
+
+    /// <summary>
+    /// 视野半径, 单位像素, 发现玩家后改视野范围可以穿墙
+    /// </summary>
+    public float ViewRange { get; set; } = 250;
+
+    /// <summary>
+    /// 发现玩家后的视野半径
+    /// </summary>
+    public float TailAfterViewRange { get; set; } = 400;
+
+    /// <summary>
+    /// 背后的视野半径, 单位像素
+    /// </summary>
+    public float BackViewRange { get; set; } = 50;
+
+    /// <summary>
+    /// 视野检测射线, 朝玩家打射线, 检测是否碰到墙
+    /// </summary>
+    public RayCast2D ViewRay { get; private set; }
+
+    /// <summary>
+    /// 导航代理
+    /// </summary>
+    public NavigationAgent2D NavigationAgent2D { get; private set; }
+
+    /// <summary>
+    /// 导航代理中点
+    /// </summary>
+    public Marker2D NavigationPoint { get; private set; }
+
+    //开火间隙时间
+    private float _enemyAttackTimer = 0;
+    //目标在视野内的时间
+    private float _targetInViewTime = 0;
+
+    public override void OnInit()
+    {
+        base.OnInit();
+        IsAi = true;
+        StateController = AddComponent<StateController<Enemy, AiStateEnum>>();
+
+        AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Prop | PhysicsLayer.Player;
+        Camp = CampEnum.Camp2;
+
+        RoleState.MoveSpeed = 20;
+
+        MaxHp = 20;
+        Hp = 20;
+
+        //视野射线
+        ViewRay = GetNode<RayCast2D>("ViewRay");
+        NavigationPoint = GetNode<Marker2D>("NavigationPoint");
+        NavigationAgent2D = NavigationPoint.GetNode<NavigationAgent2D>("NavigationAgent2D");
+
+        //PathSign = new PathSign(this, PathSignLength, GameApplication.Instance.Node3D.Player);
+
+        //注册Ai状态机
+        StateController.Register(new AiNormalState());
+        StateController.Register(new AiProbeState());
+        StateController.Register(new AiTailAfterState());
+        StateController.Register(new AiFollowUpState());
+        StateController.Register(new AiLeaveForState());
+        StateController.Register(new AiSurroundState());
+        StateController.Register(new AiFindAmmoState());
+        
+        //默认状态
+        StateController.ChangeStateInstant(AiStateEnum.AiNormal);
+    }
+
+    public override void EnterTree()
+    {
+        base.EnterTree();
+        if (!World.Enemy_InstanceList.Contains(this))
+        {
+            World.Enemy_InstanceList.Add(this);
+        }
+    }
+
+    public override void ExitTree()
+    {
+        base.ExitTree();
+        World.Enemy_InstanceList.Remove(this);
+    }
+
+    protected override void OnDie()
+    {
+        //扔掉所有武器
+        var weapons = Holster.GetAndClearWeapon();
+        for (var i = 0; i < weapons.Length; i++)
+        {
+            weapons[i].ThrowWeapon(this);
+        }
+
+        var effPos = Position + new Vector2(0, -Altitude);
+        //血液特效
+        var blood = ResourceManager.LoadAndInstantiate<AutoDestroyEffect>(ResourcePath.prefab_effect_activityObject_EnemyBloodEffect_tscn);
+        blood.Position = effPos - new Vector2(0, 12);
+        blood.AddToActivityRoot(RoomLayerEnum.NormalLayer);
+        
+        //创建敌人碎片
+        var count = Utils.RandomRangeInt(3, 6);
+        for (var i = 0; i < count; i++)
+        {
+            var debris = Create(Ids.Id_effect0001);
+            debris.PutDown(effPos, RoomLayerEnum.NormalLayer);
+            debris.InheritVelocity(this);
+        }
+        
+        //派发敌人死亡信号
+        EventManager.EmitEvent(EventEnum.OnEnemyDie, this);
+        Destroy();
+    }
+
+    protected override void Process(float delta)
+    {
+        base.Process(delta);
+        _enemyAttackTimer -= delta;
+
+        //目标在视野内的时间
+        var currState = StateController.CurrState;
+        if (currState == AiStateEnum.AiSurround || currState == AiStateEnum.AiFollowUp)
+        {
+            _targetInViewTime += delta;
+        }
+        else
+        {
+            _targetInViewTime = 0;
+        }
+
+        EnemyPickUpWeapon();
+    }
+
+    protected override void OnHit(int damage, bool realHarm)
+    {
+        //受到伤害
+        var state = StateController.CurrState;
+        if (state == AiStateEnum.AiNormal || state == AiStateEnum.AiProbe || state == AiStateEnum.AiLeaveFor)
+        {
+            StateController.ChangeState(AiStateEnum.AiTailAfter);
+        }
+    }
+
+    /// <summary>
+    /// 返回地上的武器是否有可以拾取的, 也包含没有被其他敌人标记的武器
+    /// </summary>
+    public bool CheckUsableWeaponInUnclaimed()
+    {
+        foreach (var unclaimedWeapon in World.Weapon_UnclaimedWeapons)
+        {
+            //判断是否能拾起武器, 条件: 相同的房间
+            if (unclaimedWeapon.AffiliationArea == AffiliationArea)
+            {
+                if (!unclaimedWeapon.IsTotalAmmoEmpty())
+                {
+                    if (!unclaimedWeapon.HasSign(SignNames.AiFindWeaponSign))
+                    {
+                        return true;
+                    }
+                    else
+                    {
+                        //判断是否可以移除该标记
+                        var enemy = unclaimedWeapon.GetSign<Enemy>(SignNames.AiFindWeaponSign);
+                        if (enemy == null || enemy.IsDestroyed) //标记当前武器的敌人已经被销毁
+                        {
+                            unclaimedWeapon.RemoveSign(SignNames.AiFindWeaponSign);
+                            return true;
+                        }
+                        else if (!enemy.IsAllWeaponTotalAmmoEmpty()) //标记当前武器的敌人已经有新的武器了
+                        {
+                            unclaimedWeapon.RemoveSign(SignNames.AiFindWeaponSign);
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+    
+    /// <summary>
+    /// 寻找可用的武器
+    /// </summary>
+    public Weapon FindTargetWeapon()
+    {
+        Weapon target = null;
+        var position = Position;
+        foreach (var weapon in World.Weapon_UnclaimedWeapons)
+        {
+            //判断是否能拾起武器, 条件: 相同的房间, 或者当前房间目前没有战斗, 或者不在战斗房间
+            if (weapon.AffiliationArea == AffiliationArea)
+            {
+                //还有弹药
+                if (!weapon.IsTotalAmmoEmpty())
+                {
+                    //查询是否有其他敌人标记要拾起该武器
+                    if (weapon.HasSign(SignNames.AiFindWeaponSign))
+                    {
+                        var enemy = weapon.GetSign<Enemy>(SignNames.AiFindWeaponSign);
+                        if (enemy == this) //就是自己标记的
+                        {
+
+                        }
+                        else if (enemy == null || enemy.IsDestroyed) //标记当前武器的敌人已经被销毁
+                        {
+                            weapon.RemoveSign(SignNames.AiFindWeaponSign);
+                        }
+                        else if (!enemy.IsAllWeaponTotalAmmoEmpty()) //标记当前武器的敌人已经有新的武器了
+                        {
+                            weapon.RemoveSign(SignNames.AiFindWeaponSign);
+                        }
+                        else //放弃这把武器
+                        {
+                            continue;
+                        }
+                    }
+
+                    if (target == null) //第一把武器
+                    {
+                        target = weapon;
+                    }
+                    else if (target.Position.DistanceSquaredTo(position) >
+                             weapon.Position.DistanceSquaredTo(position)) //距离更近
+                    {
+                        target = weapon;
+                    }
+                }
+            }
+        }
+
+        return target;
+    }
+
+    /// <summary>
+    /// 检查是否能切换到 AiStateEnum.AiLeaveFor 状态
+    /// </summary>
+    /// <returns></returns>
+    public bool CanChangeLeaveFor()
+    {
+        if (!World.Enemy_IsFindTarget)
+        {
+            return false;
+        }
+
+        var currState = StateController.CurrState;
+        if (currState == AiStateEnum.AiNormal || currState == AiStateEnum.AiProbe)
+        {
+            //判断是否在同一个房间内
+            return World.Enemy_FindTargetAffiliationSet.Contains(AffiliationArea);
+        }
+        
+        return false;
+    }
+
+    /// <summary>
+    /// Ai触发的攻击
+    /// </summary>
+    public void EnemyAttack(float delta)
+    {
+        var weapon = Holster.ActiveWeapon;
+        if (weapon != null)
+        {
+            if (weapon.IsTotalAmmoEmpty()) //当前武器弹药打空
+            {
+                //切换到有子弹的武器
+                var index = Holster.FindWeapon((we, i) => !we.IsTotalAmmoEmpty());
+                if (index != -1)
+                {
+                    Holster.ExchangeByIndex(index);
+                }
+                else //所有子弹打光
+                {
+                    
+                }
+            }
+            else if (weapon.Reloading) //换弹中
+            {
+
+            }
+            else if (weapon.IsAmmoEmpty()) //弹夹已经打空
+            {
+                Reload();
+            }
+            else if (_targetInViewTime >= weapon.Attribute.AiTargetLockingTime) //正常射击
+            {
+                if (weapon.GetDelayedAttackTime() > 0)
+                {
+                    Attack();
+                }
+                else
+                {
+                    if (weapon.Attribute.ContinuousShoot) //连发
+                    {
+                        Attack();
+                    }
+                    else //单发
+                    {
+                        if (_enemyAttackTimer <= 0)
+                        {
+                            _enemyAttackTimer = 60f / weapon.Attribute.StartFiringSpeed;
+                            Attack();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    /// 获取武器攻击范围 (最大距离值与最小距离的中间值)
+    /// </summary>
+    /// <param name="weight">从最小到最大距离的过渡量, 0 - 1, 默认 0.5</param>
+    public float GetWeaponRange(float weight = 0.5f)
+    {
+        if (Holster.ActiveWeapon != null)
+        {
+            var attribute = Holster.ActiveWeapon.Attribute;
+            return Mathf.Lerp(attribute.BulletMinDistance, attribute.BulletMaxDistance, weight);
+        }
+
+        return 0;
+    }
+
+    /// <summary>
+    /// 返回目标点是否在视野范围内
+    /// </summary>
+    public bool IsInViewRange(Vector2 target)
+    {
+        var isForward = IsPositionInForward(target);
+        if (isForward)
+        {
+            if (GlobalPosition.DistanceSquaredTo(target) <= ViewRange * ViewRange) //没有超出视野半径
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    /// 返回目标点是否在跟随状态下的视野半径内
+    /// </summary>
+    public bool IsInTailAfterViewRange(Vector2 target)
+    {
+        var isForward = IsPositionInForward(target);
+        if (isForward)
+        {
+            if (GlobalPosition.DistanceSquaredTo(target) <= TailAfterViewRange * TailAfterViewRange) //没有超出视野半径
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    /// 调用视野检测, 如果被墙壁和其它物体遮挡, 则返回被挡住视野的物体对象, 视野无阻则返回 null
+    /// </summary>
+    public bool TestViewRayCast(Vector2 target)
+    {
+        ViewRay.Enabled = true;
+        ViewRay.TargetPosition = ViewRay.ToLocal(target);
+        ViewRay.ForceRaycastUpdate();
+        return ViewRay.IsColliding();
+    }
+
+    /// <summary>
+    /// 调用视野检测完毕后, 需要调用 TestViewRayCastOver() 来关闭视野检测射线
+    /// </summary>
+    public void TestViewRayCastOver()
+    {
+        ViewRay.Enabled = false;
+    }
+
+    /// <summary>
+    /// AI 拾起武器操作
+    /// </summary>
+    private void EnemyPickUpWeapon()
+    {
+        //这几个状态不需要主动拾起武器操作
+        var state = StateController.CurrState;
+        if (state == AiStateEnum.AiNormal)
+        {
+            return;
+        }
+        
+        //拾起地上的武器
+        if (InteractiveItem is Weapon weapon)
+        {
+            if (Holster.ActiveWeapon == null) //手上没有武器, 无论如何也要拾起
+            {
+                TriggerInteractive();
+                return;
+            }
+
+            //没弹药了
+            if (weapon.IsTotalAmmoEmpty())
+            {
+                return;
+            }
+            
+            var index = Holster.FindWeapon((we, i) => we.ItemConfig.Id == weapon.ItemConfig.Id);
+            if (index != -1) //与武器袋中武器类型相同, 补充子弹
+            {
+                if (!Holster.GetWeapon(index).IsAmmoFull())
+                {
+                    TriggerInteractive();
+                }
+
+                return;
+            }
+
+            // var index2 = Holster.FindWeapon((we, i) =>
+            //     we.Attribute.WeightType == weapon.Attribute.WeightType && we.IsTotalAmmoEmpty());
+            var index2 = Holster.FindWeapon((we, i) => we.IsTotalAmmoEmpty());
+            if (index2 != -1) //扔掉没子弹的武器
+            {
+                ThrowWeapon(index2);
+                TriggerInteractive();
+                return;
+            }
+            
+            // if (Holster.HasVacancy()) //有空位, 拾起武器
+            // {
+            //     TriggerInteractive();
+            //     return;
+            // }
+        }
+    }
+
+}
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AIStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AIStateEnum.cs
new file mode 100644
index 0000000..6bb8db4
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AIStateEnum.cs
@@ -0,0 +1,32 @@
+
+public enum AiStateEnum
+{
+    /// <summary>
+    /// Ai 状态, 正常, 未发现目标
+    /// </summary>
+    AiNormal,
+    /// <summary>
+    /// 发现目标, 但不知道在哪
+    /// </summary>
+    AiProbe,
+    /// <summary>
+    /// 收到其他敌人通知, 前往发现目标的位置
+    /// </summary>
+    AiLeaveFor,
+    /// <summary>
+    /// 发现目标, 目标不在视野内, 但是知道位置
+    /// </summary>
+    AiTailAfter,
+    /// <summary>
+    /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火
+    /// </summary>
+    AiFollowUp,
+    /// <summary>
+    /// 距离足够近, 在目标附近随机移动
+    /// </summary>
+    AiSurround,
+    /// <summary>
+    /// Ai 寻找弹药
+    /// </summary>
+    AiFindAmmo,
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFindAmmoState.cs
new file mode 100644
index 0000000..f1f6863
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFindAmmoState.cs
@@ -0,0 +1,152 @@
+
+using Godot;
+
+/// <summary>
+/// Ai 寻找弹药, 进入该状态需要在参数中传入目标武器对象
+/// </summary>
+public class AiFindAmmoState : StateBase<Enemy, AiStateEnum>
+{
+
+    private Weapon _target;
+
+    //导航目标点刷新计时器
+    private float _navigationUpdateTimer = 0;
+    private float _navigationInterval = 1f;
+
+    private bool _isInTailAfterRange = false;
+    private float _tailAfterTimer = 0;
+
+    public AiFindAmmoState() : base(AiStateEnum.AiFindAmmo)
+    {
+    }
+
+    public override void Enter(AiStateEnum prev, params object[] args)
+    {
+        if (args.Length == 0)
+        {
+            GD.PrintErr("进入 AiStateEnum.AiFindAmmo 状态必须要把目标武器当成参数传过来");
+            ChangeState(prev);
+            return;
+        }
+
+        SetTargetWeapon((Weapon)args[0]);
+        _navigationUpdateTimer = 0;
+        _isInTailAfterRange = false;
+        _tailAfterTimer = 0;
+
+        //标记武器
+        _target.SetSign(SignNames.AiFindWeaponSign, Master);
+    }
+
+    public override void Process(float delta)
+    {
+        if (!Master.IsAllWeaponTotalAmmoEmpty()) //已经有弹药了
+        {
+            ChangeState(GetNextState());
+            return;
+        }
+
+        //更新目标位置
+        if (_navigationUpdateTimer <= 0)
+        {
+            //每隔一段时间秒更改目标位置
+            _navigationUpdateTimer = _navigationInterval;
+            var position = _target.GlobalPosition;
+            Master.NavigationAgent2D.TargetPosition = position;
+        }
+        else
+        {
+            _navigationUpdateTimer -= delta;
+        }
+
+        var playerPos = Player.Current.GetCenterPosition();
+        //枪口指向玩家
+        Master.LookTargetPosition(playerPos);
+
+        if (_target.IsDestroyed || _target.IsTotalAmmoEmpty()) //已经被销毁, 或者弹药已经被其他角色捡走
+        {
+            //再去寻找其他武器
+            SetTargetWeapon(Master.FindTargetWeapon());
+
+            if (_target == null) //也没有其他可用的武器了
+            {
+                ChangeState(GetNextState());
+            }
+        }
+        else if (_target.Master == Master) //已经被自己拾起
+        {
+            ChangeState(GetNextState());
+        }
+        else if (_target.Master != null) //武器已经被其他角色拾起!
+        {
+            //再去寻找其他武器
+            SetTargetWeapon(Master.FindTargetWeapon());
+
+            if (_target == null) //也没有其他可用的武器了
+            {
+                ChangeState(GetNextState());
+            }
+        }
+        else
+        {
+            //检测目标没有超出跟随视野距离
+            _isInTailAfterRange = Master.IsInTailAfterViewRange(playerPos);
+            if (_isInTailAfterRange)
+            {
+                _tailAfterTimer = 0;
+            }
+            else
+            {
+                _tailAfterTimer += delta;
+            }
+
+            //向武器移动
+            if (!Master.NavigationAgent2D.IsNavigationFinished())
+            {
+                //计算移动
+                var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+                Master.AnimatedSprite.Play(AnimatorNames.Run);
+                Master.BasisVelocity =
+                    (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+                    Master.RoleState.MoveSpeed;
+            }
+            else
+            {
+                Master.BasisVelocity = Vector2.Zero;
+            }
+        }
+    }
+
+    private AiStateEnum GetNextState()
+    {
+        return _tailAfterTimer > 10 ? AiStateEnum.AiNormal : AiStateEnum.AiTailAfter;
+    }
+
+    private void SetTargetWeapon(Weapon weapon)
+    {
+        _target = weapon;
+        //设置目标点
+        if (_target != null)
+        {
+            Master.NavigationAgent2D.TargetPosition = _target.GlobalPosition;
+        }
+    }
+    
+    public override void DebugDraw()
+    {
+        if (_target != null)
+        {
+            Master.DrawLine(Vector2.Zero, Master.ToLocal(_target.GlobalPosition), Colors.Purple);
+
+            if (_tailAfterTimer <= 0)
+            {
+                Master.DrawLine(Vector2.Zero, Master.ToLocal(Player.Current.GetCenterPosition()), Colors.Orange);
+            }
+            else if (_tailAfterTimer <= 10)
+            {
+                Master.DrawLine(Vector2.Zero, Master.ToLocal(Player.Current.GetCenterPosition()), Colors.Blue);
+            }
+            
+        }
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFollowUpState.cs
new file mode 100644
index 0000000..1e253ea
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiFollowUpState.cs
@@ -0,0 +1,126 @@
+
+using Godot;
+
+/// <summary>
+/// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火
+/// </summary>
+public class AiFollowUpState : StateBase<Enemy, AiStateEnum>
+{
+
+    /// <summary>
+    /// 目标是否在视野内
+    /// </summary>
+    public bool IsInView;
+
+    //导航目标点刷新计时器
+    private float _navigationUpdateTimer = 0;
+    private float _navigationInterval = 0.3f;
+
+    public AiFollowUpState() : base(AiStateEnum.AiFollowUp)
+    {
+    }
+
+    public override void Enter(AiStateEnum prev, params object[] args)
+    {
+        _navigationUpdateTimer = 0;
+        IsInView = true;
+    }
+
+    public override void Process(float delta)
+    {
+        //先检查弹药是否打光
+        if (Master.IsAllWeaponTotalAmmoEmpty())
+        {
+            //再寻找是否有可用的武器
+            var targetWeapon = Master.FindTargetWeapon();
+            if (targetWeapon != null)
+            {
+                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
+                return;
+            }
+            else
+            {
+                //切换到随机移动状态
+                ChangeState(AiStateEnum.AiSurround);
+            }
+        }
+
+        var playerPos = Player.Current.GetCenterPosition();
+
+        //更新玩家位置
+        if (_navigationUpdateTimer <= 0)
+        {
+            //每隔一段时间秒更改目标位置
+            _navigationUpdateTimer = _navigationInterval;
+            Master.NavigationAgent2D.TargetPosition = playerPos;
+        }
+        else
+        {
+            _navigationUpdateTimer -= delta;
+        }
+
+        var masterPosition = Master.GlobalPosition;
+
+        //是否在攻击范围内
+        var inAttackRange = false;
+
+        var weapon = Master.Holster.ActiveWeapon;
+        if (weapon != null)
+        {
+            inAttackRange = masterPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(Master.GetWeaponRange(0.7f), 2);
+        }
+
+        //枪口指向玩家
+        Master.LookTargetPosition(playerPos);
+        
+        if (!Master.NavigationAgent2D.IsNavigationFinished())
+        {
+            //计算移动
+            var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+            Master.AnimatedSprite.Play(AnimatorNames.Run);
+            Master.BasisVelocity = (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() *
+                              Master.RoleState.MoveSpeed;
+        }
+        else
+        {
+            Master.BasisVelocity = Vector2.Zero;
+        }
+
+        //检测玩家是否在视野内
+        if (Master.IsInTailAfterViewRange(playerPos))
+        {
+            IsInView = !Master.TestViewRayCast(playerPos);
+            //关闭射线检测
+            Master.TestViewRayCastOver();
+        }
+        else
+        {
+            IsInView = false;
+        }
+
+        if (IsInView)
+        {
+            if (inAttackRange) //在攻击范围内
+            {
+                //发起攻击
+                Master.EnemyAttack(delta);
+                
+                //距离够近, 可以切换到环绕模式
+                if (Master.GlobalPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(weapon.Attribute.BulletMinDistance, 2) * 0.7f)
+                {
+                    ChangeState(AiStateEnum.AiSurround);
+                }
+            }
+        }
+        else
+        {
+            ChangeState(AiStateEnum.AiTailAfter);
+        }
+    }
+
+    public override void DebugDraw()
+    {
+        var playerPos = Player.Current.GetCenterPosition();
+        Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Red);
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiLeaveForState.cs
new file mode 100644
index 0000000..bb1c761
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiLeaveForState.cs
@@ -0,0 +1,101 @@
+
+using Godot;
+
+/// <summary>
+/// 收到其他敌人通知, 前往发现目标的位置
+/// </summary>
+public class AiLeaveForState : StateBase<Enemy, AiStateEnum>
+{
+    //导航目标点刷新计时器
+    private float _navigationUpdateTimer = 0;
+    private float _navigationInterval = 0.3f;
+
+    public AiLeaveForState() : base(AiStateEnum.AiLeaveFor)
+    {
+    }
+
+    public override void Enter(AiStateEnum prev, params object[] args)
+    {
+        if (Master.World.Enemy_IsFindTarget)
+        {
+            Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
+        }
+        else
+        {
+            ChangeState(prev);
+            return;
+        }
+
+        //先检查弹药是否打光
+        if (Master.IsAllWeaponTotalAmmoEmpty())
+        {
+            //再寻找是否有可用的武器
+            var targetWeapon = Master.FindTargetWeapon();
+            if (targetWeapon != null)
+            {
+                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
+            }
+        }
+    }
+
+    public override void Process(float delta)
+    {
+        //这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
+        
+        //更新玩家位置
+        if (_navigationUpdateTimer <= 0)
+        {
+            //每隔一段时间秒更改目标位置
+            _navigationUpdateTimer = _navigationInterval;
+            Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
+        }
+        else
+        {
+            _navigationUpdateTimer -= delta;
+        }
+
+        if (!Master.NavigationAgent2D.IsNavigationFinished())
+        {
+            //计算移动
+            var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+            Master.LookTargetPosition(Master.World.Enemy_FindTargetPosition);
+            Master.AnimatedSprite.Play(AnimatorNames.Run);
+            Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+                              Master.RoleState.MoveSpeed;
+        }
+        else
+        {
+            Master.BasisVelocity = Vector2.Zero;
+        }
+
+        var playerPos = Player.Current.GetCenterPosition();
+        //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
+        if (Master.IsInTailAfterViewRange(playerPos))
+        {
+            if (!Master.TestViewRayCast(playerPos)) //看到玩家
+            {
+                //关闭射线检测
+                Master.TestViewRayCastOver();
+                //切换成发现目标状态
+                ChangeState(AiStateEnum.AiFollowUp);
+                return;
+            }
+            else
+            {
+                //关闭射线检测
+                Master.TestViewRayCastOver();
+            }
+        }
+
+        //移动到目标掉了, 还没发现目标
+        if (Master.NavigationAgent2D.IsNavigationFinished())
+        {
+            ChangeState(AiStateEnum.AiNormal);
+        }
+    }
+
+    public override void DebugDraw()
+    {
+        Master.DrawLine(Vector2.Zero, Master.ToLocal(Master.NavigationAgent2D.TargetPosition), Colors.Yellow);
+    }
+}
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiNormalState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiNormalState.cs
new file mode 100644
index 0000000..20cad58
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiNormalState.cs
@@ -0,0 +1,181 @@
+
+using Godot;
+
+/// <summary>
+/// AI 正常状态
+/// </summary>
+public class AiNormalState : StateBase<Enemy, AiStateEnum>
+{
+    //是否发现玩家
+    private bool _isFindPlayer;
+
+    //下一个运动的角度
+    private Vector2 _nextPos;
+
+    //是否移动结束
+    private bool _isMoveOver;
+
+    //上一次移动是否撞墙
+    private bool _againstWall;
+    
+    //撞墙法线角度
+    private float _againstWallNormalAngle;
+
+    //移动停顿计时器
+    private float _pauseTimer;
+    private bool _moveFlag;
+
+    //上一帧位置
+    private Vector2 _prevPos;
+    //卡在一个位置的时间
+    private float _lockTimer;
+
+    public AiNormalState() : base(AiStateEnum.AiNormal)
+    {
+    }
+
+    public override void Enter(AiStateEnum prev, params object[] args)
+    {
+        _isFindPlayer = false;
+        _isMoveOver = true;
+        _againstWall = false;
+        _againstWallNormalAngle = 0;
+        _pauseTimer = 0;
+        _moveFlag = false;
+    }
+
+    public override void Process(float delta)
+    {
+        //其他敌人发现玩家
+        if (Master.CanChangeLeaveFor())
+        {
+            ChangeState(AiStateEnum.AiLeaveFor);
+            return;
+        }
+
+        if (_isFindPlayer) //已经找到玩家了
+        {
+            //现临时处理, 直接切换状态
+            ChangeState(AiStateEnum.AiTailAfter);
+        }
+        else //没有找到玩家
+        {
+            //检测玩家
+            var player = Player.Current;
+            //玩家中心点坐标
+            var playerPos = player.GetCenterPosition();
+
+            if (Master.IsInViewRange(playerPos) && !Master.TestViewRayCast(playerPos)) //发现玩家
+            {
+                //发现玩家
+                _isFindPlayer = true;
+            }
+            else if (_pauseTimer >= 0)
+            {
+                Master.AnimatedSprite.Play(AnimatorNames.Idle);
+                _pauseTimer -= delta;
+            }
+            else if (_isMoveOver) //没发现玩家, 且已经移动完成
+            {
+                RunOver();
+                _isMoveOver = false;
+            }
+            else //移动中
+            {
+                if (_lockTimer >= 1) //卡在一个点超过一秒
+                {
+                    RunOver();
+                    _isMoveOver = false;
+                    _lockTimer = 0;
+                }
+                else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
+                {
+                    _pauseTimer = Utils.RandomRangeFloat(0.3f, 2f);
+                    _isMoveOver = true;
+                    _moveFlag = false;
+                    Master.BasisVelocity = Vector2.Zero;
+                }
+                else if (!_moveFlag)
+                {
+                    _moveFlag = true;
+                    var pos = Master.GlobalPosition;
+                    //计算移动
+                    var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+                    Master.AnimatedSprite.Play(AnimatorNames.Run);
+                    Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
+                                           Master.RoleState.MoveSpeed;
+                    _prevPos = pos;
+                }
+                else
+                {
+                    var pos = Master.GlobalPosition;
+                    var lastSlideCollision = Master.GetLastSlideCollision();
+                    if (lastSlideCollision != null && lastSlideCollision.GetCollider() is Role) //碰到其他角色
+                    {
+                        _pauseTimer = Utils.RandomRangeFloat(0.1f, 0.5f);
+                        _isMoveOver = true;
+                        _moveFlag = false;
+                        Master.BasisVelocity = Vector2.Zero;
+                    }
+                    else
+                    {
+                        //计算移动
+                        var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+                        Master.AnimatedSprite.Play(AnimatorNames.Run);
+                        Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
+                                               Master.RoleState.MoveSpeed;
+                    }
+
+                    if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
+                    {
+                        _lockTimer += delta;
+                    }
+                    else
+                    {
+                        _prevPos = pos;
+                    }
+                }
+            }
+
+            //关闭射线检测
+            Master.TestViewRayCastOver();
+        }
+    }
+
+    //移动结束
+    private void RunOver()
+    {
+        float angle;
+        if (_againstWall)
+        {
+            angle = Utils.RandomRangeFloat(_againstWallNormalAngle - Mathf.Pi * 0.5f,
+                _againstWallNormalAngle + Mathf.Pi * 0.5f);
+        }
+        else
+        {
+            angle = Utils.RandomRangeFloat(0, Mathf.Pi * 2f);
+        }
+
+        var len = Utils.RandomRangeInt(30, 200);
+        _nextPos = new Vector2(len, 0).Rotated(angle) + Master.GlobalPosition;
+        //获取射线碰到的坐标
+        if (Master.TestViewRayCast(_nextPos)) //碰到墙壁
+        {
+            _nextPos = Master.ViewRay.GetCollisionPoint();
+            _againstWall = true;
+            _againstWallNormalAngle = Master.ViewRay.GetCollisionNormal().Angle();
+        }
+        else
+        {
+            _againstWall = false;
+        }
+
+        Master.NavigationAgent2D.TargetPosition = _nextPos;
+        Master.LookTargetPosition(_nextPos);
+    }
+
+    public override void DebugDraw()
+    {
+        Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPos), Colors.Green);
+    }
+}
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiProbeState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiProbeState.cs
new file mode 100644
index 0000000..1015095
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiProbeState.cs
@@ -0,0 +1,20 @@
+
+/// <summary>
+/// Ai 不确定玩家位置
+/// </summary>
+public class AiProbeState : StateBase<Enemy, AiStateEnum>
+{
+    public AiProbeState() : base(AiStateEnum.AiProbe)
+    {
+    }
+
+    public override void Process(float delta)
+    {
+        //其他敌人发现玩家
+        if (Master.CanChangeLeaveFor())
+        {
+            ChangeState(AiStateEnum.AiLeaveFor);
+            return;
+        }
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiSurroundState.cs
new file mode 100644
index 0000000..9a4c90e
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiSurroundState.cs
@@ -0,0 +1,176 @@
+
+using Godot;
+
+/// <summary>
+/// 距离目标足够近, 在目标附近随机移动, 并开火
+/// </summary>
+public class AiSurroundState : StateBase<Enemy, AiStateEnum>
+{
+    /// <summary>
+    /// 目标是否在视野内
+    /// </summary>
+    public bool IsInView = true;
+
+    //是否移动结束
+    private bool _isMoveOver;
+
+    //移动停顿计时器
+    private float _pauseTimer;
+    private bool _moveFlag;
+    
+    //下一个移动点
+    private Vector2 _nextPosition;
+    
+    //上一帧位置
+    private Vector2 _prevPos;
+    //卡在一个位置的时间
+    private float _lockTimer;
+
+    public AiSurroundState() : base(AiStateEnum.AiSurround)
+    {
+    }
+
+    public override void Enter(AiStateEnum prev, params object[] args)
+    {
+        IsInView = true;
+        _isMoveOver = true;
+        _pauseTimer = 0;
+        _moveFlag = false;
+    }
+
+    public override void Process(float delta)
+    {
+        //先检查弹药是否打光
+        if (Master.IsAllWeaponTotalAmmoEmpty())
+        {
+            //再寻找是否有可用的武器
+            var targetWeapon = Master.FindTargetWeapon();
+            if (targetWeapon != null)
+            {
+                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
+                return;
+            }
+        }
+
+        var playerPos = Player.Current.GetCenterPosition();
+        var weapon = Master.Holster.ActiveWeapon;
+
+        //枪口指向玩家
+        Master.LookTargetPosition(playerPos);
+
+        //检测玩家是否在视野内
+        if (Master.IsInTailAfterViewRange(playerPos))
+        {
+            IsInView = !Master.TestViewRayCast(playerPos);
+            //关闭射线检测
+            Master.TestViewRayCastOver();
+        }
+        else
+        {
+            IsInView = false;
+        }
+
+        if (IsInView)
+        {
+            if (_pauseTimer >= 0)
+            {
+                Master.AnimatedSprite.Play(AnimatorNames.Idle);
+                _pauseTimer -= delta;
+            }
+            else if (_isMoveOver) //移动已经完成
+            {
+                RunOver(playerPos);
+                _isMoveOver = false;
+            }
+            else
+            {
+                if (_lockTimer >= 1) //卡在一个点超过一秒
+                {
+                    RunOver(playerPos);
+                    _isMoveOver = false;
+                    _lockTimer = 0;
+                }
+                else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
+                {
+                    _pauseTimer = Utils.RandomRangeFloat(0f, 0.5f);
+                    _isMoveOver = true;
+                    _moveFlag = false;
+                    Master.BasisVelocity = Vector2.Zero;
+                }
+                else if (!_moveFlag)
+                {
+                    _moveFlag = true;
+                    //计算移动
+                    var pos = Master.GlobalPosition;
+                    var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+                    Master.AnimatedSprite.Play(AnimatorNames.Run);
+                    Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+                                           Master.RoleState.MoveSpeed;
+                }
+                else
+                {
+                    var pos = Master.GlobalPosition;
+                    var lastSlideCollision = Master.GetLastSlideCollision();
+                    if (lastSlideCollision != null && lastSlideCollision.GetCollider() is Role) //碰到其他角色
+                    {
+                        _pauseTimer = Utils.RandomRangeFloat(0f, 0.3f);
+                        _isMoveOver = true;
+                        _moveFlag = false;
+                        Master.BasisVelocity = Vector2.Zero;
+                    }
+                    else
+                    {
+                        //计算移动
+                        var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+                        Master.AnimatedSprite.Play(AnimatorNames.Run);
+                        Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
+                                               Master.RoleState.MoveSpeed;
+                    }
+                    
+                    if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
+                    {
+                        _lockTimer += delta;
+                    }
+                    else
+                    {
+                        _prevPos = pos;
+                    }
+                }
+
+                if (weapon != null)
+                {
+                    var position = Master.GlobalPosition;
+                    if (position.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围
+                    {
+                        ChangeState(AiStateEnum.AiFollowUp);
+                    }
+                    else
+                    {
+                        //发起攻击
+                        Master.EnemyAttack(delta);
+                    }
+                }
+            }
+        }
+        else //目标离开视野
+        {
+            ChangeState(AiStateEnum.AiTailAfter);
+        }
+    }
+
+    private void RunOver(Vector2 targetPos)
+    {
+        var weapon = Master.Holster.ActiveWeapon;
+        var distance = (int)(weapon == null ? 150 : (weapon.Attribute.BulletMinDistance * 0.7f));
+        _nextPosition = new Vector2(
+            targetPos.X + Utils.RandomRangeInt(-distance, distance),
+            targetPos.Y + Utils.RandomRangeInt(-distance, distance)
+        );
+        Master.NavigationAgent2D.TargetPosition = _nextPosition;
+    }
+
+    public override void DebugDraw()
+    {
+        Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPosition), Colors.White);
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiTailAfterState.cs
new file mode 100644
index 0000000..455e4ae
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/state/AiTailAfterState.cs
@@ -0,0 +1,125 @@
+
+using Godot;
+
+/// <summary>
+/// AI 发现玩家, 跟随玩家
+/// </summary>
+public class AiTailAfterState : StateBase<Enemy, AiStateEnum>
+{
+    /// <summary>
+    /// 目标是否在视野半径内
+    /// </summary>
+    private bool _isInViewRange;
+
+    //导航目标点刷新计时器
+    private float _navigationUpdateTimer = 0;
+    private float _navigationInterval = 0.3f;
+
+    //目标从视野消失时已经过去的时间
+    private float _viewTimer;
+
+    public AiTailAfterState() : base(AiStateEnum.AiTailAfter)
+    {
+    }
+
+    public override void Enter(AiStateEnum prev, params object[] args)
+    {
+        _isInViewRange = true;
+        _navigationUpdateTimer = 0;
+        _viewTimer = 0;
+        
+        //先检查弹药是否打光
+        if (Master.IsAllWeaponTotalAmmoEmpty())
+        {
+            //再寻找是否有可用的武器
+            var targetWeapon = Master.FindTargetWeapon();
+            if (targetWeapon != null)
+            {
+                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
+            }
+        }
+    }
+    
+    public override void Process(float delta)
+    {
+        //这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
+        
+        var playerPos = Player.Current.GetCenterPosition();
+        
+        //更新玩家位置
+        if (_navigationUpdateTimer <= 0)
+        {
+            //每隔一段时间秒更改目标位置
+            _navigationUpdateTimer = _navigationInterval;
+            Master.NavigationAgent2D.TargetPosition = playerPos;
+        }
+        else
+        {
+            _navigationUpdateTimer -= delta;
+        }
+        
+        //枪口指向玩家
+        Master.LookTargetPosition(playerPos);
+        
+        if (!Master.NavigationAgent2D.IsNavigationFinished())
+        {
+            //计算移动
+            var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
+            Master.AnimatedSprite.Play(AnimatorNames.Run);
+            Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
+                              Master.RoleState.MoveSpeed;
+        }
+        else
+        {
+            Master.BasisVelocity = Vector2.Zero;
+        }
+        //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
+        if (Master.IsInTailAfterViewRange(playerPos))
+        {
+            if (!Master.TestViewRayCast(playerPos)) //看到玩家
+            {
+                //关闭射线检测
+                Master.TestViewRayCastOver();
+                //切换成发现目标状态
+                ChangeState(AiStateEnum.AiFollowUp);
+                return;
+            }
+            else
+            {
+                //关闭射线检测
+                Master.TestViewRayCastOver();
+            }
+        }
+        
+        //检测玩家是否在穿墙视野范围内, 直接检测距离即可
+        _isInViewRange = Master.IsInViewRange(playerPos);
+        if (_isInViewRange)
+        {
+            _viewTimer = 0;
+        }
+        else //超出视野
+        {
+            if (_viewTimer > 10) //10秒
+            {
+                ChangeState(AiStateEnum.AiNormal);
+            }
+            else
+            {
+                _viewTimer += delta;
+            }
+        }
+    }
+
+    public override void DebugDraw()
+    {
+        var playerPos = Player.Current.GetCenterPosition();
+        if (_isInViewRange)
+        {
+            Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Orange);
+        }
+        else
+        {
+            Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Blue);
+        }
+    }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
index 4cae2a7..a2541d1 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
@@ -246,7 +246,7 @@
     
     public override void OnInit()
     {
-        InitWeapon(_GetWeaponAttribute(ItemId));
+        InitWeapon(_GetWeaponAttribute(ItemConfig.Id));
         AnimatedSprite.AnimationFinished += OnAnimationFinished;
     }
 
@@ -269,7 +269,7 @@
         if (Attribute.AmmoCapacity > Attribute.MaxAmmoCapacity)
         {
             Attribute.AmmoCapacity = Attribute.MaxAmmoCapacity;
-            GD.PrintErr("弹夹的容量不能超过弹药上限, 武器id: " + ItemId);
+            GD.PrintErr("弹夹的容量不能超过弹药上限, 武器id: " + ItemConfig.Id);
         }
         //弹药量
         CurrAmmo = Attribute.AmmoCapacity;
@@ -366,7 +366,8 @@
     /// <summary>
     /// 当武器从武器袋中移除时调用
     /// </summary>
-    protected virtual void OnRemove()
+    /// <param name="master">移除该武器的角色</param>
+    protected virtual void OnRemove(Role master)
     {
     }
 
@@ -1387,7 +1388,7 @@
             {
                 var masterWeapon = roleMaster.Holster.ActiveWeapon;
                 //查找是否有同类型武器
-                var index = roleMaster.Holster.FindWeapon(ItemId);
+                var index = roleMaster.Holster.FindWeapon(ItemConfig.Id);
                 if (index != -1) //如果有这个武器
                 {
                     if (CurrAmmo + ResidueAmmo != 0) //子弹不为空
@@ -1434,7 +1435,7 @@
         {
             var holster = roleMaster.Holster;
             //查找是否有同类型武器
-            var index = holster.FindWeapon(ItemId);
+            var index = holster.FindWeapon(ItemConfig.Id);
             if (index != -1) //如果有这个武器
             {
                 if (CurrAmmo + ResidueAmmo == 0) //没有子弹了
@@ -1582,13 +1583,14 @@
     /// </summary>
     public void RemoveAt()
     {
+        var master = Master;
         Master = null;
         CollisionLayer = _tempLayer;
         _weaponAttribute = _playerWeaponAttribute;
         AnimatedSprite.Position = _tempAnimatedSpritePosition;
         //清除 Ai 拾起标记
         RemoveSign(SignNames.AiFindWeaponSign);
-        OnRemove();
+        OnRemove(master);
     }
 
     /// <summary>
diff --git a/DungeonShooting_Godot/src/game/buff/RoleState.cs b/DungeonShooting_Godot/src/game/buff/RoleState.cs
deleted file mode 100644
index 53bcff3..0000000
--- a/DungeonShooting_Godot/src/game/buff/RoleState.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-
-/// <summary>
-/// 角色属性类
-/// </summary>
-public class RoleState
-{
-    /// <summary>
-    /// 移动速度
-    /// </summary>
-    public float MoveSpeed;
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/manager/ActivityIdPrefix.cs b/DungeonShooting_Godot/src/game/manager/ActivityIdPrefix.cs
index c2edfc4..6c3d949 100644
--- a/DungeonShooting_Godot/src/game/manager/ActivityIdPrefix.cs
+++ b/DungeonShooting_Godot/src/game/manager/ActivityIdPrefix.cs
@@ -41,9 +41,13 @@
         /// </summary>
         Effect,
         /// <summary>
+        /// 道具
+        /// </summary>
+        Prop,
+        /// <summary>
         /// 其它类型
         /// </summary>
-        Other,
+        Other = 99,
     }
     
     /// <summary>
@@ -75,6 +79,10 @@
     /// </summary>
     public const string Effect = "effect";
     /// <summary>
+    /// 道具
+    /// </summary>
+    public const string Prop = "prop";
+    /// <summary>
     /// 其他类型
     /// </summary>
     public const string Other = "other";
@@ -103,6 +111,8 @@
                 return Shell;
             case ActivityPrefixType.Effect:
                 return Effect;
+            case ActivityPrefixType.Prop:
+                return Prop;
             case ActivityPrefixType.Other:
                 return Other;
         }
diff --git a/DungeonShooting_Godot/src/game/role/CampEnum.cs b/DungeonShooting_Godot/src/game/role/CampEnum.cs
deleted file mode 100644
index 6954070..0000000
--- a/DungeonShooting_Godot/src/game/role/CampEnum.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-
-public enum CampEnum
-{
-    // 阵营1, 玩家
-    Camp1,
-    // 阵营2, 敌人
-    Camp2,
-    // 阵营3, 中立单位
-    Camp3
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/Characters/CPlusPlus.cs b/DungeonShooting_Godot/src/game/role/Characters/CPlusPlus.cs
deleted file mode 100644
index 00e5353..0000000
--- a/DungeonShooting_Godot/src/game/role/Characters/CPlusPlus.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-#region 设计思路
-// c/c++ 
-// 被动:易于精通   随着刷的房间的增多 提升对于 道具的加成 增加攻击力 或者 增强对应效果
-// 
-// 速度:中偏上
-// 血量:中
-// 护盾:下
-// 
-// 专属武器:指针  近战武器  
-// 武器描述:短按 向目标方向 刺出 对路径中的 敌人或可破坏建筑 造成伤害 
-//          长按 1.8 秒 向目标方向 冲刺 并消除 途中的弹幕 蓄力过程会被打断 打断后强制取消攻击
-// 
-// 
-// 每个角色都应该有对应的被动  属性 专属武器 
-#endregion
-
-public partial class CPlusPlus : Player
-{
-
-
-    public override void OnInit()
-    {
-        base.OnInit();
-        #region 初始属性
-
-        MaxHp = 55;
-        MoveSpeed = 130f;
-        #endregion
-    }
-
-    // public CPlusPlus() : base(ResourcePath.prefab_role_CPlusPlus_tscn)
-    // {
-
-    // }
-
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/FaceDirection.cs b/DungeonShooting_Godot/src/game/role/FaceDirection.cs
deleted file mode 100644
index 5be28ef..0000000
--- a/DungeonShooting_Godot/src/game/role/FaceDirection.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-/// <summary>
-/// 脸的朝向
-/// </summary>
-public enum FaceDirection
-{
-    Left = -1,
-    Right = 1,
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/MountRotation.cs b/DungeonShooting_Godot/src/game/role/MountRotation.cs
deleted file mode 100644
index e265b10..0000000
--- a/DungeonShooting_Godot/src/game/role/MountRotation.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-
-using Godot;
-
-/// <summary>
-/// 用于限定 Marker2D 节点的旋转角度
-/// </summary>
-[Tool]
-public partial class MountRotation : Marker2D
-{
-    /// <summary>
-    /// 吸附角度
-    /// </summary>
-    private int _adsorption = 6;
-    
-    /// <summary>
-    /// 所在的角色
-    /// </summary>
-    public Role Master { get; set; }
-
-    /// <summary>
-    /// 当前节点真实的旋转角度, 角度制
-    /// </summary>
-    public float RealRotationDegrees { get; private set; }
-    
-    /// <summary>
-    /// 当前节点真实的旋转角度, 弧度制
-    /// </summary>
-    public float RealRotation => Mathf.DegToRad(RealRotationDegrees);
-
-    /// <summary>
-    /// 设置看向的目标点
-    /// </summary>
-    public void SetLookAt(Vector2 target)
-    {
-        var myPos = GlobalPosition;
-        var angle = Mathf.RadToDeg((target - myPos).Angle());
-
-        if (Master.Face == FaceDirection.Left)
-        {
-            if (angle < 0 && angle > -80)
-            {
-                angle = -80;
-            }
-            else if (angle >= 0 && angle < 80)
-            {
-                angle = 80;
-            }
-        }
-        else
-        {
-            angle = Mathf.Clamp(angle, -100, 100);
-        }
-
-        RealRotationDegrees = angle;
-
-        // if (Master.GlobalPosition.X >= target.X)
-        // {
-        //     angle = -angle;
-        // }
-        GlobalRotationDegrees = AdsorptionAngle(angle);
-    }
-
-    private float AdsorptionAngle(float angle)
-    {
-        return Mathf.Round(angle / _adsorption) * _adsorption;
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/Player.cs b/DungeonShooting_Godot/src/game/role/Player.cs
deleted file mode 100644
index cb58fc9..0000000
--- a/DungeonShooting_Godot/src/game/role/Player.cs
+++ /dev/null
@@ -1,249 +0,0 @@
-using Godot;
-
-
-/// <summary>
-/// 玩家角色基类, 所有角色都必须继承该类
-/// </summary>
-[Tool, GlobalClass]
-public partial class Player : Role
-{
-    /// <summary>
-    /// 获取当前操作的角色
-    /// </summary>
-    public static Player Current { get; private set; }
-    
-    /// <summary>
-    /// 移动加速度
-    /// </summary>
-    public float Acceleration { get; set; } = 1500f;
-    
-    /// <summary>
-    /// 移动摩擦力
-    /// </summary>
-    public float Friction { get; set; } = 800f;
-
-    /// <summary>
-    /// 设置当前操作的玩家对象
-    /// </summary>
-    public static void SetCurrentPlayer(Player player)
-    {
-        Current = player;
-        //设置相机和鼠标跟随玩家
-        GameCamera.Main.SetFollowTarget(player);
-        GameApplication.Instance.Cursor.SetMountRole(player);
-    }
-    
-    public override void OnInit()
-    {
-        base.OnInit();
-        
-        AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Props | PhysicsLayer.Enemy;
-        Camp = CampEnum.Camp1;
-
-        //让相机跟随玩家
-        // var remoteTransform = new RemoteTransform2D();
-        // AddChild(remoteTransform);
-        // MainCamera.Main.GlobalPosition = GlobalPosition;
-        // MainCamera.Main.ResetSmoothing();
-        // remoteTransform.RemotePath = remoteTransform.GetPathTo(MainCamera.Main);
-
-        MaxHp = 6;
-        Hp = 6;
-        MaxShield = 2;
-        Shield = 2;
-
-        // debug用
-        // Acceleration = 3000;
-        // Friction = 3000;
-        // MoveSpeed = 500;
-        // CollisionLayer = 0;
-        // CollisionMask = 0;
-        // GameCamera.Main.Zoom = new Vector2(0.5f, 0.5f);
-    }
-
-    protected override void Process(float delta)
-    {
-        if (IsDie)
-        {
-            return;
-        }
-        base.Process(delta);
-        //脸的朝向
-        if (LookTarget == null)
-        {
-            var gPos = GlobalPosition;
-            Vector2 mousePos = InputManager.CursorPosition;
-            if (mousePos.X > gPos.X && Face == FaceDirection.Left)
-            {
-                Face = FaceDirection.Right;
-            }
-            else if (mousePos.X < gPos.X && Face == FaceDirection.Right)
-            {
-                Face = FaceDirection.Left;
-            }
-            //枪口跟随鼠标
-            MountPoint.SetLookAt(mousePos);
-        }
-
-        if (InputManager.Exchange) //切换武器
-        {
-            ExchangeNext();
-        }
-        else if (InputManager.Throw) //扔掉武器
-        {
-            ThrowWeapon();
-
-            // //测试用的, 所有敌人也扔掉武器
-            // if (Affiliation != null)
-            // {
-            //     var enemies = Affiliation.FindIncludeItems(o =>
-            //     {
-            //         return o.CollisionWithMask(PhysicsLayer.Enemy);
-            //     });
-            //     foreach (var activityObject in enemies)
-            //     {
-            //         if (activityObject is Enemy enemy)
-            //         {
-            //             enemy.ThrowWeapon();
-            //         }
-            //     }
-            // }
-        }
-        else if (InputManager.Interactive) //互动物体
-        {
-            TriggerInteractive();
-        }
-        else if (InputManager.Reload) //换弹
-        {
-            Reload();
-        }
-        if (InputManager.Fire) //开火
-        {
-            Attack();
-        }
-
-        if (Input.IsKeyPressed(Key.P))
-        {
-            Hurt(1000, 0);
-        }
-    }
-
-    protected override void PhysicsProcess(float delta)
-    {
-        if (IsDie)
-        {
-            return;
-        }
-
-        base.PhysicsProcess(delta);
-        HandleMoveInput(delta);
-        //播放动画
-        PlayAnim();
-    }
-
-    protected override int OnHandlerHurt(int damage)
-    {
-        //修改受到的伤害, 每次只受到1点伤害
-        return 1;
-    }
-
-    protected override void OnHit(int damage, bool realHarm)
-    {
-        //进入无敌状态
-        if (realHarm) //真实伤害
-        {
-            PlayInvincibleFlashing(1.5f);
-        }
-        else //护盾抵消掉的
-        {
-            PlayInvincibleFlashing(0.5f);
-        }
-    }
-
-    protected override void OnChangeHp(int hp)
-    {
-        //GameApplication.Instance.Ui.SetHp(hp);
-        EventManager.EmitEvent(EventEnum.OnPlayerHpChange, hp);
-    }
-
-    protected override void OnChangeMaxHp(int maxHp)
-    {
-        //GameApplication.Instance.Ui.SetMaxHp(maxHp);
-        EventManager.EmitEvent(EventEnum.OnPlayerMaxHpChange, maxHp);
-    }
-
-    protected override void ChangeInteractiveItem(CheckInteractiveResult result)
-    {
-        //派发互动对象改变事件
-        EventManager.EmitEvent(EventEnum.OnPlayerChangeInteractiveItem, result);
-    }
-
-    protected override void OnChangeShield(int shield)
-    {
-        //GameApplication.Instance.Ui.SetShield(shield);
-        EventManager.EmitEvent(EventEnum.OnPlayerShieldChange, shield);
-    }
-
-    protected override void OnChangeMaxShield(int maxShield)
-    {
-        //GameApplication.Instance.Ui.SetMaxShield(maxShield);
-        EventManager.EmitEvent(EventEnum.OnPlayerMaxShieldChange, maxShield);
-    }
-
-    protected override void OnDie()
-    {
-        GameCamera.Main.SetFollowTarget(null);
-        BasisVelocity = Vector2.Zero;
-        MoveController.ClearForce();
-        UiManager.Open_Settlement();
-        //GameApplication.Instance.World.ProcessMode = ProcessModeEnum.WhenPaused;
-    }
-
-    //处理角色移动的输入
-    private void HandleMoveInput(float delta)
-    {
-        //角色移动
-        Vector2 dir = InputManager.MoveAxis;
-        // 移动. 如果移动的数值接近0(是用 摇杆可能出现 方向 可能会出现浮点),就friction的值 插值 到 0
-        // 如果 有输入 就以当前速度,用acceleration 插值到 对应方向 * 最大速度
-        if (Mathf.IsZeroApprox(dir.X))
-        {
-            BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, 0, Friction * delta), BasisVelocity.Y);
-        }
-        else
-        {
-            BasisVelocity = new Vector2(Mathf.MoveToward(BasisVelocity.X, dir.X * MoveSpeed, Acceleration * delta),
-                BasisVelocity.Y);
-        }
-
-        if (Mathf.IsZeroApprox(dir.Y))
-        {
-            BasisVelocity = new Vector2(BasisVelocity.X, Mathf.MoveToward(BasisVelocity.Y, 0, Friction * delta));
-        }
-        else
-        {
-            BasisVelocity = new Vector2(BasisVelocity.X,
-                Mathf.MoveToward(BasisVelocity.Y, dir.Y * MoveSpeed, Acceleration * delta));
-        }
-    }
-
-    // 播放动画
-    private void PlayAnim()
-    {
-        if (BasisVelocity != Vector2.Zero)
-        {
-            if ((Face == FaceDirection.Right && BasisVelocity.X >= 0) || Face == FaceDirection.Left && BasisVelocity.X <= 0) //向前走
-            {
-                AnimatedSprite.Play(AnimatorNames.Run);
-            }
-            else if ((Face == FaceDirection.Right && BasisVelocity.X < 0) || Face == FaceDirection.Left && BasisVelocity.X > 0) //向后走
-            {
-                AnimatedSprite.Play(AnimatorNames.ReverseRun);
-            }
-        }
-        else
-        {
-            AnimatedSprite.Play(AnimatorNames.Idle);
-        }
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/Role.cs b/DungeonShooting_Godot/src/game/role/Role.cs
deleted file mode 100644
index 10ebd64..0000000
--- a/DungeonShooting_Godot/src/game/role/Role.cs
+++ /dev/null
@@ -1,737 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using Godot;
-
-/// <summary>
-/// 角色基类
-/// </summary>
-public abstract partial class Role : ActivityObject
-{
-    /// <summary>
-    /// 是否是 Ai
-    /// </summary>
-    public bool IsAi { get; protected set; } = false;
-    
-    /// <summary>
-    /// 默认攻击对象层级
-    /// </summary>
-    public const uint DefaultAttackLayer = PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Wall | PhysicsLayer.Props;
-    
-    /// <summary>
-    /// 伤害区域
-    /// </summary>
-    [Export, ExportFillNode]
-    public Area2D HurtArea { get; set; }
-
-    /// <summary>
-    /// 移动速度
-    /// </summary>
-    public float MoveSpeed = 120f;
-
-    /// <summary>
-    /// 所属阵营
-    /// </summary>
-    public CampEnum Camp;
-
-    /// <summary>
-    /// 攻击目标的碰撞器所属层级, 数据源自于: PhysicsLayer
-    /// </summary>
-    public uint AttackLayer { get; set; } = PhysicsLayer.Wall;
-
-    // /// <summary>
-    // /// 携带的道具包裹
-    // /// </summary>
-    // public List<object> PropsPack { get; } = new List<object>();
-
-    /// <summary>
-    /// 角色携带的武器袋
-    /// </summary>
-    public Holster Holster { get; private set; }
-
-    /// <summary>
-    /// 武器挂载点
-    /// </summary>
-    [Export, ExportFillNode]
-    public MountRotation MountPoint { get; set; }
-    /// <summary>
-    /// 背后武器的挂载点
-    /// </summary>
-    [Export, ExportFillNode]
-    public Marker2D BackMountPoint { get; set; }
-
-    /// <summary>
-    /// 互动碰撞区域
-    /// </summary>
-    [Export, ExportFillNode]
-    public Area2D InteractiveArea { get; set; }
-    
-    /// <summary>
-    /// 脸的朝向
-    /// </summary>
-    public FaceDirection Face { get => _face; set => SetFace(value); }
-    private FaceDirection _face;
-
-    /// <summary>
-    /// 是否死亡
-    /// </summary>
-    public bool IsDie { get; private set; }
-    
-    /// <summary>
-    /// 血量
-    /// </summary>
-    public int Hp
-    {
-        get => _hp;
-        protected set
-        {
-            int temp = _hp;
-            _hp = value;
-            if (temp != _hp) OnChangeHp(_hp);
-        }
-    }
-    private int _hp = 20;
-
-    /// <summary>
-    /// 最大血量
-    /// </summary>
-    public int MaxHp
-    {
-        get => _maxHp;
-        protected set
-        {
-            int temp = _maxHp;
-            _maxHp = value;
-            //护盾值改变
-            if (temp != _maxHp) OnChangeMaxHp(_maxHp);
-        }
-    }
-    private int _maxHp = 20;
-    
-    /// <summary>
-    /// 当前护盾值
-    /// </summary>
-    public int Shield
-    {
-        get => _shield;
-        protected set
-        {
-            int temp = _shield;
-            _shield = value;
-            //护盾被破坏
-            if (temp > 0 && _shield <= 0) OnShieldDestroy();
-            //护盾值改变
-            if (temp != _shield) OnChangeShield(_shield);
-        }
-    }
-    private int _shield = 0;
-
-    /// <summary>
-    /// 最大护盾值
-    /// </summary>
-    public int MaxShield
-    {
-        get => _maxShield;
-        protected set
-        {
-            int temp = _maxShield;
-            _maxShield = value;
-            if (temp != _maxShield) OnChangeMaxShield(_maxShield);
-        }
-    }
-    private int _maxShield = 0;
-
-    /// <summary>
-    /// 单格护盾恢复时间
-    /// </summary>
-    private float ShieldRecoveryTime { get; set; } = 8;
-    
-    /// <summary>
-    /// 无敌状态
-    /// </summary>
-    public bool Invincible
-    {
-        get => _invincible;
-        set
-        {
-            if (_invincible != value)
-            {
-                if (value) //无敌状态
-                {
-                    HurtArea.CollisionLayer = _currentLayer;
-                    _flashingInvincibleTimer = -1;
-                    _flashingInvincibleFlag = false;
-                }
-                else //正常状态
-                {
-                    HurtArea.CollisionLayer = _currentLayer;
-                    SetBlendAlpha(1);
-                }
-            }
-
-            _invincible = value;
-        }
-    }
-
-    private bool _invincible = false;
-    
-    /// <summary>
-    /// 当前角色所看向的对象, 也就是枪口指向的对象
-    /// </summary>
-    public ActivityObject LookTarget { get; set; }
-
-    //初始缩放
-    private Vector2 _startScale;
-    //所有角色碰撞的道具
-    private readonly List<ActivityObject> _interactiveItemList = new List<ActivityObject>();
-
-    private CheckInteractiveResult _tempResultData;
-    private uint _currentLayer;
-    //闪烁计时器
-    private float _flashingInvincibleTimer = -1;
-    //闪烁状态
-    private bool _flashingInvincibleFlag = false;
-    //闪烁动画协程id
-    private long _invincibleFlashingId = -1;
-    //护盾恢复计时器
-    private float _shieldRecoveryTimer = 0;
-
-    /// <summary>
-    /// 可以互动的道具
-    /// </summary>
-    public ActivityObject InteractiveItem { get; private set; }
-
-    /// <summary>
-    /// 当血量改变时调用
-    /// </summary>
-    protected virtual void OnChangeHp(int hp)
-    {
-    }
-
-    /// <summary>
-    /// 当最大血量改变时调用
-    /// </summary>
-    protected virtual void OnChangeMaxHp(int maxHp)
-    {
-    }
-    
-    /// <summary>
-    /// 护盾值改变时调用
-    /// </summary>
-    protected virtual void OnChangeShield(int shield)
-    {
-    }
-
-    /// <summary>
-    /// 最大护盾值改变时调用
-    /// </summary>
-    protected virtual void OnChangeMaxShield(int maxShield)
-    {
-    }
-
-    /// <summary>
-    /// 当护盾被破坏时调用
-    /// </summary>
-    protected virtual void OnShieldDestroy()
-    {
-    }
-
-    /// <summary>
-    /// 当受伤时调用
-    /// </summary>
-    /// <param name="damage">受到的伤害</param>
-    /// <param name="realHarm">是否受到真实伤害, 如果为false, 则表示该伤害被互动格挡掉了</param>
-    protected virtual void OnHit(int damage, bool realHarm)
-    {
-    }
-
-    /// <summary>
-    /// 受到伤害时调用, 用于改变受到的伤害值
-    /// </summary>
-    /// <param name="damage">受到的伤害</param>
-    protected virtual int OnHandlerHurt(int damage)
-    {
-        return damage;
-    }
-    
-    /// <summary>
-    /// 当可互动的物体改变时调用, result 参数为 null 表示变为不可互动
-    /// </summary>
-    /// <param name="result">检测是否可互动时的返回值</param>
-    protected virtual void ChangeInteractiveItem(CheckInteractiveResult result)
-    {
-    }
-
-    /// <summary>
-    /// 死亡时调用
-    /// </summary>
-    protected virtual void OnDie()
-    {
-    }
-
-    public override void OnInit()
-    {
-        Holster = new Holster(this);
-        _startScale = Scale;
-        MountPoint.Master = this;
-        
-        HurtArea.CollisionLayer = CollisionLayer;
-        HurtArea.CollisionMask = 0;
-        _currentLayer = HurtArea.CollisionLayer;
-        
-        Face = FaceDirection.Right;
-        
-        //连接互动物体信号
-        InteractiveArea.BodyEntered += _OnPropsEnter;
-        InteractiveArea.BodyExited += _OnPropsExit;
-    }
-
-    protected override void Process(float delta)
-    {
-        //看向目标
-        if (LookTarget != null)
-        {
-            Vector2 pos = LookTarget.GlobalPosition;
-            //脸的朝向
-            var gPos = GlobalPosition;
-            if (pos.X > gPos.X && Face == FaceDirection.Left)
-            {
-                Face = FaceDirection.Right;
-            }
-            else if (pos.X < gPos.X && Face == FaceDirection.Right)
-            {
-                Face = FaceDirection.Left;
-            }
-            //枪口跟随目标
-            MountPoint.SetLookAt(pos);
-        }
-        
-        //检查可互动的道具
-        bool findFlag = false;
-        for (int i = 0; i < _interactiveItemList.Count; i++)
-        {
-            var item = _interactiveItemList[i];
-            if (item == null || item.IsDestroyed)
-            {
-                _interactiveItemList.RemoveAt(i--);
-            }
-            else
-            {
-                //找到可互动的道具了
-                if (!findFlag)
-                {
-                    var result = item.CheckInteractive(this);
-                    if (result.CanInteractive) //可以互动
-                    {
-                        findFlag = true;
-                        if (InteractiveItem != item) //更改互动物体
-                        {
-                            InteractiveItem = item;
-                            ChangeInteractiveItem(result);
-                        }
-                        else if (result.ShowIcon != _tempResultData.ShowIcon) //切换状态
-                        {
-                            ChangeInteractiveItem(result);
-                        }
-                    }
-                    _tempResultData = result;
-                }
-            }
-        }
-        //没有可互动的道具
-        if (!findFlag && InteractiveItem != null)
-        {
-            InteractiveItem = null;
-            ChangeInteractiveItem(null);
-        }
-
-        //无敌状态, 播放闪烁动画
-        if (Invincible)
-        {
-            _flashingInvincibleTimer -= delta;
-            if (_flashingInvincibleTimer <= 0)
-            {
-                _flashingInvincibleTimer = 0.15f;
-                if (_flashingInvincibleFlag)
-                {
-                    _flashingInvincibleFlag = false;
-                    SetBlendAlpha(0.7f);
-                }
-                else
-                {
-                    _flashingInvincibleFlag = true;
-                    SetBlendAlpha(0);
-                }
-            }
-
-            _shieldRecoveryTimer = 0;
-        }
-        else //恢复护盾
-        {
-            if (Shield < MaxShield)
-            {
-                _shieldRecoveryTimer += delta;
-                if (_shieldRecoveryTimer >= ShieldRecoveryTime) //时间到, 恢复
-                {
-                    Shield++;
-                    _shieldRecoveryTimer = 0;
-                }
-            }
-            else
-            {
-                _shieldRecoveryTimer = 0;
-            }
-        }
-    }
-
-    /// <summary>
-    /// 当武器放到后背时调用, 用于设置武器位置和角度
-    /// </summary>
-    /// <param name="weapon">武器实例</param>
-    /// <param name="index">放入武器袋的位置</param>
-    public virtual void OnPutBackMount(Weapon weapon, int index)
-    {
-        if (index < 8)
-        {
-            if (index % 2 == 0)
-            {
-                weapon.Position = new Vector2(-4, 3);
-                weapon.RotationDegrees = 90 - (index / 2f) * 20;
-                weapon.Scale = new Vector2(-1, 1);
-            }
-            else
-            {
-                weapon.Position = new Vector2(4, 3);
-                weapon.RotationDegrees = 270 + (index - 1) / 2f * 20;
-                weapon.Scale = new Vector2(1, 1);
-            }
-        }
-        else
-        {
-            weapon.Visible = false;
-        }
-    }
-    
-    protected override void OnAffiliationChange()
-    {
-        //身上的武器的所属区域也得跟着变
-        Holster.ForEach((weapon, i) =>
-        {
-            if (AffiliationArea != null)
-            {
-                AffiliationArea.InsertItem(weapon);
-            }
-            else if (weapon.AffiliationArea != null)
-            {
-                weapon.AffiliationArea.RemoveItem(weapon);
-            }
-        });
-    }
-
-    /// <summary>
-    /// 获取当前角色的中心点坐标
-    /// </summary>
-    public Vector2 GetCenterPosition()
-    {
-        return MountPoint.GlobalPosition;
-    }
-
-    /// <summary>
-    /// 使角色看向指定的坐标,
-    /// 注意, 调用该函数会清空 LookTarget, 因为拥有 LookTarget 时也会每帧更新玩家视野位置
-    /// </summary>
-    /// <param name="pos"></param>
-    public void LookTargetPosition(Vector2 pos)
-    {
-        LookTarget = null;
-        //脸的朝向
-        var gPos = GlobalPosition;
-        if (pos.X > gPos.X && Face == FaceDirection.Left)
-        {
-            Face = FaceDirection.Right;
-        }
-        else if (pos.X < gPos.X && Face == FaceDirection.Right)
-        {
-            Face = FaceDirection.Left;
-        }
-        //枪口跟随目标
-        MountPoint.SetLookAt(pos);
-    }
-    
-    /// <summary>
-    /// 判断指定坐标是否在角色视野方向
-    /// </summary>
-    public bool IsPositionInForward(Vector2 pos)
-    {
-        var gps = GlobalPosition;
-        return (Face == FaceDirection.Left && pos.X <= gps.X) ||
-               (Face == FaceDirection.Right && pos.X >= gps.X);
-    }
-
-    /// <summary>
-    /// 返回所有武器是否弹药都打光了
-    /// </summary>
-    public bool IsAllWeaponTotalAmmoEmpty()
-    {
-        foreach (var weapon in Holster.Weapons)
-        {
-            if (weapon != null && !weapon.IsTotalAmmoEmpty())
-            {
-                return false;
-            }
-        }
-
-        return true;
-    }
-    
-    /// <summary>
-    /// 拾起一个武器, 返回是否成功拾取, 如果不想立刻切换到该武器, exchange 请传 false
-    /// </summary>
-    /// <param name="weapon">武器对象</param>
-    /// <param name="exchange">是否立即切换到该武器, 默认 true </param>
-    public virtual bool PickUpWeapon(Weapon weapon, bool exchange = true)
-    {
-        if (Holster.PickupWeapon(weapon, exchange) != -1)
-        {
-            //从可互动队列中移除
-            _interactiveItemList.Remove(weapon);
-            return true;
-        }
-
-        return false;
-    }
-
-    /// <summary>
-    /// 切换到下一个武器
-    /// </summary>
-    public virtual void ExchangeNext()
-    {
-        Holster.ExchangeNext();
-    }
-
-    /// <summary>
-    /// 切换到上一个武器
-    /// </summary>
-    public virtual void ExchangePrev()
-    {
-        Holster.ExchangePrev();
-    }
-
-    /// <summary>
-    /// 扔掉当前使用的武器, 切换到上一个武器
-    /// </summary>
-    public virtual void ThrowWeapon()
-    {
-        ThrowWeapon(Holster.ActiveIndex);
-    }
-
-    /// <summary>
-    /// 扔掉指定位置的武器
-    /// </summary>
-    /// <param name="index">武器在武器袋中的位置</param>
-    public virtual void ThrowWeapon(int index)
-    {
-        var weapon = Holster.GetWeapon(index);
-        if (weapon == null)
-        {
-            return;
-        }
-
-        var temp = weapon.AnimatedSprite.Position;
-        if (Face == FaceDirection.Left)
-        {
-            temp.Y = -temp.Y;
-        }
-        //var pos = GlobalPosition + temp.Rotated(weapon.GlobalRotation);
-        Holster.RemoveWeapon(index);
-        //播放抛出效果
-        weapon.ThrowWeapon(this, GlobalPosition);
-    }
-
-    /// <summary>
-    /// 返回是否存在可互动的物体
-    /// </summary>
-    public bool HasInteractive()
-    {
-        return InteractiveItem != null;
-    }
-
-    /// <summary>
-    /// 触发与碰撞的物体互动, 并返回与其互动的物体
-    /// </summary>
-    public ActivityObject TriggerInteractive()
-    {
-        if (HasInteractive())
-        {
-            var item = InteractiveItem;
-            item.Interactive(this);
-            return item;
-        }
-
-        return null;
-    }
-
-    /// <summary>
-    /// 触发换弹
-    /// </summary>
-    public virtual void Reload()
-    {
-        if (Holster.ActiveWeapon != null)
-        {
-            Holster.ActiveWeapon.Reload();
-        }
-    }
-
-    /// <summary>
-    /// 触发攻击
-    /// </summary>
-    public virtual void Attack()
-    {
-        if (Holster.ActiveWeapon != null)
-        {
-            Holster.ActiveWeapon.Trigger();
-        }
-    }
-
-    /// <summary>
-    /// 受到伤害, 如果是在碰撞信号处理函数中调用该函数, 请使用 CallDeferred 来延时调用, 否则很有可能导致报错
-    /// </summary>
-    /// <param name="damage">伤害的量</param>
-    /// <param name="angle">角度</param>
-    public virtual void Hurt(int damage, float angle)
-    {
-        //受伤闪烁, 无敌状态
-        if (Invincible)
-        {
-            return;
-        }
-        
-        //计算真正受到的伤害
-        damage = OnHandlerHurt(damage);
-        if (damage <= 0)
-        {
-            return;
-        }
-
-        var flag = Shield > 0;
-        if (flag)
-        {
-            Shield -= damage;
-        }
-        else
-        {
-            Hp -= damage;
-            //播放血液效果
-            // var packedScene = ResourceManager.Load<PackedScene>(ResourcePath.prefab_effect_Blood_tscn);
-            // var blood = packedScene.Instance<Blood>();
-            // blood.GlobalPosition = GlobalPosition;
-            // blood.Rotation = angle;
-            // GameApplication.Instance.Node3D.GetRoot().AddChild(blood);
-        }
-        OnHit(damage, !flag);
-        
-        //受伤特效
-        PlayHitAnimation();
-        
-        //死亡判定
-        if (Hp <= 0)
-        {
-            //死亡
-            if (!IsDie)
-            {
-                IsDie = true;
-                OnDie();
-            }
-        }
-    }
-
-    /// <summary>
-    /// 播放无敌状态闪烁动画
-    /// </summary>
-    /// <param name="time">持续时间</param>
-    public void PlayInvincibleFlashing(float time)
-    {
-        Invincible = true;
-        if (_invincibleFlashingId >= 0) //上一个还没结束
-        {
-            StopCoroutine(_invincibleFlashingId);
-        }
-
-        _invincibleFlashingId = StartCoroutine(RunInvincibleFlashing(time));
-    }
-
-    /// <summary>
-    /// 停止无敌状态闪烁动画
-    /// </summary>
-    public void StopInvincibleFlashing()
-    {
-        Invincible = false;
-        if (_invincibleFlashingId >= 0)
-        {
-            StopCoroutine(_invincibleFlashingId);
-            _invincibleFlashingId = -1;
-        }
-    }
-
-    private IEnumerator RunInvincibleFlashing(float time)
-    {
-        yield return new WaitForSeconds(time);
-        _invincibleFlashingId = -1;
-        Invincible = false;
-    }
-
-    /// <summary>
-    /// 设置脸的朝向
-    /// </summary>
-    private void SetFace(FaceDirection face)
-    {
-        if (_face != face)
-        {
-            _face = face;
-            if (face == FaceDirection.Right)
-            {
-                RotationDegrees = 0;
-                Scale = _startScale;
-            }
-            else
-            {
-                RotationDegrees = 180;
-                Scale = new Vector2(_startScale.X, -_startScale.Y);
-            }
-        }
-    }
-    
-    /// <summary>
-    /// 连接信号: InteractiveArea.BodyEntered
-    /// 与物体碰撞
-    /// </summary>
-    private void _OnPropsEnter(Node2D other)
-    {
-        if (other is ActivityObject propObject && !propObject.CollisionWithMask(PhysicsLayer.OnHand))
-        {
-            if (!_interactiveItemList.Contains(propObject))
-            {
-                _interactiveItemList.Add(propObject);
-            }
-        }
-    }
-
-    /// <summary>
-    /// 连接信号: InteractiveArea.BodyExited
-    /// 物体离开碰撞区域
-    /// </summary>
-    private void _OnPropsExit(Node2D other)
-    {
-        if (other is ActivityObject propObject)
-        {
-            if (_interactiveItemList.Contains(propObject))
-            {
-                _interactiveItemList.Remove(propObject);
-            }
-            if (InteractiveItem == propObject)
-            {
-                InteractiveItem = null;
-                ChangeInteractiveItem(null);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
deleted file mode 100644
index c28da7e..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
+++ /dev/null
@@ -1,459 +0,0 @@
-#region 基础敌人设计思路
-/*
-敌人有三种状态: 
-状态1: 未发现玩家, 视野不可穿墙, 该状态下敌人移动比较规律, 移动速度较慢, 一旦玩家进入视野或者听到玩家枪声, 立刻切换至状态3, 该房间的敌人不能再回到状态1
-状态2: 发现有玩家, 但不知道在哪, 视野不可穿墙, 该情况下敌人移动速度明显加快, 移动不规律, 一旦玩家进入视野或者听到玩家枪声, 立刻切换至状态3
-状态3: 明确知道玩家的位置, 视野允许穿墙, 移动速度与状态2一致, 进入该状态时, 敌人之间会相互告知玩家所在位置, 并朝着玩家位置开火,
-       如果有墙格挡, 则有一定概率继续开火, 一旦玩家立刻敌人视野超哥一段时间, 敌人自动切换为状态2
-
-敌人状态1只存在于少数房间内, 比如特殊房间, 大部分情况下敌人应该是状态2, 或者玩家进入房间时就被敌人发现
-*/
-#endregion
-
-
-using Godot;
-
-/// <summary>
-/// 基础敌人
-/// </summary>
-[Tool, GlobalClass]
-public partial class Enemy : Role
-{
-    /// <summary>
-    /// 敌人身上的状态机控制器
-    /// </summary>
-    public StateController<Enemy, AiStateEnum> StateController { get; private set; }
-
-    /// <summary>
-    /// 视野半径, 单位像素, 发现玩家后改视野范围可以穿墙
-    /// </summary>
-    public float ViewRange { get; set; } = 250;
-
-    /// <summary>
-    /// 发现玩家后的视野半径
-    /// </summary>
-    public float TailAfterViewRange { get; set; } = 400;
-
-    /// <summary>
-    /// 背后的视野半径, 单位像素
-    /// </summary>
-    public float BackViewRange { get; set; } = 50;
-
-    /// <summary>
-    /// 视野检测射线, 朝玩家打射线, 检测是否碰到墙
-    /// </summary>
-    public RayCast2D ViewRay { get; private set; }
-
-    /// <summary>
-    /// 导航代理
-    /// </summary>
-    public NavigationAgent2D NavigationAgent2D { get; private set; }
-
-    /// <summary>
-    /// 导航代理中点
-    /// </summary>
-    public Marker2D NavigationPoint { get; private set; }
-
-    //开火间隙时间
-    private float _enemyAttackTimer = 0;
-    //目标在视野内的时间
-    private float _targetInViewTime = 0;
-
-    public override void OnInit()
-    {
-        base.OnInit();
-        IsAi = true;
-        StateController = AddComponent<StateController<Enemy, AiStateEnum>>();
-
-        AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Props | PhysicsLayer.Player;
-        Camp = CampEnum.Camp2;
-
-        MoveSpeed = 20;
-
-        MaxHp = 20;
-        Hp = 20;
-
-        //视野射线
-        ViewRay = GetNode<RayCast2D>("ViewRay");
-        NavigationPoint = GetNode<Marker2D>("NavigationPoint");
-        NavigationAgent2D = NavigationPoint.GetNode<NavigationAgent2D>("NavigationAgent2D");
-
-        //PathSign = new PathSign(this, PathSignLength, GameApplication.Instance.Node3D.Player);
-
-        //注册Ai状态机
-        StateController.Register(new AiNormalState());
-        StateController.Register(new AiProbeState());
-        StateController.Register(new AiTailAfterState());
-        StateController.Register(new AiFollowUpState());
-        StateController.Register(new AiLeaveForState());
-        StateController.Register(new AiSurroundState());
-        StateController.Register(new AiFindAmmoState());
-        
-        //默认状态
-        StateController.ChangeStateInstant(AiStateEnum.AiNormal);
-    }
-
-    public override void EnterTree()
-    {
-        base.EnterTree();
-        if (!World.Enemy_InstanceList.Contains(this))
-        {
-            World.Enemy_InstanceList.Add(this);
-        }
-    }
-
-    public override void ExitTree()
-    {
-        base.ExitTree();
-        World.Enemy_InstanceList.Remove(this);
-    }
-
-    protected override void OnDie()
-    {
-        //扔掉所有武器
-        var weapons = Holster.GetAndClearWeapon();
-        for (var i = 0; i < weapons.Length; i++)
-        {
-            weapons[i].ThrowWeapon(this);
-        }
-
-        var effPos = Position + new Vector2(0, -Altitude);
-        //血液特效
-        var blood = ResourceManager.LoadAndInstantiate<AutoDestroyEffect>(ResourcePath.prefab_effect_activityObject_EnemyBloodEffect_tscn);
-        blood.Position = effPos - new Vector2(0, 12);
-        blood.AddToActivityRoot(RoomLayerEnum.NormalLayer);
-        
-        //创建敌人碎片
-        var count = Utils.RandomRangeInt(3, 6);
-        for (var i = 0; i < count; i++)
-        {
-            var debris = Create(Ids.Id_effect0001);
-            debris.PutDown(effPos, RoomLayerEnum.NormalLayer);
-            debris.InheritVelocity(this);
-        }
-        
-        //派发敌人死亡信号
-        EventManager.EmitEvent(EventEnum.OnEnemyDie, this);
-        Destroy();
-    }
-
-    protected override void Process(float delta)
-    {
-        base.Process(delta);
-        _enemyAttackTimer -= delta;
-
-        //目标在视野内的时间
-        var currState = StateController.CurrState;
-        if (currState == AiStateEnum.AiSurround || currState == AiStateEnum.AiFollowUp)
-        {
-            _targetInViewTime += delta;
-        }
-        else
-        {
-            _targetInViewTime = 0;
-        }
-
-        EnemyPickUpWeapon();
-    }
-
-    protected override void OnHit(int damage, bool realHarm)
-    {
-        //受到伤害
-        var state = StateController.CurrState;
-        if (state == AiStateEnum.AiNormal || state == AiStateEnum.AiProbe || state == AiStateEnum.AiLeaveFor)
-        {
-            StateController.ChangeState(AiStateEnum.AiTailAfter);
-        }
-    }
-
-    /// <summary>
-    /// 返回地上的武器是否有可以拾取的, 也包含没有被其他敌人标记的武器
-    /// </summary>
-    public bool CheckUsableWeaponInUnclaimed()
-    {
-        foreach (var unclaimedWeapon in World.Weapon_UnclaimedWeapons)
-        {
-            //判断是否能拾起武器, 条件: 相同的房间
-            if (unclaimedWeapon.AffiliationArea == AffiliationArea)
-            {
-                if (!unclaimedWeapon.IsTotalAmmoEmpty())
-                {
-                    if (!unclaimedWeapon.HasSign(SignNames.AiFindWeaponSign))
-                    {
-                        return true;
-                    }
-                    else
-                    {
-                        //判断是否可以移除该标记
-                        var enemy = unclaimedWeapon.GetSign<Enemy>(SignNames.AiFindWeaponSign);
-                        if (enemy == null || enemy.IsDestroyed) //标记当前武器的敌人已经被销毁
-                        {
-                            unclaimedWeapon.RemoveSign(SignNames.AiFindWeaponSign);
-                            return true;
-                        }
-                        else if (!enemy.IsAllWeaponTotalAmmoEmpty()) //标记当前武器的敌人已经有新的武器了
-                        {
-                            unclaimedWeapon.RemoveSign(SignNames.AiFindWeaponSign);
-                            return true;
-                        }
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-    
-    /// <summary>
-    /// 寻找可用的武器
-    /// </summary>
-    public Weapon FindTargetWeapon()
-    {
-        Weapon target = null;
-        var position = Position;
-        foreach (var weapon in World.Weapon_UnclaimedWeapons)
-        {
-            //判断是否能拾起武器, 条件: 相同的房间, 或者当前房间目前没有战斗, 或者不在战斗房间
-            if (weapon.AffiliationArea == AffiliationArea)
-            {
-                //还有弹药
-                if (!weapon.IsTotalAmmoEmpty())
-                {
-                    //查询是否有其他敌人标记要拾起该武器
-                    if (weapon.HasSign(SignNames.AiFindWeaponSign))
-                    {
-                        var enemy = weapon.GetSign<Enemy>(SignNames.AiFindWeaponSign);
-                        if (enemy == this) //就是自己标记的
-                        {
-
-                        }
-                        else if (enemy == null || enemy.IsDestroyed) //标记当前武器的敌人已经被销毁
-                        {
-                            weapon.RemoveSign(SignNames.AiFindWeaponSign);
-                        }
-                        else if (!enemy.IsAllWeaponTotalAmmoEmpty()) //标记当前武器的敌人已经有新的武器了
-                        {
-                            weapon.RemoveSign(SignNames.AiFindWeaponSign);
-                        }
-                        else //放弃这把武器
-                        {
-                            continue;
-                        }
-                    }
-
-                    if (target == null) //第一把武器
-                    {
-                        target = weapon;
-                    }
-                    else if (target.Position.DistanceSquaredTo(position) >
-                             weapon.Position.DistanceSquaredTo(position)) //距离更近
-                    {
-                        target = weapon;
-                    }
-                }
-            }
-        }
-
-        return target;
-    }
-
-    /// <summary>
-    /// 检查是否能切换到 AiStateEnum.AiLeaveFor 状态
-    /// </summary>
-    /// <returns></returns>
-    public bool CanChangeLeaveFor()
-    {
-        if (!World.Enemy_IsFindTarget)
-        {
-            return false;
-        }
-
-        var currState = StateController.CurrState;
-        if (currState == AiStateEnum.AiNormal || currState == AiStateEnum.AiProbe)
-        {
-            //判断是否在同一个房间内
-            return World.Enemy_FindTargetAffiliationSet.Contains(AffiliationArea);
-        }
-        
-        return false;
-    }
-
-    /// <summary>
-    /// Ai触发的攻击
-    /// </summary>
-    public void EnemyAttack(float delta)
-    {
-        var weapon = Holster.ActiveWeapon;
-        if (weapon != null)
-        {
-            if (weapon.IsTotalAmmoEmpty()) //当前武器弹药打空
-            {
-                //切换到有子弹的武器
-                var index = Holster.FindWeapon((we, i) => !we.IsTotalAmmoEmpty());
-                if (index != -1)
-                {
-                    Holster.ExchangeByIndex(index);
-                }
-                else //所有子弹打光
-                {
-                    
-                }
-            }
-            else if (weapon.Reloading) //换弹中
-            {
-
-            }
-            else if (weapon.IsAmmoEmpty()) //弹夹已经打空
-            {
-                Reload();
-            }
-            else if (_targetInViewTime >= weapon.Attribute.AiTargetLockingTime) //正常射击
-            {
-                if (weapon.GetDelayedAttackTime() > 0)
-                {
-                    Attack();
-                }
-                else
-                {
-                    if (weapon.Attribute.ContinuousShoot) //连发
-                    {
-                        Attack();
-                    }
-                    else //单发
-                    {
-                        if (_enemyAttackTimer <= 0)
-                        {
-                            _enemyAttackTimer = 60f / weapon.Attribute.StartFiringSpeed;
-                            Attack();
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /// <summary>
-    /// 获取武器攻击范围 (最大距离值与最小距离的中间值)
-    /// </summary>
-    /// <param name="weight">从最小到最大距离的过渡量, 0 - 1, 默认 0.5</param>
-    public float GetWeaponRange(float weight = 0.5f)
-    {
-        if (Holster.ActiveWeapon != null)
-        {
-            var attribute = Holster.ActiveWeapon.Attribute;
-            return Mathf.Lerp(attribute.BulletMinDistance, attribute.BulletMaxDistance, weight);
-        }
-
-        return 0;
-    }
-
-    /// <summary>
-    /// 返回目标点是否在视野范围内
-    /// </summary>
-    public bool IsInViewRange(Vector2 target)
-    {
-        var isForward = IsPositionInForward(target);
-        if (isForward)
-        {
-            if (GlobalPosition.DistanceSquaredTo(target) <= ViewRange * ViewRange) //没有超出视野半径
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /// <summary>
-    /// 返回目标点是否在跟随状态下的视野半径内
-    /// </summary>
-    public bool IsInTailAfterViewRange(Vector2 target)
-    {
-        var isForward = IsPositionInForward(target);
-        if (isForward)
-        {
-            if (GlobalPosition.DistanceSquaredTo(target) <= TailAfterViewRange * TailAfterViewRange) //没有超出视野半径
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /// <summary>
-    /// 调用视野检测, 如果被墙壁和其它物体遮挡, 则返回被挡住视野的物体对象, 视野无阻则返回 null
-    /// </summary>
-    public bool TestViewRayCast(Vector2 target)
-    {
-        ViewRay.Enabled = true;
-        ViewRay.TargetPosition = ViewRay.ToLocal(target);
-        ViewRay.ForceRaycastUpdate();
-        return ViewRay.IsColliding();
-    }
-
-    /// <summary>
-    /// 调用视野检测完毕后, 需要调用 TestViewRayCastOver() 来关闭视野检测射线
-    /// </summary>
-    public void TestViewRayCastOver()
-    {
-        ViewRay.Enabled = false;
-    }
-
-    /// <summary>
-    /// AI 拾起武器操作
-    /// </summary>
-    private void EnemyPickUpWeapon()
-    {
-        //这几个状态不需要主动拾起武器操作
-        var state = StateController.CurrState;
-        if (state == AiStateEnum.AiNormal)
-        {
-            return;
-        }
-        
-        //拾起地上的武器
-        if (InteractiveItem is Weapon weapon)
-        {
-            if (Holster.ActiveWeapon == null) //手上没有武器, 无论如何也要拾起
-            {
-                TriggerInteractive();
-                return;
-            }
-
-            //没弹药了
-            if (weapon.IsTotalAmmoEmpty())
-            {
-                return;
-            }
-            
-            var index = Holster.FindWeapon((we, i) => we.ItemId == weapon.ItemId);
-            if (index != -1) //与武器袋中武器类型相同, 补充子弹
-            {
-                if (!Holster.GetWeapon(index).IsAmmoFull())
-                {
-                    TriggerInteractive();
-                }
-
-                return;
-            }
-
-            // var index2 = Holster.FindWeapon((we, i) =>
-            //     we.Attribute.WeightType == weapon.Attribute.WeightType && we.IsTotalAmmoEmpty());
-            var index2 = Holster.FindWeapon((we, i) => we.IsTotalAmmoEmpty());
-            if (index2 != -1) //扔掉没子弹的武器
-            {
-                ThrowWeapon(index2);
-                TriggerInteractive();
-                return;
-            }
-            
-            // if (Holster.HasVacancy()) //有空位, 拾起武器
-            // {
-            //     TriggerInteractive();
-            //     return;
-            // }
-        }
-    }
-
-}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AIStateEnum.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AIStateEnum.cs
deleted file mode 100644
index 6bb8db4..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AIStateEnum.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-
-public enum AiStateEnum
-{
-    /// <summary>
-    /// Ai 状态, 正常, 未发现目标
-    /// </summary>
-    AiNormal,
-    /// <summary>
-    /// 发现目标, 但不知道在哪
-    /// </summary>
-    AiProbe,
-    /// <summary>
-    /// 收到其他敌人通知, 前往发现目标的位置
-    /// </summary>
-    AiLeaveFor,
-    /// <summary>
-    /// 发现目标, 目标不在视野内, 但是知道位置
-    /// </summary>
-    AiTailAfter,
-    /// <summary>
-    /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火
-    /// </summary>
-    AiFollowUp,
-    /// <summary>
-    /// 距离足够近, 在目标附近随机移动
-    /// </summary>
-    AiSurround,
-    /// <summary>
-    /// Ai 寻找弹药
-    /// </summary>
-    AiFindAmmo,
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs
deleted file mode 100644
index 9cfb3c6..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiFindAmmoState.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-
-using Godot;
-
-/// <summary>
-/// Ai 寻找弹药, 进入该状态需要在参数中传入目标武器对象
-/// </summary>
-public class AiFindAmmoState : StateBase<Enemy, AiStateEnum>
-{
-
-    private Weapon _target;
-
-    //导航目标点刷新计时器
-    private float _navigationUpdateTimer = 0;
-    private float _navigationInterval = 1f;
-
-    private bool _isInTailAfterRange = false;
-    private float _tailAfterTimer = 0;
-
-    public AiFindAmmoState() : base(AiStateEnum.AiFindAmmo)
-    {
-    }
-
-    public override void Enter(AiStateEnum prev, params object[] args)
-    {
-        if (args.Length == 0)
-        {
-            GD.PrintErr("进入 AiStateEnum.AiFindAmmo 状态必须要把目标武器当成参数传过来");
-            ChangeState(prev);
-            return;
-        }
-
-        SetTargetWeapon((Weapon)args[0]);
-        _navigationUpdateTimer = 0;
-        _isInTailAfterRange = false;
-        _tailAfterTimer = 0;
-
-        //标记武器
-        _target.SetSign(SignNames.AiFindWeaponSign, Master);
-    }
-
-    public override void Process(float delta)
-    {
-        if (!Master.IsAllWeaponTotalAmmoEmpty()) //已经有弹药了
-        {
-            ChangeState(GetNextState());
-            return;
-        }
-
-        //更新目标位置
-        if (_navigationUpdateTimer <= 0)
-        {
-            //每隔一段时间秒更改目标位置
-            _navigationUpdateTimer = _navigationInterval;
-            var position = _target.GlobalPosition;
-            Master.NavigationAgent2D.TargetPosition = position;
-        }
-        else
-        {
-            _navigationUpdateTimer -= delta;
-        }
-
-        var playerPos = Player.Current.GetCenterPosition();
-        //枪口指向玩家
-        Master.LookTargetPosition(playerPos);
-
-        if (_target.IsDestroyed || _target.IsTotalAmmoEmpty()) //已经被销毁, 或者弹药已经被其他角色捡走
-        {
-            //再去寻找其他武器
-            SetTargetWeapon(Master.FindTargetWeapon());
-
-            if (_target == null) //也没有其他可用的武器了
-            {
-                ChangeState(GetNextState());
-            }
-        }
-        else if (_target.Master == Master) //已经被自己拾起
-        {
-            ChangeState(GetNextState());
-        }
-        else if (_target.Master != null) //武器已经被其他角色拾起!
-        {
-            //再去寻找其他武器
-            SetTargetWeapon(Master.FindTargetWeapon());
-
-            if (_target == null) //也没有其他可用的武器了
-            {
-                ChangeState(GetNextState());
-            }
-        }
-        else
-        {
-            //检测目标没有超出跟随视野距离
-            _isInTailAfterRange = Master.IsInTailAfterViewRange(playerPos);
-            if (_isInTailAfterRange)
-            {
-                _tailAfterTimer = 0;
-            }
-            else
-            {
-                _tailAfterTimer += delta;
-            }
-
-            //向武器移动
-            if (!Master.NavigationAgent2D.IsNavigationFinished())
-            {
-                //计算移动
-                var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-                Master.AnimatedSprite.Play(AnimatorNames.Run);
-                Master.BasisVelocity =
-                    (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
-                    Master.MoveSpeed;
-            }
-            else
-            {
-                Master.BasisVelocity = Vector2.Zero;
-            }
-        }
-    }
-
-    private AiStateEnum GetNextState()
-    {
-        return _tailAfterTimer > 10 ? AiStateEnum.AiNormal : AiStateEnum.AiTailAfter;
-    }
-
-    private void SetTargetWeapon(Weapon weapon)
-    {
-        _target = weapon;
-        //设置目标点
-        if (_target != null)
-        {
-            Master.NavigationAgent2D.TargetPosition = _target.GlobalPosition;
-        }
-    }
-    
-    public override void DebugDraw()
-    {
-        if (_target != null)
-        {
-            Master.DrawLine(Vector2.Zero, Master.ToLocal(_target.GlobalPosition), Colors.Purple);
-
-            if (_tailAfterTimer <= 0)
-            {
-                Master.DrawLine(Vector2.Zero, Master.ToLocal(Player.Current.GetCenterPosition()), Colors.Orange);
-            }
-            else if (_tailAfterTimer <= 10)
-            {
-                Master.DrawLine(Vector2.Zero, Master.ToLocal(Player.Current.GetCenterPosition()), Colors.Blue);
-            }
-            
-        }
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs
deleted file mode 100644
index ab05469..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiFollowUpState.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-
-using Godot;
-
-/// <summary>
-/// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火
-/// </summary>
-public class AiFollowUpState : StateBase<Enemy, AiStateEnum>
-{
-
-    /// <summary>
-    /// 目标是否在视野内
-    /// </summary>
-    public bool IsInView;
-
-    //导航目标点刷新计时器
-    private float _navigationUpdateTimer = 0;
-    private float _navigationInterval = 0.3f;
-
-    public AiFollowUpState() : base(AiStateEnum.AiFollowUp)
-    {
-    }
-
-    public override void Enter(AiStateEnum prev, params object[] args)
-    {
-        _navigationUpdateTimer = 0;
-        IsInView = true;
-    }
-
-    public override void Process(float delta)
-    {
-        //先检查弹药是否打光
-        if (Master.IsAllWeaponTotalAmmoEmpty())
-        {
-            //再寻找是否有可用的武器
-            var targetWeapon = Master.FindTargetWeapon();
-            if (targetWeapon != null)
-            {
-                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
-                return;
-            }
-            else
-            {
-                //切换到随机移动状态
-                ChangeState(AiStateEnum.AiSurround);
-            }
-        }
-
-        var playerPos = Player.Current.GetCenterPosition();
-
-        //更新玩家位置
-        if (_navigationUpdateTimer <= 0)
-        {
-            //每隔一段时间秒更改目标位置
-            _navigationUpdateTimer = _navigationInterval;
-            Master.NavigationAgent2D.TargetPosition = playerPos;
-        }
-        else
-        {
-            _navigationUpdateTimer -= delta;
-        }
-
-        var masterPosition = Master.GlobalPosition;
-
-        //是否在攻击范围内
-        var inAttackRange = false;
-
-        var weapon = Master.Holster.ActiveWeapon;
-        if (weapon != null)
-        {
-            inAttackRange = masterPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(Master.GetWeaponRange(0.7f), 2);
-        }
-
-        //枪口指向玩家
-        Master.LookTargetPosition(playerPos);
-        
-        if (!Master.NavigationAgent2D.IsNavigationFinished())
-        {
-            //计算移动
-            var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-            Master.AnimatedSprite.Play(AnimatorNames.Run);
-            Master.BasisVelocity = (nextPos - masterPosition - Master.NavigationPoint.Position).Normalized() *
-                              Master.MoveSpeed;
-        }
-        else
-        {
-            Master.BasisVelocity = Vector2.Zero;
-        }
-
-        //检测玩家是否在视野内
-        if (Master.IsInTailAfterViewRange(playerPos))
-        {
-            IsInView = !Master.TestViewRayCast(playerPos);
-            //关闭射线检测
-            Master.TestViewRayCastOver();
-        }
-        else
-        {
-            IsInView = false;
-        }
-
-        if (IsInView)
-        {
-            if (inAttackRange) //在攻击范围内
-            {
-                //发起攻击
-                Master.EnemyAttack(delta);
-                
-                //距离够近, 可以切换到环绕模式
-                if (Master.GlobalPosition.DistanceSquaredTo(playerPos) <= Mathf.Pow(weapon.Attribute.BulletMinDistance, 2) * 0.7f)
-                {
-                    ChangeState(AiStateEnum.AiSurround);
-                }
-            }
-        }
-        else
-        {
-            ChangeState(AiStateEnum.AiTailAfter);
-        }
-    }
-
-    public override void DebugDraw()
-    {
-        var playerPos = Player.Current.GetCenterPosition();
-        Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Red);
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs
deleted file mode 100644
index 8185484..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiLeaveForState.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-
-using Godot;
-
-/// <summary>
-/// 收到其他敌人通知, 前往发现目标的位置
-/// </summary>
-public class AiLeaveForState : StateBase<Enemy, AiStateEnum>
-{
-    //导航目标点刷新计时器
-    private float _navigationUpdateTimer = 0;
-    private float _navigationInterval = 0.3f;
-
-    public AiLeaveForState() : base(AiStateEnum.AiLeaveFor)
-    {
-    }
-
-    public override void Enter(AiStateEnum prev, params object[] args)
-    {
-        if (Master.World.Enemy_IsFindTarget)
-        {
-            Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
-        }
-        else
-        {
-            ChangeState(prev);
-            return;
-        }
-
-        //先检查弹药是否打光
-        if (Master.IsAllWeaponTotalAmmoEmpty())
-        {
-            //再寻找是否有可用的武器
-            var targetWeapon = Master.FindTargetWeapon();
-            if (targetWeapon != null)
-            {
-                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
-            }
-        }
-    }
-
-    public override void Process(float delta)
-    {
-        //这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
-        
-        //更新玩家位置
-        if (_navigationUpdateTimer <= 0)
-        {
-            //每隔一段时间秒更改目标位置
-            _navigationUpdateTimer = _navigationInterval;
-            Master.NavigationAgent2D.TargetPosition = Master.World.Enemy_FindTargetPosition;
-        }
-        else
-        {
-            _navigationUpdateTimer -= delta;
-        }
-
-        if (!Master.NavigationAgent2D.IsNavigationFinished())
-        {
-            //计算移动
-            var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-            Master.LookTargetPosition(Master.World.Enemy_FindTargetPosition);
-            Master.AnimatedSprite.Play(AnimatorNames.Run);
-            Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
-                              Master.MoveSpeed;
-        }
-        else
-        {
-            Master.BasisVelocity = Vector2.Zero;
-        }
-
-        var playerPos = Player.Current.GetCenterPosition();
-        //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
-        if (Master.IsInTailAfterViewRange(playerPos))
-        {
-            if (!Master.TestViewRayCast(playerPos)) //看到玩家
-            {
-                //关闭射线检测
-                Master.TestViewRayCastOver();
-                //切换成发现目标状态
-                ChangeState(AiStateEnum.AiFollowUp);
-                return;
-            }
-            else
-            {
-                //关闭射线检测
-                Master.TestViewRayCastOver();
-            }
-        }
-
-        //移动到目标掉了, 还没发现目标
-        if (Master.NavigationAgent2D.IsNavigationFinished())
-        {
-            ChangeState(AiStateEnum.AiNormal);
-        }
-    }
-
-    public override void DebugDraw()
-    {
-        Master.DrawLine(Vector2.Zero, Master.ToLocal(Master.NavigationAgent2D.TargetPosition), Colors.Yellow);
-    }
-}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs
deleted file mode 100644
index 299abf0..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiNormalState.cs
+++ /dev/null
@@ -1,181 +0,0 @@
-
-using Godot;
-
-/// <summary>
-/// AI 正常状态
-/// </summary>
-public class AiNormalState : StateBase<Enemy, AiStateEnum>
-{
-    //是否发现玩家
-    private bool _isFindPlayer;
-
-    //下一个运动的角度
-    private Vector2 _nextPos;
-
-    //是否移动结束
-    private bool _isMoveOver;
-
-    //上一次移动是否撞墙
-    private bool _againstWall;
-    
-    //撞墙法线角度
-    private float _againstWallNormalAngle;
-
-    //移动停顿计时器
-    private float _pauseTimer;
-    private bool _moveFlag;
-
-    //上一帧位置
-    private Vector2 _prevPos;
-    //卡在一个位置的时间
-    private float _lockTimer;
-
-    public AiNormalState() : base(AiStateEnum.AiNormal)
-    {
-    }
-
-    public override void Enter(AiStateEnum prev, params object[] args)
-    {
-        _isFindPlayer = false;
-        _isMoveOver = true;
-        _againstWall = false;
-        _againstWallNormalAngle = 0;
-        _pauseTimer = 0;
-        _moveFlag = false;
-    }
-
-    public override void Process(float delta)
-    {
-        //其他敌人发现玩家
-        if (Master.CanChangeLeaveFor())
-        {
-            ChangeState(AiStateEnum.AiLeaveFor);
-            return;
-        }
-
-        if (_isFindPlayer) //已经找到玩家了
-        {
-            //现临时处理, 直接切换状态
-            ChangeState(AiStateEnum.AiTailAfter);
-        }
-        else //没有找到玩家
-        {
-            //检测玩家
-            var player = Player.Current;
-            //玩家中心点坐标
-            var playerPos = player.GetCenterPosition();
-
-            if (Master.IsInViewRange(playerPos) && !Master.TestViewRayCast(playerPos)) //发现玩家
-            {
-                //发现玩家
-                _isFindPlayer = true;
-            }
-            else if (_pauseTimer >= 0)
-            {
-                Master.AnimatedSprite.Play(AnimatorNames.Idle);
-                _pauseTimer -= delta;
-            }
-            else if (_isMoveOver) //没发现玩家, 且已经移动完成
-            {
-                RunOver();
-                _isMoveOver = false;
-            }
-            else //移动中
-            {
-                if (_lockTimer >= 1) //卡在一个点超过一秒
-                {
-                    RunOver();
-                    _isMoveOver = false;
-                    _lockTimer = 0;
-                }
-                else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
-                {
-                    _pauseTimer = Utils.RandomRangeFloat(0.3f, 2f);
-                    _isMoveOver = true;
-                    _moveFlag = false;
-                    Master.BasisVelocity = Vector2.Zero;
-                }
-                else if (!_moveFlag)
-                {
-                    _moveFlag = true;
-                    var pos = Master.GlobalPosition;
-                    //计算移动
-                    var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-                    Master.AnimatedSprite.Play(AnimatorNames.Run);
-                    Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
-                                           Master.MoveSpeed;
-                    _prevPos = pos;
-                }
-                else
-                {
-                    var pos = Master.GlobalPosition;
-                    var lastSlideCollision = Master.GetLastSlideCollision();
-                    if (lastSlideCollision != null && lastSlideCollision.GetCollider() is Role) //碰到其他角色
-                    {
-                        _pauseTimer = Utils.RandomRangeFloat(0.1f, 0.5f);
-                        _isMoveOver = true;
-                        _moveFlag = false;
-                        Master.BasisVelocity = Vector2.Zero;
-                    }
-                    else
-                    {
-                        //计算移动
-                        var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-                        Master.AnimatedSprite.Play(AnimatorNames.Run);
-                        Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
-                                               Master.MoveSpeed;
-                    }
-
-                    if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
-                    {
-                        _lockTimer += delta;
-                    }
-                    else
-                    {
-                        _prevPos = pos;
-                    }
-                }
-            }
-
-            //关闭射线检测
-            Master.TestViewRayCastOver();
-        }
-    }
-
-    //移动结束
-    private void RunOver()
-    {
-        float angle;
-        if (_againstWall)
-        {
-            angle = Utils.RandomRangeFloat(_againstWallNormalAngle - Mathf.Pi * 0.5f,
-                _againstWallNormalAngle + Mathf.Pi * 0.5f);
-        }
-        else
-        {
-            angle = Utils.RandomRangeFloat(0, Mathf.Pi * 2f);
-        }
-
-        var len = Utils.RandomRangeInt(30, 200);
-        _nextPos = new Vector2(len, 0).Rotated(angle) + Master.GlobalPosition;
-        //获取射线碰到的坐标
-        if (Master.TestViewRayCast(_nextPos)) //碰到墙壁
-        {
-            _nextPos = Master.ViewRay.GetCollisionPoint();
-            _againstWall = true;
-            _againstWallNormalAngle = Master.ViewRay.GetCollisionNormal().Angle();
-        }
-        else
-        {
-            _againstWall = false;
-        }
-
-        Master.NavigationAgent2D.TargetPosition = _nextPos;
-        Master.LookTargetPosition(_nextPos);
-    }
-
-    public override void DebugDraw()
-    {
-        Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPos), Colors.Green);
-    }
-}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiProbeState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiProbeState.cs
deleted file mode 100644
index 1015095..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiProbeState.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
-/// <summary>
-/// Ai 不确定玩家位置
-/// </summary>
-public class AiProbeState : StateBase<Enemy, AiStateEnum>
-{
-    public AiProbeState() : base(AiStateEnum.AiProbe)
-    {
-    }
-
-    public override void Process(float delta)
-    {
-        //其他敌人发现玩家
-        if (Master.CanChangeLeaveFor())
-        {
-            ChangeState(AiStateEnum.AiLeaveFor);
-            return;
-        }
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs
deleted file mode 100644
index ebfce46..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiSurroundState.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-
-using Godot;
-
-/// <summary>
-/// 距离目标足够近, 在目标附近随机移动, 并开火
-/// </summary>
-public class AiSurroundState : StateBase<Enemy, AiStateEnum>
-{
-    /// <summary>
-    /// 目标是否在视野内
-    /// </summary>
-    public bool IsInView = true;
-
-    //是否移动结束
-    private bool _isMoveOver;
-
-    //移动停顿计时器
-    private float _pauseTimer;
-    private bool _moveFlag;
-    
-    //下一个移动点
-    private Vector2 _nextPosition;
-    
-    //上一帧位置
-    private Vector2 _prevPos;
-    //卡在一个位置的时间
-    private float _lockTimer;
-
-    public AiSurroundState() : base(AiStateEnum.AiSurround)
-    {
-    }
-
-    public override void Enter(AiStateEnum prev, params object[] args)
-    {
-        IsInView = true;
-        _isMoveOver = true;
-        _pauseTimer = 0;
-        _moveFlag = false;
-    }
-
-    public override void Process(float delta)
-    {
-        //先检查弹药是否打光
-        if (Master.IsAllWeaponTotalAmmoEmpty())
-        {
-            //再寻找是否有可用的武器
-            var targetWeapon = Master.FindTargetWeapon();
-            if (targetWeapon != null)
-            {
-                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
-                return;
-            }
-        }
-
-        var playerPos = Player.Current.GetCenterPosition();
-        var weapon = Master.Holster.ActiveWeapon;
-
-        //枪口指向玩家
-        Master.LookTargetPosition(playerPos);
-
-        //检测玩家是否在视野内
-        if (Master.IsInTailAfterViewRange(playerPos))
-        {
-            IsInView = !Master.TestViewRayCast(playerPos);
-            //关闭射线检测
-            Master.TestViewRayCastOver();
-        }
-        else
-        {
-            IsInView = false;
-        }
-
-        if (IsInView)
-        {
-            if (_pauseTimer >= 0)
-            {
-                Master.AnimatedSprite.Play(AnimatorNames.Idle);
-                _pauseTimer -= delta;
-            }
-            else if (_isMoveOver) //移动已经完成
-            {
-                RunOver(playerPos);
-                _isMoveOver = false;
-            }
-            else
-            {
-                if (_lockTimer >= 1) //卡在一个点超过一秒
-                {
-                    RunOver(playerPos);
-                    _isMoveOver = false;
-                    _lockTimer = 0;
-                }
-                else if (Master.NavigationAgent2D.IsNavigationFinished()) //到达终点
-                {
-                    _pauseTimer = Utils.RandomRangeFloat(0f, 0.5f);
-                    _isMoveOver = true;
-                    _moveFlag = false;
-                    Master.BasisVelocity = Vector2.Zero;
-                }
-                else if (!_moveFlag)
-                {
-                    _moveFlag = true;
-                    //计算移动
-                    var pos = Master.GlobalPosition;
-                    var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-                    Master.AnimatedSprite.Play(AnimatorNames.Run);
-                    Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
-                                           Master.MoveSpeed;
-                }
-                else
-                {
-                    var pos = Master.GlobalPosition;
-                    var lastSlideCollision = Master.GetLastSlideCollision();
-                    if (lastSlideCollision != null && lastSlideCollision.GetCollider() is Role) //碰到其他角色
-                    {
-                        _pauseTimer = Utils.RandomRangeFloat(0f, 0.3f);
-                        _isMoveOver = true;
-                        _moveFlag = false;
-                        Master.BasisVelocity = Vector2.Zero;
-                    }
-                    else
-                    {
-                        //计算移动
-                        var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-                        Master.AnimatedSprite.Play(AnimatorNames.Run);
-                        Master.BasisVelocity = (nextPos - pos - Master.NavigationPoint.Position).Normalized() *
-                                               Master.MoveSpeed;
-                    }
-                    
-                    if (_prevPos.DistanceSquaredTo(pos) <= 0.01f)
-                    {
-                        _lockTimer += delta;
-                    }
-                    else
-                    {
-                        _prevPos = pos;
-                    }
-                }
-
-                if (weapon != null)
-                {
-                    var position = Master.GlobalPosition;
-                    if (position.DistanceSquaredTo(playerPos) > Mathf.Pow(Master.GetWeaponRange(0.7f), 2)) //玩家离开正常射击范围
-                    {
-                        ChangeState(AiStateEnum.AiFollowUp);
-                    }
-                    else
-                    {
-                        //发起攻击
-                        Master.EnemyAttack(delta);
-                    }
-                }
-            }
-        }
-        else //目标离开视野
-        {
-            ChangeState(AiStateEnum.AiTailAfter);
-        }
-    }
-
-    private void RunOver(Vector2 targetPos)
-    {
-        var weapon = Master.Holster.ActiveWeapon;
-        var distance = (int)(weapon == null ? 150 : (weapon.Attribute.BulletMinDistance * 0.7f));
-        _nextPosition = new Vector2(
-            targetPos.X + Utils.RandomRangeInt(-distance, distance),
-            targetPos.Y + Utils.RandomRangeInt(-distance, distance)
-        );
-        Master.NavigationAgent2D.TargetPosition = _nextPosition;
-    }
-
-    public override void DebugDraw()
-    {
-        Master.DrawLine(new Vector2(0, -8), Master.ToLocal(_nextPosition), Colors.White);
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs
deleted file mode 100644
index 87d018e..0000000
--- a/DungeonShooting_Godot/src/game/role/enemy/state/AiTailAfterState.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-
-using Godot;
-
-/// <summary>
-/// AI 发现玩家, 跟随玩家
-/// </summary>
-public class AiTailAfterState : StateBase<Enemy, AiStateEnum>
-{
-    /// <summary>
-    /// 目标是否在视野半径内
-    /// </summary>
-    private bool _isInViewRange;
-
-    //导航目标点刷新计时器
-    private float _navigationUpdateTimer = 0;
-    private float _navigationInterval = 0.3f;
-
-    //目标从视野消失时已经过去的时间
-    private float _viewTimer;
-
-    public AiTailAfterState() : base(AiStateEnum.AiTailAfter)
-    {
-    }
-
-    public override void Enter(AiStateEnum prev, params object[] args)
-    {
-        _isInViewRange = true;
-        _navigationUpdateTimer = 0;
-        _viewTimer = 0;
-        
-        //先检查弹药是否打光
-        if (Master.IsAllWeaponTotalAmmoEmpty())
-        {
-            //再寻找是否有可用的武器
-            var targetWeapon = Master.FindTargetWeapon();
-            if (targetWeapon != null)
-            {
-                ChangeState(AiStateEnum.AiFindAmmo, targetWeapon);
-            }
-        }
-    }
-    
-    public override void Process(float delta)
-    {
-        //这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
-        
-        var playerPos = Player.Current.GetCenterPosition();
-        
-        //更新玩家位置
-        if (_navigationUpdateTimer <= 0)
-        {
-            //每隔一段时间秒更改目标位置
-            _navigationUpdateTimer = _navigationInterval;
-            Master.NavigationAgent2D.TargetPosition = playerPos;
-        }
-        else
-        {
-            _navigationUpdateTimer -= delta;
-        }
-        
-        //枪口指向玩家
-        Master.LookTargetPosition(playerPos);
-        
-        if (!Master.NavigationAgent2D.IsNavigationFinished())
-        {
-            //计算移动
-            var nextPos = Master.NavigationAgent2D.GetNextPathPosition();
-            Master.AnimatedSprite.Play(AnimatorNames.Run);
-            Master.BasisVelocity = (nextPos - Master.GlobalPosition - Master.NavigationPoint.Position).Normalized() *
-                              Master.MoveSpeed;
-        }
-        else
-        {
-            Master.BasisVelocity = Vector2.Zero;
-        }
-        //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
-        if (Master.IsInTailAfterViewRange(playerPos))
-        {
-            if (!Master.TestViewRayCast(playerPos)) //看到玩家
-            {
-                //关闭射线检测
-                Master.TestViewRayCastOver();
-                //切换成发现目标状态
-                ChangeState(AiStateEnum.AiFollowUp);
-                return;
-            }
-            else
-            {
-                //关闭射线检测
-                Master.TestViewRayCastOver();
-            }
-        }
-        
-        //检测玩家是否在穿墙视野范围内, 直接检测距离即可
-        _isInViewRange = Master.IsInViewRange(playerPos);
-        if (_isInViewRange)
-        {
-            _viewTimer = 0;
-        }
-        else //超出视野
-        {
-            if (_viewTimer > 10) //10秒
-            {
-                ChangeState(AiStateEnum.AiNormal);
-            }
-            else
-            {
-                _viewTimer += delta;
-            }
-        }
-    }
-
-    public override void DebugDraw()
-    {
-        var playerPos = Player.Current.GetCenterPosition();
-        if (_isInViewRange)
-        {
-            Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Orange);
-        }
-        else
-        {
-            Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Blue);
-        }
-    }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/ui/roomUI/InteractiveTipBar.cs b/DungeonShooting_Godot/src/game/ui/roomUI/InteractiveTipBar.cs
index b702af5..ff928a2 100644
--- a/DungeonShooting_Godot/src/game/ui/roomUI/InteractiveTipBar.cs
+++ b/DungeonShooting_Godot/src/game/ui/roomUI/InteractiveTipBar.cs
@@ -67,7 +67,8 @@
         {
             var result = (CheckInteractiveResult)o;
             var interactiveItem = Player.Current.InteractiveItem;
-            if (interactiveItem is Weapon)
+            //if (interactiveItem is Weapon)
+            if (!string.IsNullOrEmpty(result.ShowIcon))
             {
                 _interactiveTarget = interactiveItem;
                 //显示互动提示