diff --git a/DungeonShooting_Godot/prefab/role/Role0001.tscn b/DungeonShooting_Godot/prefab/role/Role0001.tscn
index 71e4939..11cf968 100644
--- a/DungeonShooting_Godot/prefab/role/Role0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/Role0001.tscn
@@ -24,7 +24,7 @@
[sub_resource type="AnimationLibrary" id="AnimationLibrary_ka171"]
[node name="Role0001" node_paths=PackedStringArray("HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_10c2n")]
-collision_layer = 8
+collision_layer = 24
script = ExtResource("2_6xwnt")
HurtArea = NodePath("HurtArea")
HurtCollision = NodePath("HurtArea/HurtCollision")
diff --git a/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn b/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn
index 3e85288..b616e02 100644
--- a/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/enemy/Enemy0001.tscn
@@ -44,12 +44,14 @@
"query": ExtResource("7_e37p2")
}
-[node name="Enemy0001" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_2vqwe")]
+[node name="Enemy0001" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "ViewArea", "ViewAreaCollision", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_2vqwe")]
script = ExtResource("2_0pcq3")
ViewRay = NodePath("ViewRay")
NavigationAgent2D = NodePath("NavigationPoint/NavigationAgent2D")
NavigationPoint = NodePath("NavigationPoint")
FirePoint = NodePath("FirePoint")
+ViewArea = NodePath("MountPoint/ViewArea")
+ViewAreaCollision = NodePath("MountPoint/ViewArea/ViewAreaCollision")
HurtArea = NodePath("HurtArea")
HurtCollision = NodePath("HurtArea/HurtCollision")
InteractiveArea = NodePath("InteractiveArea")
diff --git a/DungeonShooting_Godot/prefab/role/enemy/Enemy0002.tscn b/DungeonShooting_Godot/prefab/role/enemy/Enemy0002.tscn
index 6829646..cfc530c 100644
--- a/DungeonShooting_Godot/prefab/role/enemy/Enemy0002.tscn
+++ b/DungeonShooting_Godot/prefab/role/enemy/Enemy0002.tscn
@@ -9,7 +9,6 @@
[ext_resource type="Animation" uid="uid://cmje7jsgrhgmx" path="res://resource/animation/enemy/Enemy_query.res" id="7_h4cls"]
[ext_resource type="Animation" uid="uid://16rxpnsgj5tl" path="res://resource/animation/enemy/Enemy_notify.res" id="8_0688j"]
-
[sub_resource type="ShaderMaterial" id="ShaderMaterial_y5nia"]
resource_local_to_scene = true
shader = ExtResource("2_yunbp")
@@ -85,12 +84,14 @@
"query": ExtResource("7_h4cls")
}
-[node name="Enemy0002" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_fanet")]
+[node name="Enemy0002" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "ViewArea", "ViewAreaCollision", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_fanet")]
script = ExtResource("2_3an4s")
ViewRay = NodePath("ViewRay")
NavigationAgent2D = NodePath("NavigationPoint/NavigationAgent2D")
NavigationPoint = NodePath("NavigationPoint")
FirePoint = NodePath("FirePoint")
+ViewArea = NodePath("MountPoint/ViewArea")
+ViewAreaCollision = NodePath("MountPoint/ViewArea/ViewAreaCollision")
HurtArea = NodePath("HurtArea")
HurtCollision = NodePath("HurtArea/HurtCollision")
InteractiveArea = NodePath("InteractiveArea")
diff --git a/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn b/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn
index d0f6ea5..3638fac 100644
--- a/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn
+++ b/DungeonShooting_Godot/prefab/role/shopBoss/ShopBoss0001.tscn
@@ -29,13 +29,15 @@
shader_parameter/outline_use_blend = true
shader_parameter/grey = 0.0
-[node name="ShopBoss0001" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_25fpq")]
+[node name="ShopBoss0001" node_paths=PackedStringArray("ViewRay", "NavigationAgent2D", "NavigationPoint", "FirePoint", "ViewArea", "ViewAreaCollision", "HurtArea", "HurtCollision", "InteractiveArea", "InteractiveCollision", "TipRoot", "TipSprite", "AnimationPlayer", "MountPoint", "BackMountPoint", "MeleeAttackArea", "MeleeAttackCollision", "ShadowSprite", "AnimatedSprite", "Collision") instance=ExtResource("1_25fpq")]
collision_layer = 1024
script = ExtResource("2_2ng7e")
ViewRay = NodePath("ViewRay")
NavigationAgent2D = NodePath("NavigationPoint/NavigationAgent2D")
NavigationPoint = NodePath("NavigationPoint")
FirePoint = NodePath("FirePoint")
+ViewArea = NodePath("MountPoint/ViewArea")
+ViewAreaCollision = NodePath("MountPoint/ViewArea/ViewAreaCollision")
HurtArea = NodePath("HurtArea")
HurtCollision = NodePath("HurtArea/HurtCollision")
InteractiveArea = NodePath("InteractiveArea")
diff --git a/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn b/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn
index 23667b3..3866ed8 100644
--- a/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn
+++ b/DungeonShooting_Godot/prefab/role/template/AiTemplate.tscn
@@ -33,6 +33,13 @@
position = Vector2(0, -8)
enabled = false
+[node name="ViewArea" type="Area2D" parent="MountPoint" index="1"]
+collision_layer = 0
+collision_mask = 16
+monitorable = false
+
+[node name="ViewAreaCollision" type="CollisionPolygon2D" parent="MountPoint/ViewArea" index="0"]
+
[node name="FirePoint" type="Marker2D" parent="." index="8"]
[node name="NavigationPoint" type="Marker2D" parent="." index="9"]
diff --git a/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn b/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn
index 102bf01..ad4f584 100644
--- a/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn
+++ b/DungeonShooting_Godot/prefab/role/template/RoleTemplate.tscn
@@ -46,7 +46,7 @@
shape = SubResource("CircleShape2D_5pj80")
[node name="HurtArea" type="Area2D" parent="."]
-collision_layer = 0
+collision_layer = 1024
collision_mask = 0
monitoring = false
script = ExtResource("2_2eey0")
diff --git a/DungeonShooting_Godot/project.godot b/DungeonShooting_Godot/project.godot
index 9c42853..1822292 100644
--- a/DungeonShooting_Godot/project.godot
+++ b/DungeonShooting_Godot/project.godot
@@ -246,13 +246,13 @@
2d_physics/layer_2="bullet"
2d_physics/layer_3="prop"
2d_physics/layer_4="player"
-2d_physics/layer_5="enemy"
+2d_physics/layer_5="role"
2d_physics/layer_6="affiliation"
2d_physics/layer_7="onHand"
2d_physics/layer_8="debris"
2d_physics/layer_9="throwing"
2d_physics/layer_10="obstacle"
-2d_physics/layer_11="npc"
+2d_physics/layer_11="hurtArea"
2d_physics/layer_14="ui_mouse"
[mono]
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/GroupConfig.json b/DungeonShooting_Godot/resource/map/tileMaps/GroupConfig.json
index 93e8149..fd96875 100644
--- a/DungeonShooting_Godot/resource/map/tileMaps/GroupConfig.json
+++ b/DungeonShooting_Godot/resource/map/tileMaps/GroupConfig.json
@@ -30,8 +30,12 @@
],
"InletList": [
{
- "ErrorType": 0,
+ "ErrorType": 2,
"Path": "resource/map/tileMaps/Test1/inlet/Start"
+ },
+ {
+ "ErrorType": 0,
+ "Path": "resource/map/tileMaps/Test1/inlet/Start2"
}
],
"OutletList": [
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/Preview.png b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/Preview.png
index 65b6fc2..95f53df 100644
--- a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/Preview.png
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/Preview.png
Binary files differ
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/RoomInfo.json b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/RoomInfo.json
index 6091345..f4b132a 100644
--- a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/RoomInfo.json
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/RoomInfo.json
@@ -1 +1 @@
-{"Position":{"X":-9,"Y":-11},"Size":{"X":20,"Y":21},"DoorAreaInfos":[{"Direction":2,"Start":48,"End":176},{"Direction":3,"Start":0,"End":256},{"Direction":0,"Start":0,"End":208},{"Direction":1,"Start":0,"End":224}],"GroupName":"Test1","RoomType":2,"RoomName":"Start","Weight":100,"Remark":""}
\ No newline at end of file
+{"Position":{"X":-10,"Y":-12},"Size":{"X":22,"Y":23},"DoorAreaInfos":[{"Direction":2,"Start":48,"End":176},{"Direction":3,"Start":0,"End":256},{"Direction":0,"Start":0,"End":208},{"Direction":1,"Start":0,"End":224}],"GroupName":"Test1","RoomType":2,"RoomName":"Start","Weight":100,"Remark":""}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/TileInfo.json b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/TileInfo.json
index 04f62db..881c982 100644
--- a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/TileInfo.json
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start/TileInfo.json
@@ -1 +1 @@
-{"NavigationVertices":[{"X":134,"Y":38},{"X":138,"Y":-122},{"X":138,"Y":138},{"X":134,"Y":90},{"X":134,"Y":-6},{"X":90,"Y":-6},{"X":86,"Y":-58},{"X":86,"Y":-102},{"X":-106,"Y":-122},{"X":-38,"Y":-102},{"X":74,"Y":10},{"X":74,"Y":54},{"X":58,"Y":90},{"X":-26,"Y":38},{"X":-26,"Y":-6},{"X":90,"Y":10},{"X":-38,"Y":-58},{"X":118,"Y":54},{"X":118,"Y":38},{"X":134,"Y":138},{"X":58,"Y":138},{"X":-58,"Y":138},{"X":-58,"Y":106},{"X":-86,"Y":38},{"X":-106,"Y":106},{"X":-86,"Y":-6}],"NavigationPolygon":[[0,1,2,3],[1,0,4],[1,4,5,6,7],[8,1,7,9],[10,11,12,13,14],[6,5,15,10,14,16],[17,18,0,3],[2,19,3],[17,3,12,11],[13,12,20,21,22],[23,13,22,24],[23,24,8,25],[25,8,9,16],[14,25,16]],"Floor":[-3,-4,0,3,-2,-4,0,3,-2,-3,0,3,-3,-3,0,3,-7,-2,0,3,-7,-1,0,3,-7,0,0,3,-7,1,0,3,-7,2,0,3,-7,3,0,3,-7,4,0,3,-7,5,0,3,-6,-3,0,3,-6,-2,0,3,-6,-1,0,3,-6,0,0,3,-6,1,0,3,-6,2,0,3,-6,3,0,3,-6,4,0,3,-6,5,0,3,-5,-3,0,3,-5,-2,0,3,-5,2,0,3,-5,3,0,3,-5,4,0,3,-5,5,0,3,-4,-3,0,3,-4,-2,0,3,-4,2,0,3,-4,3,0,3,-4,4,0,3,-4,5,0,3,-3,-2,0,3,-3,2,0,3,-3,3,0,3,-3,4,0,3,-3,5,0,3,-2,-2,0,3,-2,-1,0,3,-2,0,0,3,-2,1,0,3,-2,2,0,3,-2,3,0,3,-2,4,0,3,-2,5,0,3,-4,6,0,3,-4,7,0,3,-3,6,0,3,-3,7,0,3,-2,6,0,3,-2,7,0,3,-1,3,0,3,-1,4,0,3,-1,7,0,3,0,3,0,3,0,4,0,3,0,7,0,3,1,3,0,3,1,4,0,3,1,5,0,3,1,6,0,3,1,7,0,3,2,3,0,3,2,4,0,3,2,5,0,3,2,6,0,3,2,7,0,3,3,3,0,3,3,4,0,3,3,5,0,3,3,6,0,3,-1,-4,0,3,-1,-3,0,3,-1,-2,0,3,-1,-1,0,3,-1,0,0,3,0,-4,0,3,0,-3,0,3,0,-2,0,3,0,-1,0,3,0,0,0,3,1,-4,0,3,1,-3,0,3,1,-2,0,3,1,-1,0,3,1,0,0,3,2,-4,0,3,2,-3,0,3,2,-2,0,3,2,-1,0,3,2,0,0,3,3,-4,0,3,3,-3,0,3,3,-2,0,3,3,-1,0,3,3,0,0,3,4,-4,0,3,4,-3,0,3,4,-2,0,3,4,-1,0,3,4,0,0,3,5,-4,0,3,5,-3,0,3,5,-1,0,3,3,1,0,3,3,2,0,3,4,1,0,3,4,2,0,3,4,3,0,3,4,4,0,3,5,3,0,3,5,4,0,3,6,3,0,3,6,4,0,3,6,-3,0,3,7,-3,0,3,7,-2,0,3,7,2,0,3,7,3,0,3,7,4,0,3,8,-3,0,3,8,-2,0,3,8,-1,0,3,8,0,0,3,8,1,0,3,8,2,0,3,8,3,0,3,8,4,0,3,-1,2,0,3,0,2,0,3,1,2,0,3,2,2,0,3,2,1,0,3,1,1,0,3,0,1,0,3,-1,1,0,3,-1,5,0,3,0,5,0,3,0,6,0,3,-1,6,0,3,-7,-3,0,3,6,-2,0,3,5,-2,0,3,8,5,0,3,8,6,0,3,8,7,0,3,-3,-5,0,3,-3,-6,0,3,5,-6,0,3,5,-5,0,3,5,-7,0,3,-3,-7,0,3,5,-8,0,3,4,-8,0,3,3,-8,0,3,2,-8,0,3,1,-8,0,3,0,-8,0,3,-1,-8,0,3,-2,-8,0,3,-3,-8,0,3,3,7,0,3,-7,-8,0,3,-7,-7,0,3,-7,-6,0,3,-7,-5,0,3,-7,-4,0,3,-6,-8,0,3,-6,-7,0,3,-6,-6,0,3,-6,-5,0,3,-6,-4,0,3,-5,-8,0,3,-5,-7,0,3,-5,-6,0,3,-5,-5,0,3,-5,-4,0,3,-4,-8,0,3,-4,-7,0,3,-4,-6,0,3,-4,-5,0,3,-4,-4,0,3,6,-8,0,3,6,-7,0,3,6,-6,0,3,6,-5,0,3,6,-4,0,3,7,-8,0,3,7,-7,0,3,7,-6,0,3,7,-5,0,3,7,-4,0,3,8,-8,0,3,8,-7,0,3,8,-6,0,3,8,-5,0,3,8,-4,0,3],"CustomFloor1":[-4,2,1,7,14,-3,3,1,8,15,-4,3,1,7,15,-5,3,1,6,15,6,4,1,8,15,5,4,1,7,15,-5,2,1,6,14,4,3,1,6,14,4,4,1,6,15,6,3,1,8,14,5,3,1,7,14,-3,2,1,8,14],"CustomFloor2":[],"CustomFloor3":[],"CustomMiddle1":[-3,4,1,10,5,-3,5,1,10,6,2,4,1,10,5,2,5,1,10,6],"CustomMiddle2":[5,-4,1,6,0,5,-3,1,6,1,-2,-1,1,5,0,-2,0,1,5,1],"CustomTop":[]}
\ No newline at end of file
+{"NavigationVertices":[{"X":134,"Y":38},{"X":138,"Y":-122},{"X":138,"Y":138},{"X":134,"Y":90},{"X":134,"Y":-6},{"X":90,"Y":-6},{"X":86,"Y":-58},{"X":86,"Y":-102},{"X":-106,"Y":-122},{"X":-38,"Y":-102},{"X":74,"Y":10},{"X":74,"Y":54},{"X":58,"Y":90},{"X":-26,"Y":38},{"X":-26,"Y":-6},{"X":90,"Y":10},{"X":-38,"Y":-58},{"X":118,"Y":54},{"X":118,"Y":38},{"X":134,"Y":138},{"X":58,"Y":138},{"X":-58,"Y":138},{"X":-58,"Y":106},{"X":-86,"Y":38},{"X":-106,"Y":106},{"X":-86,"Y":-6}],"NavigationPolygon":[[0,1,2,3],[1,0,4],[1,4,5,6,7],[8,1,7,9],[10,11,12,13,14],[6,5,15,10,14,16],[17,18,0,3],[2,19,3],[17,3,12,11],[13,12,20,21,22],[23,13,22,24],[23,24,8,25],[25,8,9,16],[14,25,16]],"Floor":[-3,-4,0,3,-2,-4,0,3,-2,-3,0,3,-3,-3,0,3,-7,-2,0,3,-7,-1,0,3,-7,0,0,3,-7,1,0,3,-7,2,0,3,-7,3,0,3,-7,4,0,3,-7,5,0,3,-6,-3,0,3,-6,-2,0,3,-6,-1,0,3,-6,0,0,3,-6,1,0,3,-6,2,0,3,-6,3,0,3,-6,4,0,3,-6,5,0,3,-5,-3,0,3,-5,-2,0,3,-5,2,0,3,-5,3,0,3,-5,4,0,3,-5,5,0,3,-4,-3,0,3,-4,-2,0,3,-4,2,0,3,-4,3,0,3,-4,4,0,3,-4,5,0,3,-3,-2,0,3,-3,2,0,3,-3,3,0,3,-3,4,0,3,-3,5,0,3,-2,-2,0,3,-2,-1,0,3,-2,0,0,3,-2,1,0,3,-2,2,0,3,-2,3,0,3,-2,4,0,3,-2,5,0,3,-4,6,0,3,-4,7,0,3,-3,6,0,3,-3,7,0,3,-2,6,0,3,-2,7,0,3,-1,3,0,3,-1,4,0,3,-1,7,0,3,0,3,0,3,0,4,0,3,0,7,0,3,1,3,0,3,1,4,0,3,1,5,0,3,1,6,0,3,1,7,0,3,2,3,0,3,2,4,0,3,2,5,0,3,2,6,0,3,2,7,0,3,3,3,0,3,3,4,0,3,3,5,0,3,3,6,0,3,-1,-4,0,3,-1,-3,0,3,-1,-2,0,3,-1,-1,0,3,-1,0,0,3,0,-4,0,3,0,-3,0,3,0,-2,0,3,0,-1,0,3,0,0,0,3,1,-4,0,3,1,-3,0,3,1,-2,0,3,1,-1,0,3,1,0,0,3,2,-4,0,3,2,-3,0,3,2,-2,0,3,2,-1,0,3,2,0,0,3,3,-4,0,3,3,-3,0,3,3,-2,0,3,3,-1,0,3,3,0,0,3,4,-4,0,3,4,-3,0,3,4,-2,0,3,4,-1,0,3,4,0,0,3,5,-4,0,3,5,-3,0,3,5,-1,0,3,3,1,0,3,3,2,0,3,4,1,0,3,4,2,0,3,4,3,0,3,4,4,0,3,5,3,0,3,5,4,0,3,6,3,0,3,6,4,0,3,6,-3,0,3,7,-3,0,3,7,-2,0,3,7,2,0,3,7,3,0,3,7,4,0,3,8,-3,0,3,8,-2,0,3,8,-1,0,3,8,0,0,3,8,1,0,3,8,2,0,3,8,3,0,3,8,4,0,3,-1,2,0,3,0,2,0,3,1,2,0,3,2,2,0,3,2,1,0,3,1,1,0,3,0,1,0,3,-1,1,0,3,-1,5,0,3,0,5,0,3,0,6,0,3,-1,6,0,3,-7,-3,0,3,6,-2,0,3,5,-2,0,3,8,5,0,3,8,6,0,3,8,7,0,3,-3,-5,0,3,-3,-6,0,3,5,-6,0,3,5,-5,0,3,5,-7,0,3,-3,-7,0,3,5,-8,0,3,4,-8,0,3,3,-8,0,3,2,-8,0,3,1,-8,0,3,0,-8,0,3,-1,-8,0,3,-2,-8,0,3,-3,-8,0,3,3,7,0,3,-7,-8,0,3,-7,-7,0,3,-7,-6,0,3,-7,-5,0,3,-7,-4,0,3,-6,-8,0,3,-6,-7,0,3,-6,-6,0,3,-6,-5,0,3,-6,-4,0,3,-5,-8,0,3,-5,-7,0,3,-5,-6,0,3,-5,-5,0,3,-5,-4,0,3,-4,-8,0,3,-4,-7,0,3,-4,-6,0,3,-4,-5,0,3,-4,-4,0,3,6,-8,0,3,6,-7,0,3,6,-6,0,3,6,-5,0,3,6,-4,0,3,7,-8,0,3,7,-7,0,3,7,-6,0,3,7,-5,0,3,7,-4,0,3,8,-8,0,3,8,-7,0,3,8,-6,0,3,8,-5,0,3,8,-4,0,3,-2,-6,0,3],"CustomFloor1":[-4,2,1,7,14,-3,3,1,8,15,-4,3,1,7,15,-5,3,1,6,15,6,4,1,8,15,5,4,1,7,15,-5,2,1,6,14,4,3,1,6,14,4,4,1,6,15,6,3,1,8,14,5,3,1,7,14,-3,2,1,8,14],"CustomFloor2":[],"CustomFloor3":[],"CustomMiddle1":[-3,4,1,10,5,-3,5,1,10,6,2,4,1,10,5,2,5,1,10,6],"CustomMiddle2":[5,-4,1,6,0,5,-3,1,6,1,-2,-1,1,5,0,-2,0,1,5,1],"CustomTop":[]}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json
new file mode 100644
index 0000000..155c178
--- /dev/null
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preinstall.json
@@ -0,0 +1 @@
+[{"Name":"Preinstall1","Weight":100,"Remark":"","AutoFill":true,"WaveList":[[{"Position":{"X":-81,"Y":25},"Size":{"X":0,"Y":0},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]},{"Position":{"X":21,"Y":31},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"1","Weapon":"weapon0003","CurrAmmon":"12","ResidueAmmo":"12"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":110,"Y":37},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"enemy0001","Weight":100,"Attr":{"Face":"-1","Weapon":"weapon0002","CurrAmmon":"7","ResidueAmmo":"7"},"Altitude":0,"VerticalSpeed":5.551115E-14}]},{"Position":{"X":-54,"Y":20},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0001","Weight":100,"Attr":{"CurrAmmon":"30","ResidueAmmo":"210"},"Altitude":8,"VerticalSpeed":5.551115E-14}]}]]}]
\ No newline at end of file
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preview.png b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preview.png
new file mode 100644
index 0000000..a1a56f6
--- /dev/null
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preview.png
Binary files differ
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preview.png.import b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preview.png.import
new file mode 100644
index 0000000..e160238
--- /dev/null
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/Preview.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cpx43bg5na8f4"
+path="res://.godot/imported/Preview.png-a179680c55da0fe1cc56e9132032b6e3.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://resource/map/tileMaps/Test1/inlet/Start2/Preview.png"
+dest_files=["res://.godot/imported/Preview.png-a179680c55da0fe1cc56e9132032b6e3.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/map/tileMaps/Test1/inlet/Start2/RoomInfo.json b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/RoomInfo.json
new file mode 100644
index 0000000..1b4a534
--- /dev/null
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/RoomInfo.json
@@ -0,0 +1 @@
+{"Position":{"X":-9,"Y":-7},"Size":{"X":19,"Y":16},"DoorAreaInfos":[],"GroupName":"Test1","RoomType":2,"RoomName":"Start2","Weight":100,"Remark":""}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/TileInfo.json b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/TileInfo.json
new file mode 100644
index 0000000..d48b637
--- /dev/null
+++ b/DungeonShooting_Godot/resource/map/tileMaps/Test1/inlet/Start2/TileInfo.json
@@ -0,0 +1 @@
+{"NavigationVertices":[{"X":6,"Y":86},{"X":122,"Y":122},{"X":-106,"Y":122},{"X":-22,"Y":86},{"X":-106,"Y":-58},{"X":-22,"Y":-22},{"X":122,"Y":-58},{"X":6,"Y":-22}],"NavigationPolygon":[[0,1,2,3],[3,2,4,5],[5,4,6,7],[6,1,0,7]],"Floor":[-3,-4,0,3,-3,-3,0,3,-3,-2,0,3,-3,-1,0,3,-3,0,0,3,-3,1,0,3,-3,2,0,3,-3,3,0,3,-3,4,0,3,-3,5,0,3,-3,6,0,3,-2,-4,0,3,-2,-3,0,3,-2,-2,0,3,-2,0,0,3,-2,1,0,3,-2,2,0,3,-2,3,0,3,-2,4,0,3,-2,5,0,3,-2,6,0,3,-1,-4,0,3,-1,-3,0,3,-1,5,0,3,-1,6,0,3,0,-4,0,3,0,-3,0,3,0,-2,0,3,0,-1,0,3,0,0,0,3,0,1,0,3,0,2,0,3,0,3,0,3,0,4,0,3,0,5,0,3,0,6,0,3,1,-4,0,3,1,-3,0,3,1,-2,0,3,1,-1,0,3,1,0,0,3,1,1,0,3,1,2,0,3,1,3,0,3,1,4,0,3,1,5,0,3,1,6,0,3,2,-4,0,3,2,-3,0,3,2,-2,0,3,2,-1,0,3,2,0,0,3,2,1,0,3,2,2,0,3,2,3,0,3,2,4,0,3,2,5,0,3,2,6,0,3,3,-4,0,3,3,-3,0,3,3,-2,0,3,3,-1,0,3,3,0,0,3,3,1,0,3,3,2,0,3,3,3,0,3,3,4,0,3,3,5,0,3,3,6,0,3,4,-4,0,3,4,-3,0,3,4,-2,0,3,4,-1,0,3,4,0,0,3,4,1,0,3,4,2,0,3,4,3,0,3,4,4,0,3,4,5,0,3,4,6,0,3,5,-4,0,3,5,-3,0,3,5,-2,0,3,5,-1,0,3,5,0,0,3,5,1,0,3,5,2,0,3,5,3,0,3,5,4,0,3,5,5,0,3,5,6,0,3,6,-4,0,3,6,-3,0,3,6,-2,0,3,6,-1,0,3,6,0,0,3,6,1,0,3,6,2,0,3,6,3,0,3,6,4,0,3,6,5,0,3,6,6,0,3,7,-4,0,3,7,-3,0,3,7,-2,0,3,7,-1,0,3,7,0,0,3,7,1,0,3,7,2,0,3,7,3,0,3,7,4,0,3,7,5,0,3,7,6,0,3,-4,6,0,3,-4,5,0,3,-4,4,0,3,-4,3,0,3,-4,2,0,3,-4,1,0,3,-4,0,0,3,-4,-1,0,3,-4,-2,0,3,-4,-3,0,3,-4,-4,0,3,-5,-4,0,3,-5,-3,0,3,-5,-2,0,3,-5,-1,0,3,-5,0,0,3,-5,1,0,3,-5,2,0,3,-5,3,0,3,-5,4,0,3,-5,5,0,3,-5,6,0,3,-6,6,0,3,-6,5,0,3,-6,4,0,3,-6,3,0,3,-6,2,0,3,-6,1,0,3,-6,0,0,3,-6,-1,0,3,-6,-2,0,3,-6,-3,0,3,-6,-4,0,3,-7,-4,0,3,-7,-3,0,3,-7,-2,0,3,-7,-1,0,3,-7,0,0,3,-7,1,0,3,-7,2,0,3,-7,3,0,3,-7,4,0,3,-7,5,0,3,-7,6,0,3,-2,-1,0,3],"CustomFloor1":[],"CustomFloor2":[],"CustomFloor3":[],"CustomMiddle1":[],"CustomMiddle2":[],"CustomTop":[]}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/resource/material/Sawtooth.tres b/DungeonShooting_Godot/resource/material/Sawtooth.tres
index 73c3175..68a3ed6 100644
--- a/DungeonShooting_Godot/resource/material/Sawtooth.tres
+++ b/DungeonShooting_Godot/resource/material/Sawtooth.tres
@@ -2,6 +2,5 @@
[ext_resource type="Shader" path="res://resource/shader/Sawtooth.gdshader" id="1_nrhtr"]
-
[resource]
shader = ExtResource("1_nrhtr")
diff --git a/DungeonShooting_Godot/resource/shader/Sawtooth.gdshader b/DungeonShooting_Godot/resource/shader/Sawtooth.gdshader
index cbbc062..09c8dd0 100644
--- a/DungeonShooting_Godot/resource/shader/Sawtooth.gdshader
+++ b/DungeonShooting_Godot/resource/shader/Sawtooth.gdshader
@@ -1,18 +1,178 @@
shader_type canvas_item;
+bool checkLB(float len, sampler2D tex, vec2 uv) {
+ int c = 0;
+ int c2 = 0;
+ if (texture(tex, uv + vec2(-len, 0.0)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(-len * 2.0, 0.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ if (c > 0) {
+ if (texture(tex, uv + vec2(0.0, -len)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(0.0, -len * 2.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ }
+ return c >= 2 && c2 <= 3;
+}
+
+bool checkLT(float len, sampler2D tex, vec2 uv) {
+ int c = 0;
+ int c2 = 0;
+ if (texture(tex, uv + vec2(-len, 0.0)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(-len * 2.0, 0.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ if (c > 0) {
+ if (texture(tex, uv + vec2(0.0, len)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(0.0, len * 2.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ }
+ return c >= 2 && c2 <= 3;
+}
+
+bool checkRB(float len, sampler2D tex, vec2 uv) {
+ int c = 0;
+ int c2 = 0;
+ if (texture(tex, uv + vec2(len, 0.0)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(len * 2.0, 0.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ if (c > 0) {
+ if (texture(tex, uv + vec2(0.0, -len)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(0.0, -len * 2.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ }
+ return c >= 2 && c2 <= 3;
+}
+
+bool checkRT(float len, sampler2D tex, vec2 uv) {
+ int c = 0;
+ int c2 = 0;
+ if (texture(tex, uv + vec2(len, 0.0)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(len * 2.0, 0.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ if (c > 0) {
+ if (texture(tex, uv + vec2(0.0, len)).a > 0.0) {
+ c++;
+ c2 += 1;
+ } else if (texture(tex, uv + vec2(0.0, len * 2.0)).a > 0.0) {
+ c++;
+ c2 += 2;
+ }
+ }
+ return c >= 2 && c2 <= 3;
+}
+
+
void vertex() {
VERTEX = VERTEX * vec2(4.0);
}
void fragment() {
- vec2 pixel_size = 1.0 / vec2(textureSize(TEXTURE, 0));
- vec4 color = vec4(0.0);
- for (int x = -1; x <= 1; x++) {
- for (int y = -1; y <= 1; y++) {
- color += texture(TEXTURE, UV + vec2(float(x), float(y)) * pixel_size / 2.0);
- }
- }
- color /= 9.0;
- COLOR = color;
-}
+ if (COLOR.a <= 0.0) {
+ int c = 0;
+ vec4 cf = vec4(0.0, 0.0, 0.0, 0.0);
+ vec4 cL = texture(TEXTURE, UV + vec2(-TEXTURE_PIXEL_SIZE.x, 0.0));
+ vec4 cr = texture(TEXTURE, UV + vec2(TEXTURE_PIXEL_SIZE.x, 0.0));
+ vec4 ct = texture(TEXTURE, UV + vec2(0.0, TEXTURE_PIXEL_SIZE.y));
+ vec4 cb = texture(TEXTURE, UV + vec2(0.0, -TEXTURE_PIXEL_SIZE.y));
+ if (cL.a > 0.0) {
+ c++;
+ cf += cL;
+ }
+ if (cr.a > 0.0) {
+ c++;
+ cf += cr;
+ }
+ if (ct.a > 0.0) {
+ c++;
+ cf += ct;
+ }
+ if (cb.a > 0.0) {
+ c++;
+ cf += cb;
+ }
+ if (c >= 2) {
+ if (cb.a > 0.0 && cL.a > 0.0) {
+ if (checkLB(TEXTURE_PIXEL_SIZE.y / 4.0, TEXTURE, UV)) {
+ cf /= float(c);
+ COLOR = cf;
+ }
+ }
+ if (ct.a > 0.0 && cL.a > 0.0) {
+ if (checkLT(TEXTURE_PIXEL_SIZE.y / 4.0, TEXTURE, UV)) {
+ cf /= float(c);
+ COLOR = cf;
+ }
+ }
+ if (cb.a > 0.0 && cr.a > 0.0) {
+ if (checkRB(TEXTURE_PIXEL_SIZE.y / 4.0, TEXTURE, UV)) {
+ cf /= float(c);
+ COLOR = cf;
+ }
+ }
+ if (ct.a > 0.0 && cr.a > 0.0) {
+ if (checkRT(TEXTURE_PIXEL_SIZE.y / 4.0, TEXTURE, UV)) {
+ cf /= float(c);
+ COLOR = cf;
+ }
+ }
+ }
+ } else {
+ int c = 0;
+ float tempV = TEXTURE_PIXEL_SIZE.x / 4.0;
+ vec4 cf = vec4(0.0, 0.0, 0.0, 0.0);
+ vec4 clt = texture(TEXTURE, UV + vec2(-tempV, tempV));
+ vec4 crt = texture(TEXTURE, UV + vec2(tempV, tempV));
+ vec4 clb = texture(TEXTURE, UV + vec2(-tempV, -tempV));
+ vec4 crb = texture(TEXTURE, UV + vec2(tempV, -tempV));
+
+ if (clt.a > 0.0) {
+ c++;
+ cf += clt;
+ }
+ if (crt.a > 0.0) {
+ c++;
+ cf += crt;
+ }
+ if (clb.a > 0.0) {
+ c++;
+ cf += clb;
+ }
+ if (crb.a > 0.0) {
+ c++;
+ cf += crb;
+ }
+ if (c > 0 && c < 2) {
+ COLOR = vec4(0.0, 0.0, 0.0, 0.0);
+ } else {
+ COLOR = cf / float(c);
+ }
+ }
+}
diff --git a/DungeonShooting_Godot/resource/sprite/brush/Temp.png b/DungeonShooting_Godot/resource/sprite/brush/Temp.png
new file mode 100644
index 0000000..1c50613
--- /dev/null
+++ b/DungeonShooting_Godot/resource/sprite/brush/Temp.png
Binary files differ
diff --git a/DungeonShooting_Godot/resource/sprite/brush/Temp.png.import b/DungeonShooting_Godot/resource/sprite/brush/Temp.png.import
new file mode 100644
index 0000000..d3e4a73
--- /dev/null
+++ b/DungeonShooting_Godot/resource/sprite/brush/Temp.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b6iklkty6p8sx"
+path="res://.godot/imported/Temp.png-eb88d17e172de4ef1d192f84370ff0de.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://resource/sprite/brush/Temp.png"
+dest_files=["res://.godot/imported/Temp.png-eb88d17e172de4ef1d192f84370ff0de.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/scene/test/TestCreateSector.tscn b/DungeonShooting_Godot/scene/test/TestCreateSector.tscn
index 795fc2e..255bb1e 100644
--- a/DungeonShooting_Godot/scene/test/TestCreateSector.tscn
+++ b/DungeonShooting_Godot/scene/test/TestCreateSector.tscn
@@ -1,13 +1,91 @@
-[gd_scene load_steps=4 format=3 uid="uid://d4axmwaqk1f55"]
+[gd_scene load_steps=10 format=3 uid="uid://d4axmwaqk1f55"]
[ext_resource type="Script" path="res://src/test/TestCreateSector.cs" id="1_ieqp4"]
[ext_resource type="Texture2D" uid="uid://uhhfgdhpk7i4" path="res://icon.png" id="2_73jok"]
+[ext_resource type="Texture2D" uid="uid://b6iklkty6p8sx" path="res://resource/sprite/brush/Temp.png" id="3_mchtg"]
+[ext_resource type="Material" uid="uid://cca0ka64xmrrd" path="res://resource/material/Sawtooth.tres" id="3_p1gue"]
+[ext_resource type="Texture2D" uid="uid://jnx4wfn5hu3u" path="res://resource/sprite/brush/Brush3.png" id="5_1h5h3"]
+[ext_resource type="Texture2D" uid="uid://betgai078na4v" path="res://resource/map/tileSet/TileSet1/Main.png" id="6_22ncj"]
+
+[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_on1ir"]
+texture = ExtResource("6_22ncj")
+0:0/0 = 0
+1:0/0 = 0
+2:0/0 = 0
+3:0/0 = 0
+4:0/0 = 0
+5:0/0 = 0
+6:0/0 = 0
+7:0/0 = 0
+8:0/0 = 0
+9:0/0 = 0
+10:0/0 = 0
+11:0/0 = 0
+0:1/0 = 0
+1:1/0 = 0
+2:1/0 = 0
+3:1/0 = 0
+4:1/0 = 0
+5:1/0 = 0
+6:1/0 = 0
+7:1/0 = 0
+8:1/0 = 0
+9:1/0 = 0
+11:1/0 = 0
+0:2/0 = 0
+1:2/0 = 0
+2:2/0 = 0
+3:2/0 = 0
+4:2/0 = 0
+5:2/0 = 0
+6:2/0 = 0
+7:2/0 = 0
+8:2/0 = 0
+9:2/0 = 0
+10:2/0 = 0
+11:2/0 = 0
+0:3/0 = 0
+1:3/0 = 0
+2:3/0 = 0
+3:3/0 = 0
+4:3/0 = 0
+5:3/0 = 0
+6:3/0 = 0
+7:3/0 = 0
+8:3/0 = 0
+9:3/0 = 0
+10:3/0 = 0
+11:3/0 = 0
+0:4/0 = 0
+1:4/0 = 0
+2:4/0 = 0
+3:4/0 = 0
+4:4/0 = 0
+5:4/0 = 0
+6:4/0 = 0
+7:4/0 = 0
+8:4/0 = 0
+9:4/0 = 0
+10:4/0 = 0
+0:5/0 = 0
+1:5/0 = 0
+2:5/0 = 0
+3:5/0 = 0
+4:5/0 = 0
+
+[sub_resource type="TileSet" id="TileSet_5gh5n"]
+sources/0 = SubResource("TileSetAtlasSource_on1ir")
[sub_resource type="CircleShape2D" id="CircleShape2D_42m3w"]
[node name="TestCreateSector" type="Node2D"]
script = ExtResource("1_ieqp4")
+[node name="TileMap" type="TileMap" parent="."]
+tile_set = SubResource("TileSet_5gh5n")
+format = 2
+layer_0/tile_data = PackedInt32Array(-65535, 0, 4, 0, 0, 4, 65536, 0, 4, 131072, 0, 4, 131073, 0, 4, 131074, 0, 4, 65538, 0, 4, 2, 0, 4, 1, 0, 4, 65537, 0, 4, 196609, 0, 4, 196610, 0, 4, 65539, 0, 4, 3, 0, 4, 131075, 0, 4, 196611, 0, 4, 262147, 0, 4, 65540, 0, 4, 4, 0, 4, 131076, 0, 4, 196612, 0, 4, 262148, 0, 4, 262146, 0, 4, 262145, 0, 4, 196608, 0, 4, 262144, 0, 4)
+
[node name="Area2D" type="Area2D" parent="."]
position = Vector2(959, 505)
@@ -20,3 +98,14 @@
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D2"]
shape = SubResource("CircleShape2D_42m3w")
+
+[node name="Sprite2D" type="Sprite2D" parent="."]
+material = ExtResource("3_p1gue")
+position = Vector2(5, -19)
+texture = ExtResource("3_mchtg")
+centered = false
+
+[node name="Sprite2D2" type="Sprite2D" parent="."]
+position = Vector2(32, 43)
+texture = ExtResource("5_1h5h3")
+centered = false
diff --git a/DungeonShooting_Godot/src/framework/activity/hurt/HurtArea.cs b/DungeonShooting_Godot/src/framework/activity/hurt/HurtArea.cs
index 8631faa..b83bd6b 100644
--- a/DungeonShooting_Godot/src/framework/activity/hurt/HurtArea.cs
+++ b/DungeonShooting_Godot/src/framework/activity/hurt/HurtArea.cs
@@ -1,17 +1,19 @@
using Godot;
+///
+/// 可被子弹击中的区域
+///
[Tool]
public partial class HurtArea : Area2D, IHurt
{
- public delegate void HurtDelegate(ActivityObject target, int damage, float angle);
+ ///
+ /// 所属角色
+ ///
+ public Role Master { get; private set; }
- public event HurtDelegate OnHurtEvent;
-
- public ActivityObject ActivityObject { get; private set; }
-
- public void InitActivityObject(ActivityObject activityObject)
+ public void InitRole(Role role)
{
- ActivityObject = activityObject;
+ Master = role;
}
public override void _Ready()
@@ -19,11 +21,19 @@
Monitoring = false;
}
+ public bool CanHurt(CampEnum targetCamp)
+ {
+ //无敌状态
+ if (Master.Invincible)
+ {
+ return true;
+ }
+
+ return Master.IsEnemy(targetCamp);
+ }
+
public void Hurt(ActivityObject target, int damage, float angle)
{
- if (OnHurtEvent != null)
- {
- OnHurtEvent(target, damage, angle);
- }
+ Master.CallDeferred(nameof(Master.HurtHandler), target, damage, angle);
}
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/activity/hurt/IHurt.cs b/DungeonShooting_Godot/src/framework/activity/hurt/IHurt.cs
index fd27abc..da56662 100644
--- a/DungeonShooting_Godot/src/framework/activity/hurt/IHurt.cs
+++ b/DungeonShooting_Godot/src/framework/activity/hurt/IHurt.cs
@@ -4,6 +4,12 @@
public interface IHurt
{
///
+ /// 返回是否可以造成伤害
+ ///
+ /// 攻击目标所属层级
+ bool CanHurt(CampEnum targetCamp);
+
+ ///
/// 受到伤害
///
/// 触发伤害的对象, 为 null 表示不存在对象或者对象已经被销毁
diff --git a/DungeonShooting_Godot/src/framework/common/NodeExtend.cs b/DungeonShooting_Godot/src/framework/common/NodeExtend.cs
index e04437d..50d1ad9 100644
--- a/DungeonShooting_Godot/src/framework/common/NodeExtend.cs
+++ b/DungeonShooting_Godot/src/framework/common/NodeExtend.cs
@@ -21,7 +21,7 @@
if (hurt is HurtArea hurtArea)
{
- return hurtArea.ActivityObject;
+ return hurtArea.Master;
}
return null;
diff --git a/DungeonShooting_Godot/src/framework/common/Utils.cs b/DungeonShooting_Godot/src/framework/common/Utils.cs
index 416b796..54f7ba1 100644
--- a/DungeonShooting_Godot/src/framework/common/Utils.cs
+++ b/DungeonShooting_Godot/src/framework/common/Utils.cs
@@ -67,6 +67,17 @@
return angle;
}
+
+ ///
+ /// 判断a和b是否在同一梯度下
+ ///
+ ///
+ ///
+ /// 梯度间距
+ public static bool IsSameGradient(float a, float b, float gradient)
+ {
+ return (int)(a / gradient) == (int)(b / gradient);
+ }
///
/// 根据步长吸附值
diff --git a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs
index 10f775d..3c9123d 100644
--- a/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs
+++ b/DungeonShooting_Godot/src/framework/map/AffiliationArea.cs
@@ -64,7 +64,7 @@
Monitoring = true;
Monitorable = false;
CollisionLayer = PhysicsLayer.None;
- CollisionMask = PhysicsLayer.Prop | PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Debris | PhysicsLayer.Throwing;
+ CollisionMask = PhysicsLayer.Prop | PhysicsLayer.Role | PhysicsLayer.Debris | PhysicsLayer.Throwing | PhysicsLayer.Obstacle;
BodyEntered += OnBodyEntered;
BodyExited += OnBodyExited;
diff --git a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs
index 3f82e5d..b439592 100644
--- a/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs
+++ b/DungeonShooting_Godot/src/framework/map/DungeonGenerator.cs
@@ -207,14 +207,14 @@
if (errorCode == GenerateRoomErrorCode.OutArea)
{
_failCount++;
- Debug.Log("超出区域失败次数: " + _failCount);
+ //Debug.Log("超出区域失败次数: " + _failCount);
if (_failCount >= _maxFailCount)
{
//_enableLimitRange = false;
_failCount = 0;
_rangeX += 50;
_rangeY += 50;
- Debug.Log("生成房间失败次数过多, 增大区域");
+ //Debug.Log("生成房间失败次数过多, 增大区域");
}
}
diff --git a/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs b/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs
index 1b1ab92..67007d2 100644
--- a/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs
+++ b/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs
@@ -318,6 +318,7 @@
}
else
{
+ var oldA = imagePixel.Color.A;
imagePixel.Color.A -= imagePixel.Material.WriteOffSpeed * (_runTime - imagePixel.TempTime);
if (imagePixel.Color.A <= 0) //完全透明了
@@ -328,7 +329,7 @@
imagePixel.IsUpdate = false;
return true;
}
- else
+ else if (!Utils.IsSameGradient(oldA, imagePixel.Color.A, GameConfig.LiquidGradient)) //同一渐变梯度下才会有颜色变化
{
_changeFlag = true;
_image.SetPixel(imagePixel.X, imagePixel.Y, imagePixel.Color);
diff --git a/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs b/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
index 2a63757..4e398ae 100644
--- a/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
+++ b/DungeonShooting_Godot/src/framework/map/preinstall/RoomPreinstall.cs
@@ -317,7 +317,7 @@
foreach (var preloadData in _readyList)
{
//有敌人
- if (!hasEnemy && preloadData.ActivityObject.CollisionWithMask(PhysicsLayer.Enemy))
+ if (!hasEnemy && preloadData.ActivityObject is Role role && role.IsEnemyWithPlayer())
{
hasEnemy = true;
}
@@ -332,7 +332,7 @@
if (!hasEnemy)
{
hasEnemy = RoomInfo.AffiliationArea.ExistIncludeItem(
- activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy)
+ activityObject => activityObject is Role role && role.IsEnemyWithPlayer()
);
}
diff --git a/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs b/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs
index 740846d..3459432 100644
--- a/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs
+++ b/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs
@@ -474,7 +474,7 @@
//房间内有敌人, 或者会刷新敌人才会关门
var hasEnemy = false;
- if (AffiliationArea.ExistEnterItem(activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy))) //先判断房间里面是否有敌人
+ if (AffiliationArea.ExistEnterItem(activityObject => activityObject is Role role && role.IsEnemyWithPlayer())) //先判断房间里面是否有敌人
{
hasEnemy = true;
}
diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs
index 0c2112e..53a5b93 100644
--- a/DungeonShooting_Godot/src/game/GameApplication.cs
+++ b/DungeonShooting_Godot/src/game/GameApplication.cs
@@ -134,7 +134,7 @@
//固定帧率
//Engine.MaxFps = TargetFps;
//调试绘制开关
- ActivityObject.IsDebug = false;
+ ActivityObject.IsDebug = true;
//Engine.TimeScale = 0.2f;
//调整窗口分辨率
OnWindowSizeChanged();
diff --git a/DungeonShooting_Godot/src/game/GameConfig.cs b/DungeonShooting_Godot/src/game/GameConfig.cs
index 1874314..8a36f3c 100644
--- a/DungeonShooting_Godot/src/game/GameConfig.cs
+++ b/DungeonShooting_Godot/src/game/GameConfig.cs
@@ -16,6 +16,11 @@
// ----------------------- 常量 -----------------------
+
+ ///
+ /// 液体画布渐变梯度
+ ///
+ public const float LiquidGradient = 0.1f;
///
/// 连接房间的过道宽度
diff --git a/DungeonShooting_Godot/src/game/World.cs b/DungeonShooting_Godot/src/game/World.cs
deleted file mode 100644
index 34add95..0000000
--- a/DungeonShooting_Godot/src/game/World.cs
+++ /dev/null
@@ -1,202 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using Godot;
-
-///
-/// 游戏世界
-///
-public partial class World : CanvasModulate, ICoroutine
-{
- ///
- /// 当前的游戏世界对象
- ///
- public static World Current => GameApplication.Instance.DungeonManager.CurrWorld;
-
- ///
- /// 当前操作的玩家
- ///
- public Player Player { get; private set; }
-
- ///
- /// //对象根节点
- ///
- public Node2D NormalLayer;
-
- ///
- /// 对象根节点, 带y轴排序功能
- ///
- public Node2D YSortLayer;
-
- ///
- /// 地图根节点
- ///
- public TileMap TileRoot;
-
- public Node2D StaticSpriteRoot;
- public Node2D AffiliationAreaRoot;
- public Node2D FogMaskRoot;
- public Node2D NavigationRoot;
-
- ///
- /// 是否暂停
- ///
- public bool Pause
- {
- get => _pause;
- set
- {
- if (_pause != value)
- {
- _pause = value;
- if (value)
- {
- ProcessMode = ProcessModeEnum.WhenPaused;
- }
- else
- {
- ProcessMode = ProcessModeEnum.Inherit;
- }
- }
- }
- }
-
- ///
- /// 所有被扔在地上的武器
- ///
- public HashSet Weapon_UnclaimedWeapons { get; } = new HashSet();
-
- ///
- /// 记录所有存活的敌人
- ///
- public List Enemy_InstanceList { get; } = new List();
-
- ///
- /// 随机数对象
- ///
- public SeedRandom Random { get; private set; }
-
- ///
- /// 随机对象池
- ///
- public RandomPool RandomPool { get; private set; }
-
- ///
- /// 角色死亡事件
- ///
- public event Action OnRoleDieEvent;
-
- private bool _pause = false;
- private List _coroutineList;
-
- public override void _Ready()
- {
- //TileRoot.YSortEnabled = false;
- NormalLayer = GetNode("TileRoot/NormalLayer");
- YSortLayer = GetNode("TileRoot/YSortLayer");
- TileRoot = GetNode("TileRoot");
- StaticSpriteRoot = GetNode("TileRoot/StaticSpriteRoot");
- FogMaskRoot = GetNode("TileRoot/FogMaskRoot");
- NavigationRoot = GetNode("TileRoot/NavigationRoot");
- AffiliationAreaRoot = GetNode("TileRoot/AffiliationAreaRoot");
- }
-
- public override void _Process(double delta)
- {
- //协程更新
- ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, (float)delta);
- }
-
- ///
- /// 获取指定层级根节点
- ///
- public Node2D GetRoomLayer(RoomLayerEnum layerEnum)
- {
- switch (layerEnum)
- {
- case RoomLayerEnum.NormalLayer:
- return NormalLayer;
- case RoomLayerEnum.YSortLayer:
- return YSortLayer;
- }
-
- return null;
- }
-
- ///
- /// 设置当前操作的玩家对象
- ///
- public void SetCurrentPlayer(Player player)
- {
- Player = player;
- //设置相机和鼠标跟随玩家
- GameCamera.Main.SetFollowTarget(player);
- GameApplication.Instance.Cursor.SetMountRole(player);
- }
-
- ///
- /// 通知其他敌人发现目标了
- ///
- /// 发送通知的角色
- /// 目标
- public void NotifyEnemyTarget(Role self, ActivityObject target)
- {
- foreach (var role in Enemy_InstanceList)
- {
- if (role != self && !role.IsDestroyed && role.AffiliationArea == self.AffiliationArea)
- {
- //将未发现目标的敌人状态置为惊讶状态
- var controller = role.StateController;
- //延时通知效果
- role.CallDelay(Utils.Random.RandomRangeFloat(0.2f, 1f), () =>
- {
- if (controller.CurrState == AIStateEnum.AiNormal)
- {
- controller.ChangeState(AIStateEnum.AiLeaveFor, target);
- }
- });
- }
- }
- }
-
- public long StartCoroutine(IEnumerator able)
- {
- return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
- }
-
- public void StopCoroutine(long coroutineId)
- {
- ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
- }
-
- public bool IsCoroutineOver(long coroutineId)
- {
- return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId);
- }
-
- public void StopAllCoroutine()
- {
- ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
- }
-
- ///
- /// 初始化随机池
- ///
- public void InitRandomPool(SeedRandom random)
- {
- Random = random;
- RandomPool = new RandomPool(this);
- }
-
- ///
- /// 角色死亡
- ///
- public void OnRoleDie(Role role)
- {
- if (OnRoleDieEvent != null)
- {
- OnRoleDieEvent(role);
- }
- }
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs b/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs
index 17edff3..52af65a 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/explode/Explode.cs
@@ -26,21 +26,26 @@
public CircleShape2D CircleShape { get; private set; }
///
- /// 爆炸攻击的层级
- ///
- public uint AttackLayer { get; private set; }
-
- ///
/// 产生爆炸的子弹数据
///
public BulletData BulletData { get; private set; }
+
+ ///
+ /// 所属阵营
+ ///
+ public CampEnum Camp { get; private set; }
private bool _init = false;
private float _hitRadius;
private int _harm;
private float _repelledRadius;
private float _maxRepelled;
-
+
+ public override void _Ready()
+ {
+ CollisionMask = Role.AttackLayer;
+ }
+
public void Destroy()
{
if (IsDestroyed)
@@ -56,12 +61,12 @@
/// 初始化爆炸数据
///
/// 产生爆炸的子弹数据
- /// 攻击的层级
+ /// 所属阵营
/// 伤害半径
/// 造成的伤害
/// 击退半径
/// 最大击退速度
- public void Init(BulletData bulletData, uint attackLayer, float hitRadius, int harm, float repelledRadius, float maxRepelled)
+ public void Init(BulletData bulletData, CampEnum camp, float hitRadius, int harm, float repelledRadius, float maxRepelled)
{
if (!_init)
{
@@ -74,13 +79,12 @@
BodyEntered += OnBodyEntered;
}
+ Camp = camp;
BulletData = bulletData;
- AttackLayer = attackLayer;
_hitRadius = hitRadius;
_harm = harm;
_repelledRadius = repelledRadius;
_maxRepelled = maxRepelled;
- CollisionMask = attackLayer | PhysicsLayer.Prop | PhysicsLayer.Debris;
CircleShape.Radius = Mathf.Max(hitRadius, maxRepelled);
//冲击波
@@ -162,18 +166,22 @@
var len = temp.Length();
var angle = temp.Angle();
- if (len <= _hitRadius) //在伤害半径内
+ if (hurt.CanHurt(Camp))
{
- hurt.Hurt(BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, _harm, angle);
- }
-
- if (len <= _repelledRadius) //击退半径内
- {
- var o = hurt.GetActivityObject();
- if (o != null)
+ var target = BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole;
+ if (len <= _hitRadius) //在伤害半径内
{
- var repelled = (_repelledRadius - len) / _repelledRadius * _maxRepelled;
- o.AddRepelForce(Vector2.FromAngle(angle) * repelled);
+ hurt.Hurt(target, _harm, angle);
+ }
+
+ if (len <= _repelledRadius) //击退半径内
+ {
+ var o = hurt.GetActivityObject();
+ if (o != null)
+ {
+ var repelled = (_repelledRadius - len) / _repelledRadius * _maxRepelled;
+ o.AddRepelForce(Vector2.FromAngle(angle) * repelled);
+ }
}
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs b/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs
index ebfb3f2..af0a9c4 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs
@@ -24,18 +24,14 @@
public Sprite2D LineSprite { get; private set; }
public RectangleShape2D Shape { get; private set; }
+ public CampEnum Camp { get; set; }
+
public event Action OnReclaimEvent;
public event Action OnLeavePoolEvent;
public bool IsRecycled { get; set; }
public string Logotype { get; set; }
- public uint AttackLayer
- {
- get => CollisionMask;
- set => CollisionMask = value;
- }
-
public BulletData BulletData { get; private set; }
public BulletStateEnum State { get; protected set; } = BulletStateEnum.Normal;
@@ -49,12 +45,17 @@
private Tween _tween;
private bool _init = false;
- public void InitData(BulletData data, uint attackLayer)
+ public override void _Ready()
{
- InitData(data, attackLayer, LaserDefaultWidth);
+ CollisionMask = Role.AttackLayer;
}
- public void InitData(BulletData data, uint attackLayer, float width)
+ public void InitData(BulletData data, CampEnum camp)
+ {
+ InitData(data, camp, LaserDefaultWidth);
+ }
+
+ public void InitData(BulletData data, CampEnum camp, float width)
{
if (!_init)
{
@@ -70,9 +71,9 @@
_init = true;
}
+ Camp = camp;
ZIndex = 1;
BulletData = data;
- AttackLayer = attackLayer;
Position = data.Position;
Rotation = data.Rotation;
@@ -103,7 +104,7 @@
LineSprite.Scale = new Vector2(0, width * _pixelScale);
//如果子弹会对玩家造成伤害, 则显示成红色
- if (BulletData.World.Player.CollisionWithMask(attackLayer))
+ if (BulletData.TriggerRole != null && BulletData.TriggerRole.IsEnemyWithPlayer())
{
LineSprite.Modulate = new Color(2.5f, 0.5f, 0.5f);
}
@@ -191,7 +192,7 @@
bulletData.BounceCount -= 1;
bulletData.MaxDistance = newDistance;
bulletData.Rotation = rotation;
- FireManager.ShootBullet(bulletData, AttackLayer);
+ FireManager.ShootBullet(bulletData, Camp);
}
}
}
@@ -214,17 +215,21 @@
private void HandlerCollision(IHurt hurt)
{
- if (BulletData.Repel != 0)
+ if (hurt.CanHurt(Camp))
{
- var o = hurt.GetActivityObject();
- if (o != null && o is not Player) //目标不是玩家才会触发击退
+ if (BulletData.Repel != 0)
{
- o.AddRepelForce(Vector2.FromAngle(Rotation) * BulletData.Repel);
+ var o = hurt.GetActivityObject();
+ if (o != null && o is not Player) //目标不是玩家才会触发击退
+ {
+ o.AddRepelForce(Vector2.FromAngle(Rotation) * BulletData.Repel);
+ }
}
+
+ //造成伤害
+ var target = BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole;
+ hurt.Hurt(target, BulletData.Harm, Rotation);
}
-
- //造成伤害
- hurt.Hurt(BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, BulletData.Harm, Rotation);
}
public long StartCoroutine(IEnumerator able)
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/Arrow.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/Arrow.cs
index 3f1ad52..dc53286 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/normal/Arrow.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/Arrow.cs
@@ -10,9 +10,9 @@
[Export, ExportFillNode]
public AnimatedSprite2D HalfSprite { get; set; }
- public override void InitData(BulletData data, uint attackLayer)
+ public override void InitData(BulletData data, CampEnum camp)
{
- base.InitData(data, attackLayer);
+ base.InitData(data, camp);
SetEnableMovement(true);
EnableVerticalMotion = false;
DefaultLayer = RoomLayerEnum.NormalLayer;
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs
index 79174e7..129e855 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs
@@ -21,9 +21,12 @@
public override void OnCollisionTarget(IHurt o)
{
- State = BulletStateEnum.CollisionTarget;
- PlayBoom();
- LogicalFinish();
+ if (o.CanHurt(Camp))
+ {
+ State = BulletStateEnum.CollisionTarget;
+ PlayBoom();
+ LogicalFinish();
+ }
}
public override void OnMoveCollision(KinematicCollision2D lastSlideCollision)
@@ -59,7 +62,7 @@
explode.Position = pos;
explode.RotationDegrees = Utils.Random.RandomRangeInt(0, 360);
explode.AddToActivityRootDeferred(RoomLayerEnum.YSortLayer);
- explode.Init(BulletData, AttackLayer, 25, BulletData.Harm, 50, BulletData.Repel);
+ explode.Init(BulletData, Camp, 25, BulletData.Harm, 50, BulletData.Repel);
explode.RunPlay(BulletData.TriggerRole);
if (AffiliationArea != null)
{
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs
index 5ce3d20..d96b193 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/Bullet.cs
@@ -12,9 +12,12 @@
{
public event Action OnReclaimEvent;
public event Action OnLeavePoolEvent;
+
public bool IsRecycled { get; set; }
public string Logotype { get; set; }
+ public CampEnum Camp { get; set; }
+
///
/// 子弹伤害碰撞区域
///
@@ -34,15 +37,6 @@
public Array Particles2D { get; set; }
///
- /// 攻击的层级
- ///
- public uint AttackLayer
- {
- get => CollisionArea.CollisionMask;
- set => CollisionArea.CollisionMask = value;
- }
-
- ///
/// 子弹使用的数据
///
public BulletData BulletData { get; private set; }
@@ -77,9 +71,11 @@
base.OnInit();
OutlineColor = new Color(2.5f, 0, 0);
SetBlendColor(new Color(2.5f, 2.5f, 2.5f));
+
+ CollisionArea.CollisionMask = Role.AttackLayer;
}
- public virtual void InitData(BulletData data, uint attackLayer)
+ public virtual void InitData(BulletData data, CampEnum camp)
{
if (!_init)
{
@@ -87,13 +83,13 @@
CollisionArea.BodyEntered += OnBodyEntered;
_init = true;
}
-
+
+ Camp = camp;
CurrentBounce = 0;
CurrentPenetration = 0;
CurrFlyDistance = 0;
BulletData = data;
- AttackLayer = attackLayer;
Rotation = data.Rotation;
var triggerRole = data.TriggerRole;
@@ -120,7 +116,7 @@
MoveController.AddForce(new Vector2(data.FlySpeed, 0).Rotated(Rotation));
//如果子弹会对玩家造成伤害, 则显示红色描边
- if (World.Player != null && World.Player.CollisionWithMask(attackLayer))
+ if (triggerRole != null && triggerRole.IsEnemyWithPlayer())
{
if (!IsEnemyBullet)
{
@@ -193,25 +189,29 @@
///
public virtual void OnCollisionTarget(IHurt hurt)
{
- OnPlayDisappearEffect();
- if (BulletData.Repel != 0)
+ if (hurt.CanHurt(Camp))
{
- var o = hurt.GetActivityObject();
- if (o != null && o is not Player) //目标不是玩家才会触发击退
+ OnPlayDisappearEffect();
+ if (BulletData.Repel != 0)
{
- o.AddRepelForce(Velocity.Normalized() * BulletData.Repel);
+ var o = hurt.GetActivityObject();
+ if (o != null && o is not Player) //目标不是玩家才会触发击退
+ {
+ o.AddRepelForce(Velocity.Normalized() * BulletData.Repel);
+ }
}
- }
-
- //造成伤害
- hurt.Hurt(BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, BulletData.Harm, Rotation);
-
- //穿透次数
- CurrentPenetration++;
- if (CurrentPenetration > BulletData.Penetration)
- {
- State = BulletStateEnum.CollisionTarget;
- CallDeferred(nameof(LogicalFinish));
+
+ //造成伤害
+ var target = BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole;
+ hurt.Hurt(target, BulletData.Harm, Rotation);
+
+ //穿透次数
+ CurrentPenetration++;
+ if (CurrentPenetration > BulletData.Penetration)
+ {
+ State = BulletStateEnum.CollisionTarget;
+ CallDeferred(nameof(LogicalFinish));
+ }
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/IBullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/IBullet.cs
index a642541..0e2df83 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/normal/IBullet.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/IBullet.cs
@@ -14,9 +14,10 @@
event Action OnLeavePoolEvent;
///
- /// 攻击的层级
+ /// 子弹所在阵营
///
- uint AttackLayer { get; set; }
+ CampEnum Camp { get; set; }
+
///
/// 子弹数据
///
@@ -30,7 +31,8 @@
///
/// 初始化子弹数据
///
- void InitData(BulletData data, uint attackLayer);
+ void InitData(BulletData data, CampEnum camp);
+
///
/// 子弹运行逻辑执行完成
///
diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/TrailBullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/TrailBullet.cs
index 67f6da9..d459b56 100644
--- a/DungeonShooting_Godot/src/game/activity/bullet/normal/TrailBullet.cs
+++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/TrailBullet.cs
@@ -8,9 +8,9 @@
private static Color EnemyTerrainColor = new Color(1.5f, 0, 0, 0.7f);
private Trail trail;
- public override void InitData(BulletData data, uint attackLayer)
+ public override void InitData(BulletData data, CampEnum camp)
{
- base.InitData(data, attackLayer);
+ base.InitData(data, camp);
trail = ObjectManager.GetPoolItem(ResourcePath.prefab_effect_common_Trail0001_tscn);
trail.SetTarget(AnimatedSprite);
diff --git a/DungeonShooting_Godot/src/game/activity/item/ObstacleObject.cs b/DungeonShooting_Godot/src/game/activity/item/ObstacleObject.cs
index 46ed568..f49703d 100644
--- a/DungeonShooting_Godot/src/game/activity/item/ObstacleObject.cs
+++ b/DungeonShooting_Godot/src/game/activity/item/ObstacleObject.cs
@@ -7,6 +7,11 @@
[Tool]
public partial class ObstacleObject : ActivityObject, IHurt
{
+ public virtual bool CanHurt(CampEnum targetCamp)
+ {
+ return true;
+ }
+
public virtual void Hurt(ActivityObject target, int damage, float angle)
{
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/CampEnum.cs b/DungeonShooting_Godot/src/game/activity/role/CampEnum.cs
index 6954070..6ba2bb7 100644
--- a/DungeonShooting_Godot/src/game/activity/role/CampEnum.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/CampEnum.cs
@@ -1,10 +1,28 @@
public enum CampEnum
{
- // 阵营1, 玩家
+ ///
+ /// 无阵营, 所有角色都视为敌人
+ ///
+ None,
+ ///
+ /// 和平阵营, 不会被攻击
+ ///
+ Peace,
+ ///
+ /// 阵营1, 玩家
+ ///
Camp1,
- // 阵营2, 敌人
+ ///
+ /// 阵营2, 敌人
+ ///
Camp2,
- // 阵营3, 中立单位
- Camp3
+ ///
+ /// 阵营3, 敌人2
+ ///
+ Camp3,
+ ///
+ /// 阵营4, 敌人3
+ ///
+ Camp4,
}
\ 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
index 850cba3..7b36d4d 100644
--- a/DungeonShooting_Godot/src/game/activity/role/Role.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/Role.cs
@@ -11,6 +11,11 @@
public abstract partial class Role : ActivityObject
{
///
+ /// 攻击目标的碰撞器所属层级, 数据源自于:
+ ///
+ public const uint AttackLayer = PhysicsLayer.Wall | PhysicsLayer.Obstacle | PhysicsLayer.HurtArea;
+
+ ///
/// 当前角色对其他角色造成伤害时对回调
/// 参数1为目标角色
/// 参数2为造成对伤害值
@@ -28,11 +33,6 @@
public RoleState RoleState { get; private set; }
///
- /// 默认攻击对象层级
- ///
- public const uint DefaultAttackLayer = PhysicsLayer.Player | PhysicsLayer.Enemy | PhysicsLayer.Obstacle;
-
- ///
/// 伤害区域
///
[Export, ExportFillNode]
@@ -47,17 +47,7 @@
///
/// 所属阵营
///
- public CampEnum Camp;
-
- ///
- /// 攻击目标的碰撞器所属层级, 数据源自于:
- ///
- public uint AttackLayer { get; set; } = PhysicsLayer.Wall | PhysicsLayer.Obstacle;
-
- ///
- /// 该角色敌对目标的碰撞器所属层级, 数据源自于:
- ///
- public uint EnemyLayer { get; set; } = PhysicsLayer.Enemy;
+ public CampEnum Camp { get; set; }
///
/// 携带的被动道具列表
@@ -282,20 +272,11 @@
{
if (value) //无敌状态
{
- if (HurtArea != null)
- {
- HurtArea.CollisionLayer = _currentLayer;
- }
-
_flashingInvincibleTimer = -1;
_flashingInvincibleFlag = false;
}
else //正常状态
{
- if (HurtArea != null)
- {
- HurtArea.CollisionLayer = _currentLayer;
- }
SetBlendModulate(new Color(1, 1, 1, 1));
}
}
@@ -335,7 +316,6 @@
private Vector2 _startScale;
//当前可互动的物体
private CheckInteractiveResult _currentResultData;
- private uint _currentLayer;
//闪烁计时器
private float _flashingInvincibleTimer = -1;
//闪烁状态
@@ -471,6 +451,20 @@
{
}
+ public override void EnterTree()
+ {
+ if (!World.Role_InstanceList.Contains(this))
+ {
+ World.Role_InstanceList.Add(this);
+ }
+ }
+
+ public override void ExitTree()
+ {
+ World.Role_InstanceList.Remove(this);
+ }
+
+
public override void OnInit()
{
RoleState = OnCreateRoleState();
@@ -479,15 +473,7 @@
_startScale = Scale;
- HurtArea.InitActivityObject(this);
- HurtArea.CollisionLayer = CollisionLayer;
- HurtArea.CollisionMask = PhysicsLayer.None;
- _currentLayer = HurtArea.CollisionLayer;
- //CollisionLayer = PhysicsLayer.None;
- HurtArea.OnHurtEvent += (target, damage, angle) =>
- {
- CallDeferred(nameof(HurtHandler), target, damage, angle);
- };
+ HurtArea.InitRole(this);
Face = FaceDirection.Right;
@@ -857,7 +843,7 @@
/// 触发伤害的对象, 为 null 表示不存在对象或者对象已经被销毁
/// 伤害的量
/// 伤害角度(弧度制)
- protected virtual void HurtHandler(ActivityObject target, int damage, float angle)
+ public virtual void HurtHandler(ActivityObject target, int damage, float angle)
{
//受伤闪烁, 无敌状态
if (Invincible)
@@ -1016,6 +1002,33 @@
return this == World.Player;
}
+
+ ///
+ /// 返回指定角色是否是敌人
+ ///
+ public bool IsEnemy(Role other)
+ {
+ if (other.Camp == Camp || other.Camp == CampEnum.Peace || Camp == CampEnum.Peace)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// 返回指定阵营是否是敌人
+ ///
+ public bool IsEnemy(CampEnum otherCamp)
+ {
+ if (otherCamp == Camp || otherCamp == CampEnum.Peace || Camp == CampEnum.Peace)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
///
/// 是否是玩家的敌人
///
@@ -1025,7 +1038,7 @@
{
return false;
}
- return CollisionWithMask(World.Player.EnemyLayer);
+ return IsEnemy(World.Player);
}
///
@@ -1413,8 +1426,7 @@
}
else if (body is Bullet bullet) //攻击子弹
{
- var attackLayer = bullet.AttackLayer;
- if (CollisionWithMask(attackLayer)) //是攻击玩家的子弹
+ if (IsEnemy(bullet.BulletData.TriggerRole))
{
bullet.OnPlayDisappearEffect();
bullet.Destroy();
@@ -1424,21 +1436,24 @@
private void HandlerCollision(IHurt hurt, Weapon activeWeapon)
{
- var damage = Utils.Random.RandomConfigRange(activeWeapon.Attribute.MeleeAttackHarmRange);
- damage = RoleState.CalcDamage(damage);
-
- var o = hurt.GetActivityObject();
- var pos = hurt.GetPosition();
- if (o != null && o is not Player) //不是玩家才能被击退
+ if (hurt.CanHurt(Camp))
{
- var attr = IsAi ? activeWeapon.AiUseAttribute : activeWeapon.PlayerUseAttribute;
- var repel = Utils.Random.RandomConfigRange(attr.MeleeAttackRepelRange);
- var position = pos - MountPoint.GlobalPosition;
- var v2 = position.Normalized() * repel;
- o.AddRepelForce(v2);
+ var damage = Utils.Random.RandomConfigRange(activeWeapon.Attribute.MeleeAttackHarmRange);
+ damage = RoleState.CalcDamage(damage);
+
+ var o = hurt.GetActivityObject();
+ var pos = hurt.GetPosition();
+ if (o != null && o is not Player) //不是玩家才能被击退
+ {
+ var attr = IsAi ? activeWeapon.AiUseAttribute : activeWeapon.PlayerUseAttribute;
+ var repel = Utils.Random.RandomConfigRange(attr.MeleeAttackRepelRange);
+ var position = pos - MountPoint.GlobalPosition;
+ var v2 = position.Normalized() * repel;
+ o.AddRepelForce(v2);
+ }
+
+ hurt.Hurt(this, damage, (pos - GlobalPosition).Angle());
}
-
- hurt.Hurt(this, damage, (pos - GlobalPosition).Angle());
}
protected override void OnDestroy()
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/AIStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/ai/AIStateEnum.cs
new file mode 100644
index 0000000..9b923d5
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/AIStateEnum.cs
@@ -0,0 +1,40 @@
+
+public enum AIStateEnum
+{
+ ///
+ /// Ai 状态, 正常, 未发现目标
+ ///
+ AiNormal,
+ ///
+ /// 找到玩家,准备通知其他敌人
+ ///
+ AiNotify,
+ ///
+ /// 惊讶状态
+ ///
+ AiAstonished,
+ ///
+ /// 收到其他敌人通知, 前往发现目标的位置
+ ///
+ AiLeaveFor,
+ ///
+ /// 发现目标, 目标不在视野内, 但是知道位置
+ ///
+ AiTailAfter,
+ ///
+ /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火
+ ///
+ AiFollowUp,
+ ///
+ /// 距离足够近, 在目标附近随机移动
+ ///
+ AiSurround,
+ ///
+ /// Ai 寻找弹药
+ ///
+ AiFindAmmo,
+ ///
+ /// Ai攻击
+ ///
+ AiAttack,
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
index 2eba496..2935087 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/AiRole.cs
@@ -1,4 +1,5 @@
+using System.Collections.Generic;
using AiState;
using Godot;
@@ -42,6 +43,18 @@
public Marker2D FirePoint { get; set; }
///
+ /// 视野区域
+ ///
+ [Export, ExportFillNode]
+ public Area2D ViewArea { get; set; }
+
+ ///
+ /// 视野区域碰撞器形状
+ ///
+ [Export, ExportFillNode]
+ public CollisionPolygon2D ViewAreaCollision { get; set; }
+
+ ///
/// 当前敌人所看向的对象, 也就是枪口指向的对象
///
public ActivityObject LookTarget { get; set; }
@@ -55,11 +68,27 @@
/// 锁定目标已经走过的时间
///
public float LockTargetTime { get; set; } = 0;
-
+
///
/// 视野半径, 单位像素, 发现玩家后改视野范围可以穿墙
///
- public float ViewRange { get; set; } = 250;
+ public float ViewRange
+ {
+ get => _viewRange;
+ set
+ {
+ if (_viewRange != value)
+ {
+ _viewRange = value;
+ if (ViewAreaCollision != null)
+ {
+ ViewAreaCollision.Polygon = Utils.CreateSectorPolygon(0, _viewRange, 120, 4);
+ }
+ }
+ }
+ }
+
+ private float _viewRange = -1;
///
/// 发现玩家后跟随玩家的视野半径
@@ -80,11 +109,25 @@
/// 当前Ai是否有攻击欲望
///
public bool HasAttackDesire { get; private set; } = true;
+
+ ///
+ /// 是否有移动欲望, 仅在 AiNormal 状态下有效, 其他状态都可以移动
+ ///
+ public bool HasMoveDesire { get; private set; } = true;
+
+ ///
+ /// 临时存储攻击目标, 获取该值请调用 GetAttackTarget() 函数
+ ///
+ private Role AttackTarget { get; set; } = null;
+
+ private HashSet _viewTargets = new HashSet();
public override void OnInit()
{
base.OnInit();
IsAi = true;
+ ViewArea.BodyEntered += OnViewAreaBodyEntered;
+ ViewArea.BodyExited += OnViewAreaBodyExited;
StateController = AddComponent>();
@@ -108,9 +151,32 @@
///
/// 获取攻击的目标对象, 当 HasAttackDesire 为 true 时才会调用
///
- public virtual Role GetAttackTarget()
+ /// 上一次发现的角色在本次检测中是否开启视野透视
+ public Role GetAttackTarget(bool perspective = true)
{
- return World.Player;
+ //目标丢失
+ if (AttackTarget == null || AttackTarget.IsDestroyed || !IsEnemy(AttackTarget))
+ {
+ AttackTarget = RefreshAttackTargets(AttackTarget);
+ return AttackTarget;
+ }
+
+ if (!perspective)
+ {
+ //被墙阻挡
+ if (TestViewRayCast(AttackTarget.GetCenterPosition()))
+ {
+ AttackTarget = RefreshAttackTargets(AttackTarget);
+ TestViewRayCastOver();
+ return AttackTarget;
+ }
+ else
+ {
+ TestViewRayCastOver();
+ }
+ }
+
+ return AttackTarget;
}
///
@@ -118,7 +184,7 @@
///
public bool CheckUsableWeaponInUnclaimed()
{
- foreach (var unclaimedWeapon in World.Weapon_UnclaimedWeapons)
+ foreach (var unclaimedWeapon in World.Weapon_UnclaimedList)
{
//判断是否能拾起武器, 条件: 相同的房间
if (unclaimedWeapon.AffiliationArea == AffiliationArea)
@@ -158,7 +224,7 @@
{
Weapon target = null;
var position = Position;
- foreach (var weapon in World.Weapon_UnclaimedWeapons)
+ foreach (var weapon in World.Weapon_UnclaimedList)
{
//判断是否能拾起武器, 条件: 相同的房间, 或者当前房间目前没有战斗, 或者不在战斗房间
if (weapon.AffiliationArea == AffiliationArea)
@@ -405,6 +471,52 @@
}
}
+ ///
+ /// 设置Ai是否有移动欲望
+ ///
+ public void SetMoveDesire(bool v)
+ {
+ HasMoveDesire = v;
+ }
+
+ private void OnViewAreaBodyEntered(Node2D node)
+ {
+ if (node is Role role)
+ {
+ _viewTargets.Add(role);
+ }
+ }
+
+ private void OnViewAreaBodyExited(Node2D node)
+ {
+ if (node is Role role)
+ {
+ _viewTargets.Remove(role);
+ }
+ }
+
+ private Role RefreshAttackTargets(Role prevRole)
+ {
+ if (_viewTargets.Count == 0)
+ {
+ return null;
+ }
+ foreach (var attackTarget in _viewTargets)
+ {
+ if (prevRole != attackTarget && !attackTarget.IsDestroyed && IsEnemy(attackTarget))
+ {
+ if (!TestViewRayCast(attackTarget.GetCenterPosition()))
+ {
+ TestViewRayCastOver();
+ return attackTarget;
+ }
+ }
+ }
+
+ TestViewRayCastOver();
+ return null;
+ }
+
// private void OnVelocityComputed(Vector2 velocity)
// {
// if (Mathf.Abs(velocity.X) >= 0.01f && Mathf.Abs(velocity.Y) >= 0.01f)
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs
index 7e8f382..d3f446f 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAstonishedState.cs
@@ -7,13 +7,10 @@
///
public class AiAstonishedState : StateBase
{
- ///
- /// 下一个状态
- ///
- public AIStateEnum NextState;
-
private float _timer;
private object[] _args;
+ //用于判断是否进入过惊讶状态
+ private bool _flag = false;
public AiAstonishedState() : base(AIStateEnum.AiAstonished)
{
@@ -28,9 +25,15 @@
return;
}
+ if (_flag)
+ {
+ ChangeNextState(args);
+ return;
+ }
+
+ _flag = true;
_args = args;
- NextState = (AIStateEnum)args[0];
_timer = 0.6f;
//播放惊讶表情
@@ -46,14 +49,19 @@
_timer -= delta;
if (_timer <= 0)
{
- if (_args.Length == 1)
- {
- ChangeState(NextState);
- }
- else if (_args.Length == 2)
- {
- ChangeState(NextState, _args[1]);
- }
+ ChangeNextState(_args);
+ }
+ }
+
+ private void ChangeNextState(object[] args)
+ {
+ if (args.Length == 1)
+ {
+ ChangeState((AIStateEnum)args[0]);
+ }
+ else if (args.Length == 2)
+ {
+ ChangeState((AIStateEnum)args[0], args[1]);
}
}
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAttackState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAttackState.cs
index 12acf2e..417a039 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAttackState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiAttackState.cs
@@ -43,7 +43,9 @@
{
if (Master.LookTarget == null)
{
- throw new Exception("进入 AIAdvancedStateEnum.AiAttack 状态时角色没有攻击目标!");
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ //throw new Exception("进入 AIAdvancedStateEnum.AiAttack 状态时角色没有攻击目标!");
}
var weapon = Master.WeaponPack.ActiveItem;
@@ -83,6 +85,12 @@
public override void Process(float delta)
{
+ if (Master.LookTarget == null || Master.LookTarget.IsDestroyed || (Master.LookTarget is Role role && !Master.IsEnemy(role))) //更改攻击状态
+ {
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ }
+
//更新标记位置
Master.UpdateMarkTargetPosition();
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
index c776dc0..adc289d 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFindAmmoState.cs
@@ -81,17 +81,11 @@
var attackTarget = Master.GetAttackTarget();
if (attackTarget != null)
{
- var targetPos = attackTarget.GetCenterPosition();
- if (Master.IsInViewRange(targetPos) && !Master.TestViewRayCast(targetPos)) //发现玩家
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
- //发现玩家
- Master.LookTarget = attackTarget;
- //进入惊讶状态, 然后再进入通知状态
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFindAmmo, TargetWeapon);
- return;
- }
+ //发现玩家
+ Master.LookTarget = attackTarget;
+ //进入惊讶状态, 然后再进入通知状态
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFindAmmo, TargetWeapon);
+ return;
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs
index c231a9a..679ed22 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiFollowUpState.cs
@@ -21,7 +21,9 @@
{
if (Master.LookTarget == null)
{
- throw new Exception("进入 AIAdvancedStateEnum.AiFollowUp 状态时角色没有攻击目标!");
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ //throw new Exception("进入 AIAdvancedStateEnum.AiFollowUp 状态时角色没有攻击目标!");
}
_navigationUpdateTimer = 0;
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs
index 4f118db..5bec8fc 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiLeaveForState.cs
@@ -108,27 +108,11 @@
var attackTarget = Master.GetAttackTarget();
if (attackTarget != null)
{
- var targetPos = attackTarget.GetCenterPosition();
- //检测玩家是否在视野内, 如果在, 则切换到 AiTargetInView 状态
- if (Master.IsInTailAfterViewRange(targetPos))
- {
- if (!Master.TestViewRayCast(targetPos)) //看到玩家
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
- //切换成发现目标状态
- Master.LookTarget = attackTarget;
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFollowUp);
- return;
- }
- else
- {
- //关闭射线检测
- Master.TestViewRayCastOver();
- }
- }
+ //切换成发现目标状态
+ Master.LookTarget = attackTarget;
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiFollowUp);
+ return;
}
-
//移动到目标掉了, 还没发现目标
if (Master.NavigationAgent2D.IsNavigationFinished())
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs
index dfdc704..7844ea7 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNormalState.cs
@@ -49,33 +49,27 @@
if (Master.HasAttackDesire) //有攻击欲望
{
//获取攻击目标
- var attackTarget = Master.GetAttackTarget();
+ var attackTarget = Master.GetAttackTarget(false);
if (attackTarget != null)
{
- //玩家中心点坐标
- var targetPos = attackTarget.GetCenterPosition();
-
- if (Master.IsInViewRange(targetPos) && !Master.TestViewRayCast(targetPos)) //发现目标
+ //发现玩家
+ Master.LookTarget = attackTarget;
+ //判断是否进入通知状态
+ if (Master.World.Role_InstanceList.FindIndex(role =>
+ role is AiRole enemy &&
+ enemy != Master && !enemy.IsDie && enemy.AffiliationArea == Master.AffiliationArea &&
+ enemy.StateController.CurrState == AIStateEnum.AiNormal) != -1)
{
- //关闭射线检测
- Master.TestViewRayCastOver();
- //发现玩家
- Master.LookTarget = attackTarget;
- //判断是否进入通知状态
- if (Master.World.Enemy_InstanceList.FindIndex(enemy =>
- enemy != Master && !enemy.IsDie && enemy.AffiliationArea == Master.AffiliationArea &&
- enemy.StateController.CurrState == AIStateEnum.AiNormal) != -1)
- {
- //进入惊讶状态, 然后再进入通知状态
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiNotify);
- }
- else
- {
- //进入惊讶状态, 然后再进入跟随状态
- ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiTailAfter);
- }
- return;
+ //进入惊讶状态, 然后再进入通知状态
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiNotify);
}
+ else
+ {
+ //进入惊讶状态, 然后再进入跟随状态
+ ChangeState(AIStateEnum.AiAstonished, AIStateEnum.AiTailAfter);
+ }
+
+ return;
}
}
@@ -89,7 +83,7 @@
RunOver();
_isMoveOver = false;
}
- else //移动中
+ else if (Master.HasMoveDesire) //移动中
{
if (_lockTimer >= 1) //卡在一个点超过一秒
{
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs
index b1e0b3f..fac6cc8 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiNotifyState.cs
@@ -17,7 +17,9 @@
{
if (Master.LookTarget == null)
{
- throw new Exception("进入 AIAdvancedStateEnum.AiNotify 没有攻击目标!");
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ //throw new Exception("进入 AIAdvancedStateEnum.AiNotify 没有攻击目标!");
}
_timer = 1.2f;
//通知其它角色
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs
index 94afce7..4760836 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiSurroundState.cs
@@ -32,7 +32,9 @@
{
if (Master.LookTarget == null)
{
- throw new Exception("进入 AIAdvancedStateEnum.AiSurround 状态时角色没有攻击目标!");
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ //throw new Exception("进入 AIAdvancedStateEnum.AiSurround 状态时角色没有攻击目标!");
}
Master.TargetInView = true;
@@ -43,6 +45,12 @@
public override void Process(float delta)
{
+ if (Master.LookTarget == null)
+ {
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ }
+
//先检查弹药是否打光
if (Master.IsAllWeaponTotalAmmoEmpty())
{
diff --git a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs
index 05a5d9e..00706f3 100644
--- a/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/ai/state/AiTailAfterState.cs
@@ -29,7 +29,9 @@
{
if (Master.LookTarget == null)
{
- throw new Exception("进入 AIAdvancedStateEnum.AiTailAfter 状态时角色没有攻击目标!");
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ //throw new Exception("进入 AIAdvancedStateEnum.AiTailAfter 状态时角色没有攻击目标!");
}
_isInViewRange = true;
@@ -51,7 +53,12 @@
public override void Process(float delta)
{
//这个状态下不会有攻击事件, 所以没必要每一帧检查是否弹药耗尽
-
+
+ if (Master.LookTarget == null)
+ {
+ ChangeState(AIStateEnum.AiNormal);
+ return;
+ }
var playerPos = Master.LookTarget.GetCenterPosition();
//更新玩家位置
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/AIStateEnum.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/AIStateEnum.cs
deleted file mode 100644
index 9b923d5..0000000
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/AIStateEnum.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-
-public enum AIStateEnum
-{
- ///
- /// Ai 状态, 正常, 未发现目标
- ///
- AiNormal,
- ///
- /// 找到玩家,准备通知其他敌人
- ///
- AiNotify,
- ///
- /// 惊讶状态
- ///
- AiAstonished,
- ///
- /// 收到其他敌人通知, 前往发现目标的位置
- ///
- AiLeaveFor,
- ///
- /// 发现目标, 目标不在视野内, 但是知道位置
- ///
- AiTailAfter,
- ///
- /// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火
- ///
- AiFollowUp,
- ///
- /// 距离足够近, 在目标附近随机移动
- ///
- AiSurround,
- ///
- /// Ai 寻找弹药
- ///
- AiFindAmmo,
- ///
- /// Ai攻击
- ///
- AiAttack,
-}
\ 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
index 14c0bc5..1f8dd9f 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/Enemy.cs
@@ -63,9 +63,6 @@
public override void OnInit()
{
base.OnInit();
-
- AttackLayer = PhysicsLayer.Obstacle | PhysicsLayer.Player;
- EnemyLayer = PhysicsLayer.Player;
Camp = CampEnum.Camp2;
RoleState.MoveSpeed = 20;
@@ -94,20 +91,7 @@
roleState.Gold = Mathf.Max(0, Utils.Random.RandomConfigRange(enemyBase.Gold));
return roleState;
}
-
- public override void EnterTree()
- {
- if (!World.Enemy_InstanceList.Contains(this))
- {
- World.Enemy_InstanceList.Add(this);
- }
- }
-
- public override void ExitTree()
- {
- World.Enemy_InstanceList.Remove(this);
- }
-
+
protected override void OnDie()
{
var effPos = Position + new Vector2(0, -Altitude);
@@ -144,20 +128,27 @@
//看向目标
if (LookTarget != null && MountLookTarget)
{
- var pos = LookTarget.Position;
- LookPosition = pos;
- //脸的朝向
- var gPos = Position;
- if (pos.X > gPos.X && Face == FaceDirection.Left)
+ if (LookTarget.IsDestroyed)
{
- Face = FaceDirection.Right;
+ LookTarget = null;
}
- else if (pos.X < gPos.X && Face == FaceDirection.Right)
+ else
{
- Face = FaceDirection.Left;
+ var pos = LookTarget.Position;
+ LookPosition = pos;
+ //脸的朝向
+ var gPos = Position;
+ 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);
}
- //枪口跟随目标
- MountPoint.SetLookAt(pos);
}
if (RoleState.CanPickUpWeapon)
@@ -184,7 +175,8 @@
{
LookTarget = target;
//判断是否进入通知状态
- if (World.Enemy_InstanceList.FindIndex(enemy =>
+ if (World.Role_InstanceList.FindIndex(role =>
+ role is AiRole enemy &&
enemy != this && !enemy.IsDie && enemy.AffiliationArea == AffiliationArea &&
enemy.StateController.CurrState == AIStateEnum.AiNormal) != -1)
{
diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs
index 89d9ccc..3dd5f63 100644
--- a/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs
@@ -56,7 +56,7 @@
var data = bulletData.Clone();
var tempPos = new Vector2(targetPosition.X + Utils.Random.RandomRangeInt(-30, 30), targetPosition.Y + Utils.Random.RandomRangeInt(-30, 30));
FireManager.SetParabolaTarget(data, tempPos);
- FireManager.ShootBullet(data, AttackLayer);
+ FireManager.ShootBullet(data, Camp);
}
}
diff --git a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
index 342d205..ca2e85f 100644
--- a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs
@@ -37,8 +37,6 @@
IsAi = false;
StateController = AddComponent>();
- AttackLayer = PhysicsLayer.Obstacle | PhysicsLayer.Enemy;
- EnemyLayer = EnemyLayer = PhysicsLayer.Enemy;
Camp = CampEnum.Camp1;
MaxHp = 6;
@@ -205,6 +203,15 @@
else if (InputManager.UseActiveProp) //使用道具
{
UseActiveProp();
+
+ foreach (var role in World.Role_InstanceList)
+ {
+ if (IsEnemy(role))
+ {
+ role.Camp = Camp;
+ break;
+ }
+ }
}
else if (InputManager.ExchangeProp) //切换道具
{
@@ -223,10 +230,14 @@
}
else if (Input.IsKeyPressed(Key.O)) //测试用, 消灭房间内所有敌人
{
- var enemyList = AffiliationArea.FindIncludeItems(o => o.CollisionWithMask(PhysicsLayer.Enemy));
+ var enemyList = AffiliationArea.FindIncludeItems(o => o is Role role && role.IsEnemyWithPlayer());
foreach (var enemy in enemyList)
{
- ((Enemy)enemy).HurtArea.Hurt(this, 1000, 0);
+ var hurt = ((Enemy)enemy).HurtArea;
+ if (hurt.CanHurt(Camp))
+ {
+ hurt.Hurt(this, 1000, 0);
+ }
}
}
// //测试用
@@ -253,7 +264,7 @@
}
//测试刷地
- //DrawLiquid(_brushData2);
+ DrawLiquid(_brushData2);
}
protected override void OnAffiliationChange(AffiliationArea prevArea)
diff --git a/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs b/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs
index f481376..02360d5 100644
--- a/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs
+++ b/DungeonShooting_Godot/src/game/activity/role/shop/ShopBoss.cs
@@ -10,7 +10,8 @@
public override void OnInit()
{
base.OnInit();
- SetAttackDesire(false);
+ SetAttackDesire(false); //默认不攻击
+ SetMoveDesire(false); //默认不攻击
}
protected override RoleState OnCreateRoleState()
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
index edb144a..2ec849b 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/Weapon.cs
@@ -27,11 +27,6 @@
private ExcelConfig.WeaponBase _playerWeaponAttribute;
private ExcelConfig.WeaponBase _aiWeaponAttribute;
- ///
- /// 武器攻击的目标阵营
- ///
- public CampEnum TargetCamp { get; set; }
-
public Role Master { get; set; }
public int PackageIndex { get; set; } = -1;
@@ -150,11 +145,6 @@
public Role TriggerRole { get; private set; }
///
- /// 上一次触发改武器开火的触发开火攻击的层级, 数据源自于:
- ///
- public long TriggerRoleAttackLayer { get; private set; }
-
- ///
/// 武器当前射速
///
public float CurrentFiringSpeed { get; private set; }
@@ -494,13 +484,13 @@
//收集落在地上的武器
if (IsInGround())
{
- World.Weapon_UnclaimedWeapons.Add(this);
+ World.Weapon_UnclaimedList.Add(this);
}
}
public override void ExitTree()
{
- World.Weapon_UnclaimedWeapons.Remove(this);
+ World.Weapon_UnclaimedList.Remove(this);
}
protected override void Process(float delta)
@@ -850,13 +840,11 @@
if (triggerRole != null)
{
TriggerRole = triggerRole;
- TriggerRoleAttackLayer = triggerRole.AttackLayer;
SetCurrentWeaponAttribute(triggerRole.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute);
}
else if (Master != null)
{
TriggerRole = Master;
- TriggerRoleAttackLayer = Master.AttackLayer;
SetCurrentWeaponAttribute(Master.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute);
}
@@ -1276,19 +1264,6 @@
}
///
- /// 获取武器攻击的目标层级
- ///
- ///
- public uint GetAttackLayer()
- {
- if (TriggerRoleAttackLayer > 0)
- {
- return (uint)TriggerRoleAttackLayer;
- }
- return Master != null ? Master.AttackLayer : Role.DefaultAttackLayer;
- }
-
- ///
/// 返回弹药是否到达上限
///
public bool IsAmmoFull()
diff --git a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
index 11c2d30..dffce05 100644
--- a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
+++ b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs
@@ -26,7 +26,7 @@
public override void OnInit()
{
base.OnInit();
-
+
//没有Master时不能触发开火
NoMasterCanTrigger = false;
_hitArea = GetNode("HitArea");
@@ -40,6 +40,9 @@
_hitArea.Monitorable = false;
_hitArea.BodyEntered += OnBodyEntered;
_hitArea.AreaEntered += OnArea2dEntered;
+
+ //更新碰撞层级
+ _hitArea.CollisionMask = Role.AttackLayer | PhysicsLayer.Bullet;
//禁用自动播放动画
IsAutoPlaySpriteFrames = false;
@@ -74,8 +77,6 @@
protected override void OnFire()
{
Debug.Log("近战武器攻击! 蓄力时长: " + GetTriggerChargeTime() + ", 扳机按下时长: " + GetTriggerDownTime());
- //更新碰撞层级
- _hitArea.CollisionMask = GetAttackLayer() | PhysicsLayer.Bullet;
//启用碰撞
_hitArea.Monitoring = true;
_attackIndex = 0;
@@ -130,8 +131,7 @@
}
else if (body is Bullet bullet) //攻击子弹
{
- var attackLayer = bullet.AttackLayer;
- if (TriggerRole != null && TriggerRole.CollisionWithMask(attackLayer)) //是攻击玩家的子弹
+ if (TriggerRole != null && TriggerRole.IsEnemy(bullet.BulletData.TriggerRole))
{
//反弹子弹
bullet.OnPlayDisappearEffect();
@@ -143,7 +143,7 @@
}
bullet.MoveController.ScaleAllVelocity(scale);
bullet.Rotation += Mathf.Pi;
- bullet.AttackLayer = TriggerRole.AttackLayer;
+ bullet.Camp = Master.Camp;
bullet.RefreshBulletColor(false);
}
}
@@ -159,42 +159,45 @@
private void HandlerCollision(IHurt hurt)
{
- var damage = Utils.Random.RandomConfigRange(Attribute.Bullet.HarmRange);
- //计算子弹造成的伤害
- if (TriggerRole != null)
+ if (TriggerRole == null || hurt.CanHurt(TriggerRole.Camp))
{
- damage = TriggerRole.RoleState.CalcDamage(damage);
- }
- //击退
- var attr = GetUseAttribute(TriggerRole);
- var repel = Utils.Random.RandomConfigRange(attr.Bullet.RepelRange);
- //计算击退
- if (TriggerRole != null)
- {
- repel = TriggerRole.RoleState.CalcBulletRepel(repel);
- }
-
- var globalPosition = GlobalPosition;
- if (repel != 0)
- {
- var o = hurt.GetActivityObject();
- if (o != null && o is not Player) //不是玩家才能被击退
+ var damage = Utils.Random.RandomConfigRange(Attribute.Bullet.HarmRange);
+ //计算子弹造成的伤害
+ if (TriggerRole != null)
{
- Vector2 position;
- if (TriggerRole != null)
- {
- position = o.GlobalPosition - TriggerRole.MountPoint.GlobalPosition;
- }
- else
- {
- position = o.GlobalPosition - globalPosition;
- }
- var v2 = position.Normalized() * repel;
- o.AddRepelForce(v2);
+ damage = TriggerRole.RoleState.CalcDamage(damage);
}
- }
+ //击退
+ var attr = GetUseAttribute(TriggerRole);
+ var repel = Utils.Random.RandomConfigRange(attr.Bullet.RepelRange);
+ //计算击退
+ if (TriggerRole != null)
+ {
+ repel = TriggerRole.RoleState.CalcBulletRepel(repel);
+ }
- //造成伤害
- hurt.Hurt(TriggerRole, damage, (hurt.GetPosition() - globalPosition).Angle());
+ var globalPosition = GlobalPosition;
+ if (repel != 0)
+ {
+ var o = hurt.GetActivityObject();
+ if (o != null && o is not Player) //不是玩家才能被击退
+ {
+ Vector2 position;
+ if (TriggerRole != null)
+ {
+ position = o.GlobalPosition - TriggerRole.MountPoint.GlobalPosition;
+ }
+ else
+ {
+ position = o.GlobalPosition - globalPosition;
+ }
+ var v2 = position.Normalized() * repel;
+ o.AddRepelForce(v2);
+ }
+ }
+
+ //造成伤害
+ hurt.Hurt(TriggerRole, damage, (hurt.GetPosition() - globalPosition).Angle());
+ }
}
}
diff --git a/DungeonShooting_Godot/src/game/buff/effect/Eff_SwapWeapon.cs b/DungeonShooting_Godot/src/game/buff/effect/Eff_SwapWeapon.cs
index d2b95ae..e89e6fb 100644
--- a/DungeonShooting_Godot/src/game/buff/effect/Eff_SwapWeapon.cs
+++ b/DungeonShooting_Godot/src/game/buff/effect/Eff_SwapWeapon.cs
@@ -14,13 +14,12 @@
public override void OnUse()
{
- var list = new List();
- foreach (var enemy in Master.World.Enemy_InstanceList)
+ var list = new List();
+ foreach (var role in Master.World.Role_InstanceList)
{
- if (enemy.WeaponPack.ActiveItem != null)
+ if (role is AiRole enemy && enemy.IsEnemy(Role) && enemy.WeaponPack.ActiveItem != null)
{
list.Add(enemy);
-
}
}
@@ -45,9 +44,9 @@
return false;
}
- foreach (var enemy in Master.World.Enemy_InstanceList)
+ foreach (var role in Master.World.Role_InstanceList)
{
- if (enemy.WeaponPack.ActiveItem != null)
+ if (role is AiRole enemy && enemy.IsEnemy(Role) && enemy.WeaponPack.ActiveItem != null)
{
return true;
}
diff --git a/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs b/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs
index 0194269..cf6f7f8 100644
--- a/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs
+++ b/DungeonShooting_Godot/src/game/data/property/PhysicsLayer.cs
@@ -24,9 +24,9 @@
///
public const uint Player = 0b1000;
///
- /// 敌人
+ /// 角色基类
///
- public const uint Enemy = 0b10000;
+ public const uint Role = 0b10000;
///
/// 归属区域判断层级
///
@@ -48,7 +48,7 @@
///
public const uint Obstacle = 0b1000000000;
///
- /// npc
+ /// 可被子弹击中的区域
///
- public const uint Npc = 0b10000000000;
+ public const uint HurtArea = 0b10000000000;
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/manager/FireManager.cs b/DungeonShooting_Godot/src/game/manager/FireManager.cs
index c7b436b..db692a7 100644
--- a/DungeonShooting_Godot/src/game/manager/FireManager.cs
+++ b/DungeonShooting_Godot/src/game/manager/FireManager.cs
@@ -97,11 +97,13 @@
{
if (bullet.Type == 1) //实体子弹
{
- return ShootSolidBullet(CreateSolidBulletData(weapon, fireRotation, bullet), weapon.GetAttackLayer());
+ return ShootSolidBullet(CreateSolidBulletData(weapon, fireRotation, bullet),
+ weapon.TriggerRole != null ? weapon.TriggerRole.Camp : CampEnum.None);
}
else if (bullet.Type == 2) //激光子弹
{
- return ShootLaser(CreateLaserData(weapon, fireRotation, bullet), weapon.GetAttackLayer());
+ return ShootLaser(CreateLaserData(weapon, fireRotation, bullet),
+ weapon.TriggerRole != null ? weapon.TriggerRole.Camp : CampEnum.None);
}
else
{
@@ -118,7 +120,7 @@
{
if (bullet.Type == 1) //实体子弹
{
- return ShootSolidBullet(CreateSolidBulletData(trigger, fireRotation, bullet), trigger.AttackLayer);
+ return ShootSolidBullet(CreateSolidBulletData(trigger, fireRotation, bullet), trigger.Camp);
}
return null;
@@ -127,15 +129,15 @@
///
/// 通过 BulletData 直接发射子弹
///
- public static IBullet ShootBullet(BulletData bulletData, uint attackLayer)
+ public static IBullet ShootBullet(BulletData bulletData, CampEnum camp)
{
if (bulletData.BulletBase.Type == 1) //实体子弹
{
- return ShootSolidBullet(bulletData, attackLayer);
+ return ShootSolidBullet(bulletData, camp);
}
else if (bulletData.BulletBase.Type == 2) //激光子弹
{
- return ShootLaser(bulletData, attackLayer);
+ return ShootLaser(bulletData, camp);
}
else
{
@@ -148,23 +150,23 @@
///
/// 发射子弹的默认实现方式
///
- private static Bullet ShootSolidBullet(BulletData bulletData, uint attackLayer)
+ private static Bullet ShootSolidBullet(BulletData bulletData, CampEnum camp)
{
//创建子弹
var bulletInstance = ObjectManager.GetBullet(bulletData.BulletBase.Prefab);
- bulletInstance.InitData(bulletData, attackLayer);
+ bulletInstance.InitData(bulletData, camp);
return bulletInstance;
}
///
/// 发射射线的默认实现方式
///
- private static Laser ShootLaser(BulletData bulletData, uint attackLayer)
+ private static Laser ShootLaser(BulletData bulletData, CampEnum camp)
{
//创建激光
var laser = ObjectManager.GetLaser(bulletData.BulletBase.Prefab);
laser.AddToActivityRoot(RoomLayerEnum.YSortLayer);
- laser.InitData(bulletData, attackLayer, Laser.LaserDefaultWidth);
+ laser.InitData(bulletData, camp, Laser.LaserDefaultWidth);
return laser;
}
diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs
index ab52b27..eb38790 100644
--- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs
+++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs
@@ -858,10 +858,10 @@
if (room.IsSeclusion)
{
var playerAffiliationArea = CurrWorld.Player.AffiliationArea;
- foreach (var enemy in CurrWorld.Enemy_InstanceList)
+ foreach (var role in CurrWorld.Role_InstanceList)
{
//不与玩家处于同一个房间
- if (!enemy.IsDestroyed && enemy.AffiliationArea != playerAffiliationArea)
+ if (role is AiRole enemy && !enemy.IsDestroyed && enemy.AffiliationArea != playerAffiliationArea)
{
if (enemy.StateController.CurrState != AIStateEnum.AiNormal)
{
@@ -904,7 +904,7 @@
{
//房间内是否有存活的敌人
var flag = ActiveAffiliationArea.ExistEnterItem(
- activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy)
+ activityObject => activityObject is Role role && role.IsEnemyWithPlayer()
);
//Debug.Log("当前房间存活数量: " + count);
if (!flag)
diff --git a/DungeonShooting_Godot/src/game/ui/roomMap/RoomMapPanel.cs b/DungeonShooting_Godot/src/game/ui/roomMap/RoomMapPanel.cs
index 5ba219f..41e04fd 100644
--- a/DungeonShooting_Godot/src/game/ui/roomMap/RoomMapPanel.cs
+++ b/DungeonShooting_Godot/src/game/ui/roomMap/RoomMapPanel.cs
@@ -75,7 +75,7 @@
//更新敌人位置
{
- var enemyList = World.Current.Enemy_InstanceList;
+ var enemyList = World.Current.Role_InstanceList;
if (enemyList.Count == 0) //没有敌人
{
foreach (var sprite in _enemySpriteList)
@@ -90,8 +90,8 @@
var count = 0; //绘制数量
for (var i = 0; i < enemyList.Count; i++)
{
- var enemy = enemyList[i];
- if (!enemy.IsDestroyed && !enemy.IsDie && enemy.AffiliationArea != null && enemy.AffiliationArea.RoomInfo.RoomFogMask.IsExplored)
+ var role = enemyList[i];
+ if (role is AiRole enemy && !enemy.IsDestroyed && !enemy.IsDie && enemy.AffiliationArea != null && enemy.AffiliationArea.RoomInfo.RoomFogMask.IsExplored)
{
count++;
Sprite2D sprite;
diff --git a/DungeonShooting_Godot/src/game/world/World.cs b/DungeonShooting_Godot/src/game/world/World.cs
new file mode 100644
index 0000000..f5a32fd
--- /dev/null
+++ b/DungeonShooting_Godot/src/game/world/World.cs
@@ -0,0 +1,202 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Godot;
+
+///
+/// 游戏世界
+///
+public partial class World : CanvasModulate, ICoroutine
+{
+ ///
+ /// 当前的游戏世界对象
+ ///
+ public static World Current => GameApplication.Instance.DungeonManager.CurrWorld;
+
+ ///
+ /// 当前操作的玩家
+ ///
+ public Player Player { get; private set; }
+
+ ///
+ /// //对象根节点
+ ///
+ public Node2D NormalLayer;
+
+ ///
+ /// 对象根节点, 带y轴排序功能
+ ///
+ public Node2D YSortLayer;
+
+ ///
+ /// 地图根节点
+ ///
+ public TileMap TileRoot;
+
+ public Node2D StaticSpriteRoot;
+ public Node2D AffiliationAreaRoot;
+ public Node2D FogMaskRoot;
+ public Node2D NavigationRoot;
+
+ ///
+ /// 是否暂停
+ ///
+ public bool Pause
+ {
+ get => _pause;
+ set
+ {
+ if (_pause != value)
+ {
+ _pause = value;
+ if (value)
+ {
+ ProcessMode = ProcessModeEnum.WhenPaused;
+ }
+ else
+ {
+ ProcessMode = ProcessModeEnum.Inherit;
+ }
+ }
+ }
+ }
+
+ ///
+ /// 所有被扔在地上的武器
+ ///
+ public HashSet Weapon_UnclaimedList { get; } = new HashSet();
+
+ ///
+ /// 记录所有存活的角色
+ ///
+ public List Role_InstanceList { get; } = new List();
+
+ ///
+ /// 随机数对象
+ ///
+ public SeedRandom Random { get; private set; }
+
+ ///
+ /// 随机对象池
+ ///
+ public RandomPool RandomPool { get; private set; }
+
+ ///
+ /// 角色死亡事件
+ ///
+ public event Action OnRoleDieEvent;
+
+ private bool _pause = false;
+ private List _coroutineList;
+
+ public override void _Ready()
+ {
+ //TileRoot.YSortEnabled = false;
+ NormalLayer = GetNode("TileRoot/NormalLayer");
+ YSortLayer = GetNode("TileRoot/YSortLayer");
+ TileRoot = GetNode("TileRoot");
+ StaticSpriteRoot = GetNode("TileRoot/StaticSpriteRoot");
+ FogMaskRoot = GetNode("TileRoot/FogMaskRoot");
+ NavigationRoot = GetNode("TileRoot/NavigationRoot");
+ AffiliationAreaRoot = GetNode("TileRoot/AffiliationAreaRoot");
+ }
+
+ public override void _Process(double delta)
+ {
+ //协程更新
+ ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, (float)delta);
+ }
+
+ ///
+ /// 获取指定层级根节点
+ ///
+ public Node2D GetRoomLayer(RoomLayerEnum layerEnum)
+ {
+ switch (layerEnum)
+ {
+ case RoomLayerEnum.NormalLayer:
+ return NormalLayer;
+ case RoomLayerEnum.YSortLayer:
+ return YSortLayer;
+ }
+
+ return null;
+ }
+
+ ///
+ /// 设置当前操作的玩家对象
+ ///
+ public void SetCurrentPlayer(Player player)
+ {
+ Player = player;
+ //设置相机和鼠标跟随玩家
+ GameCamera.Main.SetFollowTarget(player);
+ GameApplication.Instance.Cursor.SetMountRole(player);
+ }
+
+ ///
+ /// 通知其他敌人发现目标了
+ ///
+ /// 发送通知的角色
+ /// 目标
+ public void NotifyEnemyTarget(Role self, ActivityObject target)
+ {
+ foreach (var role in Role_InstanceList)
+ {
+ if (role != self && !role.IsDestroyed && role.AffiliationArea == self.AffiliationArea && role is AiRole enemy && !self.IsEnemy(enemy))
+ {
+ //将未发现目标的敌人状态置为惊讶状态
+ var controller = enemy.StateController;
+ //延时通知效果
+ role.CallDelay(Utils.Random.RandomRangeFloat(0.2f, 1f), () =>
+ {
+ if (controller.CurrState == AIStateEnum.AiNormal)
+ {
+ controller.ChangeState(AIStateEnum.AiLeaveFor, target);
+ }
+ });
+ }
+ }
+ }
+
+ public long StartCoroutine(IEnumerator able)
+ {
+ return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
+ }
+
+ public void StopCoroutine(long coroutineId)
+ {
+ ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
+ }
+
+ public bool IsCoroutineOver(long coroutineId)
+ {
+ return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId);
+ }
+
+ public void StopAllCoroutine()
+ {
+ ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
+ }
+
+ ///
+ /// 初始化随机池
+ ///
+ public void InitRandomPool(SeedRandom random)
+ {
+ Random = random;
+ RandomPool = new RandomPool(this);
+ }
+
+ ///
+ /// 角色死亡
+ ///
+ public void OnRoleDie(Role role)
+ {
+ if (OnRoleDieEvent != null)
+ {
+ OnRoleDieEvent(role);
+ }
+ }
+}
\ No newline at end of file