diff --git a/DungeonShooting_Godot/DungeonShooting.csproj b/DungeonShooting_Godot/DungeonShooting.csproj index d2f5fb2..f909828 100644 --- a/DungeonShooting_Godot/DungeonShooting.csproj +++ b/DungeonShooting_Godot/DungeonShooting.csproj @@ -1,4 +1,4 @@ - + net6.0 true diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs index d33af7d..e8b7e51 100644 --- a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs @@ -120,7 +120,12 @@ { var dungeonRoomTemplate = packedScene.Instantiate(); var usedRect = dungeonRoomTemplate.GetUsedRect(); - DungeonRoomTemplate.SaveConfig(new List(), usedRect.Position, usedRect.Size, item); + var dungeonTile = new DungeonTile(dungeonRoomTemplate); + dungeonTile.SetFloorAtlasCoords(new List() { new Vector2I(0, 8) }); + //计算导航网格 + dungeonTile.GenerateNavigationPolygon(0); + var polygonData = dungeonTile.GetPolygonData(); + DungeonRoomTemplate.SaveConfig(new List(), usedRect.Position, usedRect.Size, polygonData.ToList(), item); dungeonRoomTemplate.QueueFree(); } } diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs index 5d60ede..2db2e91 100644 --- a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs @@ -35,8 +35,11 @@ { RemoveCustomType("ActivityObjectTemplate"); RemoveCustomType("DungeonRoomTemplate"); - RemoveControlFromDocks(dock); - dock.Free(); + if (dock != null) + { + RemoveControlFromDocks(dock); + dock.Free(); + } } /*public override bool Handles(Object @object) diff --git a/DungeonShooting_Godot/prefab/map/RoomDoor.tscn b/DungeonShooting_Godot/prefab/map/RoomDoor.tscn new file mode 100644 index 0000000..f64e80b --- /dev/null +++ b/DungeonShooting_Godot/prefab/map/RoomDoor.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=2 format=3 uid="uid://b72vjthv7exo1"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_vke61"] +size = Vector2(60, 66) + +[node name="RoomDoor" type="RigidBody2D"] +collision_layer = 0 +collision_mask = 0 + +[node name="NavigationObstacle2D" type="NavigationObstacle2D" parent="."] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("RectangleShape2D_vke61") diff --git a/DungeonShooting_Godot/project.godot b/DungeonShooting_Godot/project.godot index e47983c..741b18f 100644 --- a/DungeonShooting_Godot/project.godot +++ b/DungeonShooting_Godot/project.godot @@ -178,6 +178,15 @@ project/assembly_name="DungeonShooting" +[navigation] + +2d/default_edge_connection_margin=4 + +[physics] + +2d/default_gravity=0.0 +2d/default_gravity_vector=Vector2(0, 0) + [rendering] environment/defaults/default_clear_color=Color(0.109804, 0.0666667, 0.0901961, 1) diff --git a/DungeonShooting_Godot/resource/map/RoomConfig.json b/DungeonShooting_Godot/resource/map/RoomConfig.json index 8f2f2a3..77e7d2a 100644 --- a/DungeonShooting_Godot/resource/map/RoomConfig.json +++ b/DungeonShooting_Godot/resource/map/RoomConfig.json @@ -1,5 +1,155 @@ [ { + "ScenePath": "res://resource/map/tileMaps/Room1.tscn", + "ConfigPath": "res://resource/map/tiledata/Room1.json", + "RoomInfo": { + "Position": { + "X": -1, + "Y": -1 + }, + "Size": { + "X": 20, + "Y": 13 + }, + "DoorAreaInfos": [], + "NavigationList": [ + { + "Type": 0, + "Points": [ + { + "X": 8, + "Y": 8 + }, + { + "X": 280, + "Y": 8 + }, + { + "X": 280, + "Y": 168 + }, + { + "X": 8, + "Y": 168 + } + ] + }, + { + "Type": 1, + "Points": [ + { + "X": 40, + "Y": 40 + }, + { + "X": 248, + "Y": 40 + }, + { + "X": 248, + "Y": 136 + }, + { + "X": 40, + "Y": 136 + } + ] + } + ] + } + }, + { + "ScenePath": "res://resource/map/tileMaps/Room2.tscn", + "ConfigPath": "res://resource/map/tiledata/Room2.json", + "RoomInfo": { + "Position": { + "X": -1, + "Y": -1 + }, + "Size": { + "X": 19, + "Y": 12 + }, + "DoorAreaInfos": [ + { + "Direction": 1, + "Start": 16, + "End": 176 + }, + { + "Direction": 2, + "Start": 16, + "End": 176 + }, + { + "Direction": 3, + "Start": 128, + "End": 288 + }, + { + "Direction": 0, + "Start": 16, + "End": 176 + } + ], + "NavigationList": [ + { + "Type": 0, + "Points": [ + { + "X": 8, + "Y": 8 + }, + { + "X": 40, + "Y": 8 + }, + { + "X": 40, + "Y": 120 + }, + { + "X": 120, + "Y": 120 + }, + { + "X": 120, + "Y": 8 + }, + { + "X": 264, + "Y": 8 + }, + { + "X": 264, + "Y": 152 + }, + { + "X": 232, + "Y": 152 + }, + { + "X": 232, + "Y": 24 + }, + { + "X": 152, + "Y": 24 + }, + { + "X": 152, + "Y": 152 + }, + { + "X": 8, + "Y": 152 + } + ] + } + ] + } + }, + { "ScenePath": "res://resource/map/tileMaps/Room3.tscn", "ConfigPath": "res://resource/map/tiledata/Room3.json", "RoomInfo": { @@ -11,46 +161,112 @@ "X": 21, "Y": 21 }, - "DoorAreaInfos": [ + "DoorAreaInfos": [], + "NavigationList": [ { - "Direction": 1, - "Start": 208, - "End": 320 + "Type": 0, + "Points": [ + { + "X": 8, + "Y": 8 + }, + { + "X": 296, + "Y": 8 + }, + { + "X": 296, + "Y": 296 + }, + { + "X": 8, + "Y": 296 + } + ] }, { - "Direction": 3, - "Start": 16, - "End": 128 + "Type": 1, + "Points": [ + { + "X": 40, + "Y": 40 + }, + { + "X": 136, + "Y": 40 + }, + { + "X": 136, + "Y": 136 + }, + { + "X": 40, + "Y": 136 + } + ] }, { - "Direction": 2, - "Start": 16, - "End": 128 + "Type": 1, + "Points": [ + { + "X": 168, + "Y": 40 + }, + { + "X": 264, + "Y": 40 + }, + { + "X": 264, + "Y": 136 + }, + { + "X": 168, + "Y": 136 + } + ] }, { - "Direction": 1, - "Start": 16, - "End": 128 + "Type": 1, + "Points": [ + { + "X": 40, + "Y": 168 + }, + { + "X": 136, + "Y": 168 + }, + { + "X": 136, + "Y": 264 + }, + { + "X": 40, + "Y": 264 + } + ] }, { - "Direction": 2, - "Start": 208, - "End": 320 - }, - { - "Direction": 3, - "Start": 208, - "End": 320 - }, - { - "Direction": 0, - "Start": 16, - "End": 128 - }, - { - "Direction": 0, - "Start": 208, - "End": 320 + "Type": 1, + "Points": [ + { + "X": 168, + "Y": 168 + }, + { + "X": 264, + "Y": 168 + }, + { + "X": 264, + "Y": 264 + }, + { + "X": 168, + "Y": 264 + } + ] } ] } diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Room1.tscn b/DungeonShooting_Godot/resource/map/tileMaps/Room1.tscn new file mode 100644 index 0000000..175519b --- /dev/null +++ b/DungeonShooting_Godot/resource/map/tileMaps/Room1.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=3 format=3 uid="uid://degtollvmf37f"] + +[ext_resource type="TileSet" uid="uid://b00g22o1cqhe8" path="res://resource/map/tileset/TileSet1.tres" id="1_luio1"] +[ext_resource type="Script" path="res://src/framework/map/DungeonRoomTemplate.cs" id="1_wwejn"] + +[node name="Room1" type="TileMap"] +tile_set = ExtResource("1_luio1") +format = 2 +layer_0/tile_data = PackedInt32Array(720914, 851968, 2, 655378, 65536, 3, 589842, 65536, 3, 524306, 65536, 3, 458770, 65536, 3, 393234, 65536, 3, 327698, 65536, 3, 262162, 65536, 3, 196626, 65536, 3, 131090, 65536, 3, 65554, 65536, 3, 18, 65536, 3, -65518, 65536, 4, 720913, 131072, 2, 655377, 0, 8, 589841, 0, 8, 524305, 0, 8, 458769, 0, 8, 393233, 0, 8, 327697, 0, 8, 262161, 0, 8, 196625, 0, 8, 131089, 0, 8, 65553, 0, 8, 17, 0, 8, -65519, 131072, 7, 720912, 131072, 2, 655376, 0, 8, 589840, 0, 8, 524304, 0, 8, 458768, 0, 8, 393232, 0, 8, 327696, 0, 8, 262160, 0, 8, 196624, 0, 8, 131088, 0, 8, 65552, 0, 8, 16, 0, 8, 720911, 131072, 2, 655375, 0, 8, 589839, 0, 8, 524303, 0, 8, 458767, 0, 8, 393231, 0, 8, 327695, 0, 8, 262159, 0, 8, 196623, 0, 8, 131087, 0, 8, 65551, 0, 8, 15, 0, 8, 720910, 131072, 2, 655374, 0, 8, 589838, 0, 8, 524302, 0, 8, 458766, 196608, 7, 393230, 196608, 3, 327694, 196608, 3, 262158, 196608, 3, 196622, 196608, 2, 131086, 0, 8, 65550, 0, 8, 14, 0, 8, -65522, 131072, 7, 720909, 131072, 2, 655373, 0, 8, 589837, 0, 8, 524301, 0, 8, 458765, 131072, 7, 196621, 131072, 2, 131085, 0, 8, 65549, 0, 8, 13, 0, 8, -65523, 131072, 7, 720908, 131072, 2, 655372, 0, 8, 589836, 0, 8, 524300, 0, 8, 458764, 131072, 7, 196620, 131072, 2, 131084, 0, 8, 65548, 0, 8, 12, 0, 8, -65524, 131072, 7, 720907, 131072, 2, 655371, 0, 8, 589835, 0, 8, 524299, 0, 8, 458763, 131072, 7, 196619, 131072, 2, 131083, 0, 8, 65547, 0, 8, 11, 0, 8, -65525, 131072, 7, 720906, 131072, 2, 655370, 0, 8, 589834, 0, 8, 524298, 0, 8, 458762, 131072, 7, 196618, 131072, 2, 131082, 0, 8, 65546, 0, 8, 10, 0, 8, -65526, 131072, 7, 720905, 131072, 2, 655369, 0, 8, 589833, 0, 8, 524297, 0, 8, 458761, 131072, 7, 196617, 131072, 2, 131081, 0, 8, 65545, 0, 8, 9, 0, 8, -65527, 131072, 7, 720904, 131072, 2, 655368, 0, 8, 589832, 0, 8, 524296, 0, 8, 458760, 131072, 7, 196616, 131072, 2, 131080, 0, 8, 65544, 0, 8, 8, 0, 8, -65528, 131072, 7, 720903, 131072, 2, 655367, 0, 8, 589831, 0, 8, 524295, 0, 8, 458759, 131072, 7, 196615, 131072, 2, 131079, 0, 8, 65543, 0, 8, 7, 0, 8, -65529, 131072, 7, 720902, 131072, 2, 655366, 0, 8, 589830, 0, 8, 524294, 0, 8, 458758, 131072, 7, 196614, 131072, 2, 131078, 0, 8, 65542, 0, 8, 6, 0, 8, -65530, 131072, 7, 720901, 131072, 2, 655365, 0, 8, 589829, 0, 8, 524293, 0, 8, 458757, 131072, 7, 196613, 131072, 2, 131077, 0, 8, 65541, 0, 8, 5, 0, 8, -65531, 131072, 7, 720900, 131072, 2, 655364, 0, 8, 589828, 0, 8, 524292, 0, 8, 458756, 131072, 7, 196612, 131072, 2, 131076, 0, 8, 65540, 0, 8, 4, 0, 8, -65532, 131072, 7, 720899, 131072, 2, 655363, 0, 8, 589827, 0, 8, 524291, 0, 8, 458755, 65536, 7, 393219, 65536, 3, 327683, 65536, 3, 262147, 65536, 3, 196611, 65536, 2, 131075, 0, 8, 65539, 0, 8, 3, 0, 8, -65533, 131072, 7, 720898, 131072, 2, 655362, 0, 8, 589826, 0, 8, 524290, 0, 8, 458754, 0, 8, 393218, 0, 8, 327682, 0, 8, 262146, 0, 8, 196610, 0, 8, 131074, 0, 8, 65538, 0, 8, 2, 0, 8, -65534, 131072, 7, 720897, 131072, 2, 655361, 0, 8, 589825, 0, 8, 524289, 0, 8, 458753, 0, 8, 393217, 0, 8, 327681, 0, 8, 262145, 0, 8, 196609, 0, 8, 131073, 0, 8, 65537, 0, 8, 1, 0, 8, -65535, 131072, 7, 720896, 131072, 2, 655360, 0, 8, 589824, 0, 8, 524288, 0, 8, 458752, 0, 8, 393216, 0, 8, 327680, 0, 8, 262144, 0, 8, 196608, 0, 8, 131072, 0, 8, 65536, 0, 8, 0, 0, 8, -65536, 131072, 7, 786431, 720896, 2, 720895, 196608, 3, 655359, 196608, 3, 589823, 196608, 3, 524287, 196608, 3, 458751, 196608, 3, 393215, 196608, 3, 327679, 196608, 3, 262143, 196608, 3, 196607, 196608, 3, 131071, 196608, 3, 65535, 196608, 3, -1, 196608, 4, -65521, 131072, 7, -65520, 131072, 7) +script = ExtResource("1_wwejn") diff --git a/DungeonShooting_Godot/resource/map/tileMaps/Room2.tscn b/DungeonShooting_Godot/resource/map/tileMaps/Room2.tscn new file mode 100644 index 0000000..a9ce8aa --- /dev/null +++ b/DungeonShooting_Godot/resource/map/tileMaps/Room2.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=3 format=3 uid="uid://hbgdhf84okk6"] + +[ext_resource type="Script" path="res://src/framework/map/DungeonRoomTemplate.cs" id="1_hg3w8"] +[ext_resource type="TileSet" uid="uid://b00g22o1cqhe8" path="res://resource/map/tileset/TileSet1.tres" id="1_u22xh"] + +[node name="Room2" type="TileMap"] +tile_set = ExtResource("1_u22xh") +format = 2 +layer_0/tile_data = PackedInt32Array(589840, 0, 8, 524304, 0, 8, 458768, 0, 8, 393232, 0, 8, 327696, 0, 8, 262160, 0, 8, 196624, 0, 8, 131088, 0, 8, 65552, 0, 8, 16, 0, 8, 589839, 0, 8, 524303, 0, 8, 458767, 0, 8, 393231, 0, 8, 327695, 0, 8, 262159, 0, 8, 196623, 0, 8, 131087, 0, 8, 65551, 0, 8, 15, 0, 8, 589838, 0, 8, 524302, 0, 8, 458766, 0, 8, 393230, 0, 8, 327694, 0, 8, 262158, 0, 8, 196622, 0, 8, 131086, 0, 8, 65550, 0, 8, 14, 0, 8, 65549, 0, 8, 13, 0, 8, 65548, 0, 8, 12, 0, 8, 65547, 0, 8, 11, 0, 8, 65546, 0, 8, 10, 0, 8, 589833, 0, 8, 524297, 0, 8, 458761, 0, 8, 393225, 0, 8, 327689, 0, 8, 262153, 0, 8, 196617, 0, 8, 131081, 0, 8, 65545, 0, 8, 9, 0, 8, 589832, 0, 8, 524296, 0, 8, 458760, 0, 8, 393224, 0, 8, 327688, 0, 8, 262152, 0, 8, 196616, 0, 8, 131080, 0, 8, 65544, 0, 8, 8, 0, 8, 589831, 0, 8, 524295, 0, 8, 458759, 0, 8, 393223, 0, 8, 327687, 0, 8, 262151, 0, 8, 196615, 0, 8, 131079, 0, 8, 65543, 0, 8, 7, 0, 8, 589830, 0, 8, 524294, 0, 8, 458758, 0, 8, 589829, 0, 8, 524293, 0, 8, 458757, 0, 8, 589828, 0, 8, 524292, 0, 8, 458756, 0, 8, 589827, 0, 8, 524291, 0, 8, 458755, 0, 8, 589826, 0, 8, 524290, 0, 8, 458754, 0, 8, 393218, 0, 8, 327682, 0, 8, 262146, 0, 8, 196610, 0, 8, 131074, 0, 8, 65538, 0, 8, 2, 0, 8, 589825, 0, 8, 524289, 0, 8, 458753, 0, 8, 393217, 0, 8, 327681, 0, 8, 262145, 0, 8, 196609, 0, 8, 131073, 0, 8, 65537, 0, 8, 1, 0, 8, 589824, 0, 8, 524288, 0, 8, 458752, 0, 8, 393216, 0, 8, 327680, 0, 8, 262144, 0, 8, 196608, 0, 8, 131072, 0, 8, 65536, 0, 8, 0, 0, 8, 131071, 196608, 3, 65535, 196608, 3, -1, 196608, 4, -65536, 131072, 7, -65535, 131072, 7, 196607, 196608, 3, 262143, 196608, 3, 327679, 196608, 3, 393215, 196608, 3, 458751, 196608, 3, 524287, 196608, 3, 589823, 196608, 3, 655359, 196608, 3, 655361, 131072, 2, 655360, 131072, 2, 720895, 720896, 2, -65534, 131072, 7, 655362, 131072, 2, 655363, 131072, 2, 655364, 131072, 2, 655365, 131072, 2, 655366, 131072, 2, -65529, 131072, 7, 655367, 131072, 2, -65528, 131072, 7, 655368, 131072, 2, -65527, 131072, 7, 655369, 131072, 2, -65526, 131072, 7, -65525, 131072, 7, -65524, 131072, 7, -65523, 131072, 7, -65522, 131072, 7, 655374, 131072, 2, -65521, 131072, 7, 655375, 131072, 2, -65520, 131072, 7, 655376, 131072, 2, 3, 65536, 3, 65539, 65536, 3, -65533, 65536, 4, 131075, 65536, 3, 196611, 65536, 3, 262147, 65536, 3, 327683, 65536, 3, 393219, 65536, 7, 393220, 131072, 7, 393221, 131072, 7, 393222, 196608, 7, 327686, 196608, 3, 262150, 196608, 3, 196614, 196608, 3, 131078, 196608, 3, 65542, 196608, 3, 6, 196608, 3, -65530, 196608, 4, 17, 65536, 3, 65553, 65536, 3, -65519, 65536, 4, 131089, 65536, 3, 196625, 65536, 3, 262161, 65536, 3, 327697, 65536, 3, 393233, 65536, 3, 458769, 65536, 3, 655377, 851968, 2, 655373, 720896, 2, 589837, 196608, 3, 524301, 196608, 3, 458765, 196608, 3, 393229, 196608, 3, 327693, 196608, 3, 262157, 196608, 3, 196621, 196608, 3, 131085, 196608, 2, 131084, 131072, 2, 131083, 131072, 2, 131082, 65536, 2, 196618, 65536, 3, 262154, 65536, 3, 327690, 65536, 3, 393226, 65536, 3, 458762, 65536, 3, 524298, 65536, 3, 589834, 65536, 3, 655370, 851968, 2, 524305, 65536, 3, 589841, 65536, 3) +script = ExtResource("1_hg3w8") diff --git a/DungeonShooting_Godot/resource/map/tiledata/Room1.json b/DungeonShooting_Godot/resource/map/tiledata/Room1.json new file mode 100644 index 0000000..f64b47a --- /dev/null +++ b/DungeonShooting_Godot/resource/map/tiledata/Room1.json @@ -0,0 +1,55 @@ +{ + "Position": { + "X": -1, + "Y": -1 + }, + "Size": { + "X": 20, + "Y": 13 + }, + "DoorAreaInfos": [], + "NavigationList": [ + { + "Type": 0, + "Points": [ + { + "X": 8, + "Y": 8 + }, + { + "X": 280, + "Y": 8 + }, + { + "X": 280, + "Y": 168 + }, + { + "X": 8, + "Y": 168 + } + ] + }, + { + "Type": 1, + "Points": [ + { + "X": 40, + "Y": 40 + }, + { + "X": 248, + "Y": 40 + }, + { + "X": 248, + "Y": 136 + }, + { + "X": 40, + "Y": 136 + } + ] + } + ] +} \ No newline at end of file diff --git a/DungeonShooting_Godot/resource/map/tiledata/Room2.json b/DungeonShooting_Godot/resource/map/tiledata/Room2.json new file mode 100644 index 0000000..0b999d4 --- /dev/null +++ b/DungeonShooting_Godot/resource/map/tiledata/Room2.json @@ -0,0 +1,87 @@ +{ + "Position": { + "X": -1, + "Y": -1 + }, + "Size": { + "X": 19, + "Y": 12 + }, + "DoorAreaInfos": [ + { + "Direction": 1, + "Start": 16, + "End": 176 + }, + { + "Direction": 2, + "Start": 16, + "End": 176 + }, + { + "Direction": 3, + "Start": 128, + "End": 288 + }, + { + "Direction": 0, + "Start": 16, + "End": 176 + } + ], + "NavigationList": [ + { + "Type": 0, + "Points": [ + { + "X": 8, + "Y": 8 + }, + { + "X": 40, + "Y": 8 + }, + { + "X": 40, + "Y": 120 + }, + { + "X": 120, + "Y": 120 + }, + { + "X": 120, + "Y": 8 + }, + { + "X": 264, + "Y": 8 + }, + { + "X": 264, + "Y": 152 + }, + { + "X": 232, + "Y": 152 + }, + { + "X": 232, + "Y": 24 + }, + { + "X": 152, + "Y": 24 + }, + { + "X": 152, + "Y": 152 + }, + { + "X": 8, + "Y": 152 + } + ] + } + ] +} \ No newline at end of file diff --git a/DungeonShooting_Godot/resource/map/tiledata/Room3.json b/DungeonShooting_Godot/resource/map/tiledata/Room3.json index ed98615..1be08dd 100644 --- a/DungeonShooting_Godot/resource/map/tiledata/Room3.json +++ b/DungeonShooting_Godot/resource/map/tiledata/Room3.json @@ -7,46 +7,112 @@ "X": 21, "Y": 21 }, - "DoorAreaInfos": [ + "DoorAreaInfos": [], + "NavigationList": [ { - "Direction": 1, - "Start": 208, - "End": 320 + "Type": 0, + "Points": [ + { + "X": 8, + "Y": 8 + }, + { + "X": 296, + "Y": 8 + }, + { + "X": 296, + "Y": 296 + }, + { + "X": 8, + "Y": 296 + } + ] }, { - "Direction": 3, - "Start": 16, - "End": 128 + "Type": 1, + "Points": [ + { + "X": 40, + "Y": 40 + }, + { + "X": 136, + "Y": 40 + }, + { + "X": 136, + "Y": 136 + }, + { + "X": 40, + "Y": 136 + } + ] }, { - "Direction": 2, - "Start": 16, - "End": 128 + "Type": 1, + "Points": [ + { + "X": 168, + "Y": 40 + }, + { + "X": 264, + "Y": 40 + }, + { + "X": 264, + "Y": 136 + }, + { + "X": 168, + "Y": 136 + } + ] }, { - "Direction": 1, - "Start": 16, - "End": 128 + "Type": 1, + "Points": [ + { + "X": 40, + "Y": 168 + }, + { + "X": 136, + "Y": 168 + }, + { + "X": 136, + "Y": 264 + }, + { + "X": 40, + "Y": 264 + } + ] }, { - "Direction": 2, - "Start": 208, - "End": 320 - }, - { - "Direction": 3, - "Start": 208, - "End": 320 - }, - { - "Direction": 0, - "Start": 16, - "End": 128 - }, - { - "Direction": 0, - "Start": 208, - "End": 320 + "Type": 1, + "Points": [ + { + "X": 168, + "Y": 168 + }, + { + "X": 264, + "Y": 168 + }, + { + "X": 264, + "Y": 264 + }, + { + "X": 168, + "Y": 264 + } + ] } ] } \ No newline at end of file diff --git a/DungeonShooting_Godot/resource/theme/mainTheme.tres b/DungeonShooting_Godot/resource/theme/mainTheme.tres index cbaa476..ea0b3cf 100644 --- a/DungeonShooting_Godot/resource/theme/mainTheme.tres +++ b/DungeonShooting_Godot/resource/theme/mainTheme.tres @@ -352,7 +352,7 @@ [sub_resource type="ImageTexture" id="58"] -[sub_resource type="Image" id="Image_soqha"] +[sub_resource type="Image" id="Image_63cds"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 39, 255, 255, 255, 67, 255, 255, 255, 67, 255, 255, 255, 39, 255, 255, 255, 1, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 39, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 39, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 66, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 66, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 66, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 66, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 39, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 39, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 39, 255, 255, 255, 67, 255, 255, 255, 67, 255, 255, 255, 39, 255, 255, 255, 1, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -362,7 +362,7 @@ } [sub_resource type="ImageTexture" id="60"] -image = SubResource("Image_soqha") +image = SubResource("Image_63cds") [sub_resource type="StyleBoxTexture" id="61"] content_margin_left = 2.0 @@ -372,7 +372,7 @@ texture = SubResource("60") region_rect = Rect2(0, 0, 12, 12) -[sub_resource type="Image" id="Image_tmvuf"] +[sub_resource type="Image" id="Image_opvvo"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 247, 247, 247, 0, 248, 248, 248, 0, 248, 248, 248, 0, 247, 247, 247, 0, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 191, 191, 191, 4, 247, 247, 247, 98, 248, 248, 248, 167, 248, 248, 248, 167, 247, 247, 247, 98, 191, 191, 191, 4, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 0, 247, 247, 247, 97, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 247, 247, 247, 97, 247, 247, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 248, 248, 0, 248, 248, 248, 164, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 164, 248, 248, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 248, 248, 0, 248, 248, 248, 164, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 164, 248, 248, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 0, 247, 247, 247, 97, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 247, 247, 247, 97, 247, 247, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 191, 191, 191, 4, 247, 247, 247, 98, 248, 248, 248, 167, 248, 248, 248, 167, 247, 247, 247, 98, 191, 191, 191, 4, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 247, 247, 247, 0, 248, 248, 248, 0, 248, 248, 248, 0, 247, 247, 247, 0, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -382,7 +382,7 @@ } [sub_resource type="ImageTexture" id="63"] -image = SubResource("Image_tmvuf") +image = SubResource("Image_opvvo") [sub_resource type="StyleBoxTexture" id="64"] content_margin_left = 2.0 @@ -392,7 +392,7 @@ texture = SubResource("63") region_rect = Rect2(0, 0, 12, 12) -[sub_resource type="Image" id="Image_cmfvh"] +[sub_resource type="Image" id="Image_6t8ol"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 4, 173, 173, 173, 97, 173, 173, 173, 166, 173, 173, 173, 166, 173, 173, 173, 97, 127, 127, 127, 4, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 0, 172, 172, 172, 96, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 172, 172, 172, 96, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 0, 173, 173, 173, 163, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 163, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 0, 173, 173, 173, 163, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 163, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 0, 172, 172, 172, 96, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 172, 172, 172, 96, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 4, 173, 173, 173, 97, 173, 173, 173, 166, 173, 173, 173, 166, 173, 173, 173, 97, 127, 127, 127, 4, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -402,7 +402,7 @@ } [sub_resource type="ImageTexture" id="66"] -image = SubResource("Image_cmfvh") +image = SubResource("Image_6t8ol") [sub_resource type="StyleBoxTexture" id="67"] content_margin_left = 2.0 @@ -412,7 +412,7 @@ texture = SubResource("66") region_rect = Rect2(0, 0, 12, 12) -[sub_resource type="Image" id="Image_nkbhm"] +[sub_resource type="Image" id="Image_xjqym"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 4, 255, 255, 255, 16, 255, 255, 255, 16, 255, 255, 255, 4, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 16, 255, 255, 255, 21, 255, 255, 255, 21, 255, 255, 255, 16, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 16, 255, 255, 255, 21, 255, 255, 255, 21, 255, 255, 255, 16, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 4, 255, 255, 255, 16, 255, 255, 255, 16, 255, 255, 255, 4, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -422,7 +422,7 @@ } [sub_resource type="ImageTexture" id="69"] -image = SubResource("Image_nkbhm") +image = SubResource("Image_xjqym") [sub_resource type="StyleBoxTexture" id="70"] content_margin_left = 0.0 @@ -446,7 +446,7 @@ content_margin_right = 4.0 content_margin_bottom = 4.0 -[sub_resource type="Image" id="Image_uft0g"] +[sub_resource type="Image" id="Image_ysgqp"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 228, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 228, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 18, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 17, 255, 255, 255, 186, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 191, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 186, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 189, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 77, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 77, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -456,7 +456,7 @@ } [sub_resource type="ImageTexture" id="56"] -image = SubResource("Image_uft0g") +image = SubResource("Image_ysgqp") [sub_resource type="StyleBoxFlat" id="57"] content_margin_left = 6.0 diff --git a/DungeonShooting_Godot/scene/Main.tscn b/DungeonShooting_Godot/scene/Main.tscn index 0aaea00..454b56d 100644 --- a/DungeonShooting_Godot/scene/Main.tscn +++ b/DungeonShooting_Godot/scene/Main.tscn @@ -24,6 +24,7 @@ [node name="Main" type="Node2D"] script = ExtResource("3") +Debug = true CursorPack = ExtResource("4") RoomPath = NodePath("ViewCanvas/SubViewportContainer/SubViewport/Room") ViewportPath = NodePath("ViewCanvas/SubViewportContainer/SubViewport") diff --git a/DungeonShooting_Godot/scene/Room.tscn b/DungeonShooting_Godot/scene/Room.tscn index d8fb321..666fa28 100644 --- a/DungeonShooting_Godot/scene/Room.tscn +++ b/DungeonShooting_Godot/scene/Room.tscn @@ -600,6 +600,13 @@ layer_2/y_sort_origin = 0 layer_2/z_index = 10 layer_2/tile_data = PackedInt32Array() +layer_3/name = "AisleFloor" +layer_3/enabled = true +layer_3/modulate = Color(1, 1, 1, 1) +layer_3/y_sort_enabled = true +layer_3/y_sort_origin = 0 +layer_3/z_index = -10 +layer_3/tile_data = PackedInt32Array() [node name="NormalLayer" type="Node2D" parent="."] z_index = -1 diff --git a/DungeonShooting_Godot/scene/test/TestNavigation2.tscn b/DungeonShooting_Godot/scene/test/TestNavigation2.tscn index 4fcdaa3..bd27dfe 100644 --- a/DungeonShooting_Godot/scene/test/TestNavigation2.tscn +++ b/DungeonShooting_Godot/scene/test/TestNavigation2.tscn @@ -1,12 +1,22 @@ -[gd_scene load_steps=4 format=3 uid="uid://cjbbs1protcwb"] +[gd_scene load_steps=6 format=3 uid="uid://cjbbs1protcwb"] [ext_resource type="Script" path="res://src/test/TestNavigation2.cs" id="1"] [ext_resource type="Texture2D" uid="uid://uhhfgdhpk7i4" path="res://icon.png" id="2"] [sub_resource type="NavigationPolygon" id="1"] -vertices = PackedVector2Array(1650, 237, 1789, 81, 1795, 986, 1635, 828, 1627, 721, 1215, 660, 1070, 733, 62, 978, 975, 834, 888, 830, 806, 831, 1123, 576, 1033, 218, 1563, 162, 950, 211, 883, 208, 288, 833, 286, 610, 807, 609, 208, 836, 79, 73, 212, 202, 796, 205, 795, 525, 300, 527, 292, 192) -polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3, 4), PackedInt32Array(5, 0, 4), PackedInt32Array(5, 4, 6), PackedInt32Array(3, 2, 7, 8), PackedInt32Array(9, 8, 7, 10), PackedInt32Array(11, 5, 6), PackedInt32Array(11, 6, 12), PackedInt32Array(13, 11, 12), PackedInt32Array(14, 8, 9, 15), PackedInt32Array(16, 17, 18, 10), PackedInt32Array(16, 10, 7, 19), PackedInt32Array(19, 7, 20, 21), PackedInt32Array(22, 23, 24, 25), PackedInt32Array(1, 0, 13), PackedInt32Array(20, 1, 13, 12, 14), PackedInt32Array(20, 14, 15), PackedInt32Array(20, 15, 22), PackedInt32Array(20, 22, 25), PackedInt32Array(20, 25, 21)]) -outlines = Array[PackedVector2Array]([PackedVector2Array(79, 73, 62, 978, 1795, 986, 1789, 81), PackedVector2Array(212, 202, 208, 836, 288, 833, 286, 610, 807, 609, 806, 831, 888, 830, 883, 208, 796, 205, 795, 525, 300, 527, 292, 192), PackedVector2Array(950, 211, 975, 834, 1635, 828, 1627, 721, 1070, 733, 1033, 218), PackedVector2Array(1123, 576, 1215, 660, 1650, 237, 1563, 162)]) +vertices = PackedVector2Array(1138, 78, 1168, 948, 1070, 733, 1033, 218, 79, 73, 950, 211, 975, 834, 888, 830, 62, 978, 806, 831, 883, 208, 796, 205, 288, 833, 286, 610, 807, 609, 208, 836, 212, 202, 795, 525, 300, 527, 292, 192) +polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3), PackedInt32Array(4, 0, 3, 5), PackedInt32Array(6, 2, 1), PackedInt32Array(7, 6, 1, 8, 9), PackedInt32Array(5, 6, 7, 10), PackedInt32Array(4, 5, 10), PackedInt32Array(4, 10, 11), PackedInt32Array(12, 13, 14, 9), PackedInt32Array(12, 9, 8, 15), PackedInt32Array(15, 8, 4, 16), PackedInt32Array(11, 17, 18, 19), PackedInt32Array(4, 11, 19), PackedInt32Array(4, 19, 16)]) +outlines = Array[PackedVector2Array]([PackedVector2Array(79, 73, 62, 978, 1168, 948, 1138, 78), PackedVector2Array(212, 202, 208, 836, 288, 833, 286, 610, 807, 609, 806, 831, 888, 830, 883, 208, 796, 205, 795, 525, 300, 527, 292, 192), PackedVector2Array(950, 211, 975, 834, 1070, 733, 1033, 218)]) + +[sub_resource type="NavigationPolygon" id="NavigationPolygon_oawm0"] +vertices = PackedVector2Array(606, 123, 648, 952, 62, 978, 79, 73) +polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3)]) +outlines = Array[PackedVector2Array]([PackedVector2Array(79, 73, 62, 978, 648, 952, 606, 123)]) + +[sub_resource type="NavigationPolygon" id="NavigationPolygon_nrkta"] +vertices = PackedVector2Array(379, 510, 374, 753, 172, 747, 161, 524) +polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3)]) +outlines = Array[PackedVector2Array]([PackedVector2Array(161, 524, 172, 747, 374, 753, 379, 510)]) [node name="TestNavigation2" type="Node2D"] script = ExtResource("1") @@ -16,6 +26,14 @@ [node name="NavigationRegion2D" type="NavigationRegion2D" parent="Node2D"] navigation_polygon = SubResource("1") +[node name="NavigationRegion2D2" type="NavigationRegion2D" parent="Node2D"] +position = Vector2(1307, -8) +navigation_polygon = SubResource("NavigationPolygon_oawm0") + +[node name="NavigationRegion2D3" type="NavigationRegion2D" parent="Node2D"] +position = Vector2(996, 94) +navigation_polygon = SubResource("NavigationPolygon_nrkta") + [node name="Enemy" type="Sprite2D" parent="Node2D"] position = Vector2(129, 118) texture = ExtResource("2") diff --git a/DungeonShooting_Godot/src/framework/SerializeVector2.cs b/DungeonShooting_Godot/src/framework/SerializeVector2.cs new file mode 100644 index 0000000..f4e53c7 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/SerializeVector2.cs @@ -0,0 +1,53 @@ + +using System.Text.Json.Serialization; +using Godot; + +/// +/// 可序列化的 Vector2 对象 +/// +public class SerializeVector2 +{ + public SerializeVector2(float x, float y) + { + X = x; + Y = y; + } + + public SerializeVector2(Vector2 v) + { + X = v.X; + Y = v.Y; + } + + public SerializeVector2(Vector2I v) + { + X = v.X; + Y = v.Y; + } + + public SerializeVector2() + { + + } + + [JsonInclude] + public float X { get; private set; } + [JsonInclude] + public float Y { get; private set; } + + /// + /// 转为 Vector2 + /// + public Vector2 AsVector2() + { + return new Vector2(X, Y); + } + + /// + /// 转为 Vector2I + /// + public Vector2I AsVector2I() + { + return new Vector2I((int)X, (int)Y); + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/common/Utils.cs b/DungeonShooting_Godot/src/framework/common/Utils.cs index 3b06941..0e8b005 100644 --- a/DungeonShooting_Godot/src/framework/common/Utils.cs +++ b/DungeonShooting_Godot/src/framework/common/Utils.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Godot; /// @@ -97,4 +98,28 @@ Mathf.Abs(start1 - start2), Mathf.Abs(end1 - end2) ); } + + /// + /// 使用定的 canvasItem 绘制导航区域, 注意, 该函数只能在 draw 函数中调用 + /// + public static void DrawNavigationPolygon(CanvasItem canvasItem, NavigationPolygonData[] polygonData) + { + for (var i = 0; i < polygonData.Length; i++) + { + var item = polygonData[i]; + if (item.Points.Count >= 2) + { + var array = item.ConvertPointsToVector2Array().ToList(); + array.Add(array[0]); + if (item.Type == NavigationPolygonType.In) + { + canvasItem.DrawPolyline(array.ToArray(), Colors.Yellow); + } + else + { + canvasItem.DrawPolyline(array.ToArray(), Colors.Red); + } + } + } + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/DoorAreaInfo.cs b/DungeonShooting_Godot/src/framework/map/DoorAreaInfo.cs index 7ed012e..8d2263c 100644 --- a/DungeonShooting_Godot/src/framework/map/DoorAreaInfo.cs +++ b/DungeonShooting_Godot/src/framework/map/DoorAreaInfo.cs @@ -32,6 +32,17 @@ /// public Vector2 EndPosition; + public DoorAreaInfo() + { + } + + public DoorAreaInfo(DoorDirection direction, float start, float end) + { + Direction = direction; + Start = start; + End = end; + } + /// /// 自动计算 startPosition 和 endPosition /// diff --git a/DungeonShooting_Godot/src/framework/map/DungeonRoomInfo.cs b/DungeonShooting_Godot/src/framework/map/DungeonRoomInfo.cs index e7fe9ba..8a661bc 100644 --- a/DungeonShooting_Godot/src/framework/map/DungeonRoomInfo.cs +++ b/DungeonShooting_Godot/src/framework/map/DungeonRoomInfo.cs @@ -24,4 +24,10 @@ /// [JsonInclude] public List DoorAreaInfos; + + /// + /// 导航数据 + /// + [JsonInclude] + public List NavigationList; } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/DungeonRoomTemplate.cs b/DungeonShooting_Godot/src/framework/map/DungeonRoomTemplate.cs index c25dfed..4510201 100644 --- a/DungeonShooting_Godot/src/framework/map/DungeonRoomTemplate.cs +++ b/DungeonShooting_Godot/src/framework/map/DungeonRoomTemplate.cs @@ -2,27 +2,33 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.Json; using Godot; [Tool] public partial class DungeonRoomTemplate : TileMap { - /// /// 地图路径 /// - public static readonly string RoomTileDir = System.Environment.CurrentDirectory + "\\resource\\map\\tileMaps\\"; + public static readonly string RoomTileDir = System.Environment.CurrentDirectory + "/resource/map/tileMaps/"; /// /// 地图描述数据路径 /// - public static readonly string RoomTileDataDir = System.Environment.CurrentDirectory + "\\resource\\map\\tiledata\\"; + public static readonly string RoomTileDataDir = System.Environment.CurrentDirectory + "/resource/map/tiledata/"; /// /// 房间配置汇总 /// - public static readonly string RoomTileConfigFile = System.Environment.CurrentDirectory + "\\resource\\map\\RoomConfig.json"; + public static readonly string RoomTileConfigFile = System.Environment.CurrentDirectory + "/resource/map/RoomConfig.json"; + + /// + /// 是否启用编辑模式 + /// + [Export(PropertyHint.None, "是否启用编辑模式")] + public bool EnableEdit = false; #if TOOLS //是否悬停在线上 @@ -49,10 +55,28 @@ private bool _mouseDown = false; - // + //门区域数据 private List _doorConfigs; private Rect2 _prevRect; - + + //是否能保存 + private bool _canSave = false; + private bool _clickSave = false; + + private DungeonTile _dungeonTile; + + //计算导航的计时器 + private float _calcTileNavTimer = 0; + + public override void _Ready() + { + if (!Engine.IsEditorHint()) + { + return; + } + EnableEdit = false; + } + public override void _Process(double delta) { if (!Engine.IsEditorHint()) @@ -60,13 +84,38 @@ return; } + if (_dungeonTile == null) + { + _dungeonTile = new DungeonTile(this); + _dungeonTile.SetFloorAtlasCoords(new List() { new Vector2I(0, 8) }); + OnTileChanged(); + var callable = new Callable(this, nameof(OnTileChanged)); + if (!IsConnected("changed", callable)) + { + Connect("changed", callable); + } + } + + //导航计算 + if (_calcTileNavTimer > 0) + { + _calcTileNavTimer -= (float)delta; + //重新计算导航 + if (_calcTileNavTimer <= 0) + { + _dungeonTile.GenerateNavigationPolygon(0); + } + } + + //加载配置 var initConfigs = false; if (_doorConfigs == null) { initConfigs = true; _doorConfigs = ReadConfig(CalcTileRange(this), Name); } - + + //按键检测 var isClick = false; if (Input.IsMouseButtonPressed(MouseButton.Left)) { @@ -84,18 +133,18 @@ if (Input.IsMouseButtonPressed(MouseButton.Middle)) //中键移除门 { - if (_activeArea != null) + if (EnableEdit && _activeArea != null) { RemoveDoorArea(_activeArea); _hasActivePoint = false; _activeArea = null; } } - else if (TileSet != null) + else if (TileSet != null) //编辑操作 { var mapRect = CalcTileRange(this); var mousePosition = GetLocalMousePosition(); - + if (mapRect != _prevRect) { if (!initConfigs) @@ -103,222 +152,247 @@ OnMapRectChange(); } } + _prevRect = mapRect; - var tileSize = TileSet.TileSize; - if (_isDrag) //拖拽中 + if (EnableEdit) { - if (_activeArea != null) + var tileSize = TileSet.TileSize; + if (_isDrag) //拖拽中 { - //拖拽节点操作 - if (_activeArea.Direction == DoorDirection.N || _activeArea.Direction == DoorDirection.S) + if (_activeArea != null) { - if (_activePointType == 0) + //拖拽节点操作 + if (_activeArea.Direction == DoorDirection.N || _activeArea.Direction == DoorDirection.S) { - var mouseOffset = Approach(mousePosition.X, tileSize.X); - _activeArea.StartPosition = new Vector2(mouseOffset, _activeArea.StartPosition.Y); - _activeArea.Start = mouseOffset - mapRect.Position.X; - _dragHasCollision = _activeArea.StartPosition.X <= mapRect.Position.X || - _activeArea.StartPosition.X + 3 * tileSize.X >= _activeArea.EndPosition.X || - CheckDoorCollision(_activeArea.Direction, _activeArea); + if (_activePointType == 0) + { + var mouseOffset = Approach(mousePosition.X, tileSize.X); + _activeArea.StartPosition = new Vector2(mouseOffset, _activeArea.StartPosition.Y); + _activeArea.Start = mouseOffset - mapRect.Position.X; + _dragHasCollision = _activeArea.StartPosition.X <= mapRect.Position.X || + _activeArea.StartPosition.X + 3 * tileSize.X >= + _activeArea.EndPosition.X || + CheckDoorCollision(_activeArea.Direction, _activeArea); + } + else + { + var mouseOffset = Approach(mousePosition.X, tileSize.X); + _activeArea.EndPosition = new Vector2(mouseOffset, _activeArea.EndPosition.Y); + _activeArea.End = mouseOffset - mapRect.Position.X; + _dragHasCollision = _activeArea.EndPosition.X >= mapRect.Position.X + mapRect.Size.X || + _activeArea.EndPosition.X - 3 * tileSize.X <= + _activeArea.StartPosition.X || + CheckDoorCollision(_activeArea.Direction, _activeArea); + } } else { - var mouseOffset = Approach(mousePosition.X, tileSize.X); - _activeArea.EndPosition = new Vector2(mouseOffset, _activeArea.EndPosition.Y); - _activeArea.End = mouseOffset - mapRect.Position.X; - _dragHasCollision = _activeArea.EndPosition.X >= mapRect.Position.X + mapRect.Size.X || - _activeArea.EndPosition.X - 3 * tileSize.X <= _activeArea.StartPosition.X || - CheckDoorCollision(_activeArea.Direction, _activeArea); + if (_activePointType == 0) + { + var mouseOffset = Approach(mousePosition.Y, tileSize.Y); + _activeArea.StartPosition = new Vector2(_activeArea.StartPosition.X, mouseOffset); + _activeArea.Start = mouseOffset - mapRect.Position.Y; + _dragHasCollision = _activeArea.StartPosition.Y <= mapRect.Position.Y || + _activeArea.StartPosition.Y + 3 * tileSize.Y >= + _activeArea.EndPosition.Y || + CheckDoorCollision(_activeArea.Direction, _activeArea); + } + else + { + var mouseOffset = Approach(mousePosition.Y, tileSize.Y); + _activeArea.EndPosition = new Vector2(_activeArea.EndPosition.X, mouseOffset); + _activeArea.End = mouseOffset - mapRect.Position.Y; + _dragHasCollision = _activeArea.EndPosition.Y >= mapRect.Position.Y + mapRect.Size.Y || + _activeArea.EndPosition.Y - 3 * tileSize.Y <= + _activeArea.StartPosition.Y || + CheckDoorCollision(_activeArea.Direction, _activeArea); + } } } - else - { - if (_activePointType == 0) - { - var mouseOffset = Approach(mousePosition.Y, tileSize.Y); - _activeArea.StartPosition = new Vector2(_activeArea.StartPosition.X, mouseOffset); - _activeArea.Start = mouseOffset - mapRect.Position.Y; - _dragHasCollision = _activeArea.StartPosition.Y <= mapRect.Position.Y || - _activeArea.StartPosition.Y + 3 * tileSize.Y >= _activeArea.EndPosition.Y || - CheckDoorCollision(_activeArea.Direction, _activeArea); - } - else - { - var mouseOffset = Approach(mousePosition.Y, tileSize.Y); - _activeArea.EndPosition = new Vector2(_activeArea.EndPosition.X, mouseOffset); - _activeArea.End = mouseOffset - mapRect.Position.Y; - _dragHasCollision = _activeArea.EndPosition.Y >= mapRect.Position.Y + mapRect.Size.Y || - _activeArea.EndPosition.Y - 3 * tileSize.Y <= _activeArea.StartPosition.Y || - CheckDoorCollision(_activeArea.Direction, _activeArea); - } - } - } - } - else - { - if (Mathf.Abs(mousePosition.Y - mapRect.Position.Y) <= 8 && mousePosition.X >= mapRect.Position.X && - mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //上 - { - _hover = true; - _hoverDirection = DoorDirection.N; - var mouseOffset = Approach(mousePosition.X, tileSize.X); - _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, mapRect.Position.Y); - _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y); - - //判断是否能放下新的门 - if (_hoverPoint1.X <= mapRect.Position.X || _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X || - CheckDoorCollision()) - { - _canPut = false; - FindHoverPoint(mouseOffset); - } - else - { - _canPut = true; - _hasActivePoint = false; - _activeArea = null; - } - } - else if (Mathf.Abs(mousePosition.X - mapRect.Position.X) <= 8 && - mousePosition.Y >= mapRect.Position.Y && - mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //左 - { - _hover = true; - _hoverDirection = DoorDirection.W; - var mouseOffset = Approach(mousePosition.Y, tileSize.Y); - _hoverPoint1 = new Vector2(mapRect.Position.X, mouseOffset - tileSize.Y * 2); - _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4); - - //判断是否能放下新的门 - if (_hoverPoint1.Y <= mapRect.Position.Y || _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y || - CheckDoorCollision()) - { - _canPut = false; - FindHoverPoint(mouseOffset); - } - else - { - _canPut = true; - _hasActivePoint = false; - _activeArea = null; - } - } - else if (Mathf.Abs(mousePosition.Y - (mapRect.Position.Y + mapRect.Size.Y)) <= 8 && - mousePosition.X >= mapRect.Position.X && - mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //下 - { - _hover = true; - _hoverDirection = DoorDirection.S; - var mouseOffset = Approach(mousePosition.X, tileSize.X); - _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, - mapRect.Position.Y + mapRect.Size.Y); - _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y); - - //判断是否能放下新的门 - if (_hoverPoint1.X <= mapRect.Position.X || _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X || - CheckDoorCollision()) - { - _canPut = false; - FindHoverPoint(mouseOffset); - } - else - { - _canPut = true; - _hasActivePoint = false; - _activeArea = null; - } - } - else if (Mathf.Abs(mousePosition.X - (mapRect.Position.X + mapRect.Size.X)) <= 8 && - mousePosition.Y >= mapRect.Position.Y && - mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //右 - { - _hover = true; - _hoverDirection = DoorDirection.E; - var mouseOffset = Approach(mousePosition.Y, tileSize.Y); - _hoverPoint1 = new Vector2(mapRect.Position.X + mapRect.Size.X, - mouseOffset - tileSize.Y * 2); - _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4); - - //判断是否能放下新的门 - if (_hoverPoint1.Y <= mapRect.Position.Y || _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y || - CheckDoorCollision()) - { - _canPut = false; - FindHoverPoint(mouseOffset); - } - else - { - _canPut = true; - _hasActivePoint = false; - _activeArea = null; - } } else { - _hover = false; - _canPut = false; - _hasActivePoint = false; - _activeArea = null; - } - } + if (Mathf.Abs(mousePosition.Y - mapRect.Position.Y) <= 8 && mousePosition.X >= mapRect.Position.X && + mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //上 + { + _hover = true; + _hoverDirection = DoorDirection.N; + var mouseOffset = Approach(mousePosition.X, tileSize.X); + _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, mapRect.Position.Y); + _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y); - if (isClick && _canPut) //判断是否可以创建新的点 - { - CreateDoorArea(mapRect); - } - else if (_mouseDown && !_isDrag) //拖拽节点 - { - _isDrag = true; - _dragHasCollision = false; - if (_activeArea != null) - { - if (_activePointType == 0) - { - _startDragValue = _activeArea.Start; - _startDragPositionValue = _activeArea.StartPosition; - } - else - { - _startDragValue = _activeArea.End; - _startDragPositionValue = _activeArea.EndPosition; - } - } - } - else if (!_mouseDown && _isDrag) //松开拖拽的点 - { - _isDrag = false; - if (_activeArea != null) //提交拖拽结果 - { - if (_dragHasCollision) - { - if (_activePointType == 0) + //判断是否能放下新的门 + if (_hoverPoint1.X <= mapRect.Position.X || + _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X || + CheckDoorCollision()) { - _activeArea.Start = _startDragValue; - _activeArea.StartPosition = _startDragPositionValue; + _canPut = false; + FindHoverPoint(mouseOffset); } else { - _activeArea.End = _startDragValue; - _activeArea.EndPosition = _startDragPositionValue; + _canPut = true; + _hasActivePoint = false; + _activeArea = null; } } - OnDoorAreaChange(); + else if (Mathf.Abs(mousePosition.X - mapRect.Position.X) <= 8 && + mousePosition.Y >= mapRect.Position.Y && + mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //左 + { + _hover = true; + _hoverDirection = DoorDirection.W; + var mouseOffset = Approach(mousePosition.Y, tileSize.Y); + _hoverPoint1 = new Vector2(mapRect.Position.X, mouseOffset - tileSize.Y * 2); + _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4); + + //判断是否能放下新的门 + if (_hoverPoint1.Y <= mapRect.Position.Y || + _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y || + CheckDoorCollision()) + { + _canPut = false; + FindHoverPoint(mouseOffset); + } + else + { + _canPut = true; + _hasActivePoint = false; + _activeArea = null; + } + } + else if (Mathf.Abs(mousePosition.Y - (mapRect.Position.Y + mapRect.Size.Y)) <= 8 && + mousePosition.X >= mapRect.Position.X && + mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //下 + { + _hover = true; + _hoverDirection = DoorDirection.S; + var mouseOffset = Approach(mousePosition.X, tileSize.X); + _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, + mapRect.Position.Y + mapRect.Size.Y); + _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y); + + //判断是否能放下新的门 + if (_hoverPoint1.X <= mapRect.Position.X || + _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X || + CheckDoorCollision()) + { + _canPut = false; + FindHoverPoint(mouseOffset); + } + else + { + _canPut = true; + _hasActivePoint = false; + _activeArea = null; + } + } + else if (Mathf.Abs(mousePosition.X - (mapRect.Position.X + mapRect.Size.X)) <= 8 && + mousePosition.Y >= mapRect.Position.Y && + mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //右 + { + _hover = true; + _hoverDirection = DoorDirection.E; + var mouseOffset = Approach(mousePosition.Y, tileSize.Y); + _hoverPoint1 = new Vector2(mapRect.Position.X + mapRect.Size.X, + mouseOffset - tileSize.Y * 2); + _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4); + + //判断是否能放下新的门 + if (_hoverPoint1.Y <= mapRect.Position.Y || + _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y || + CheckDoorCollision()) + { + _canPut = false; + FindHoverPoint(mouseOffset); + } + else + { + _canPut = true; + _hasActivePoint = false; + _activeArea = null; + } + } + else + { + ClearState(); + } } - _dragHasCollision = false; + if (isClick && _canPut) //判断是否可以创建新的点 + { + CreateDoorArea(mapRect); + } + else if (_mouseDown && !_isDrag) //拖拽节点 + { + _isDrag = true; + _dragHasCollision = false; + if (_activeArea != null) + { + if (_activePointType == 0) + { + _startDragValue = _activeArea.Start; + _startDragPositionValue = _activeArea.StartPosition; + } + else + { + _startDragValue = _activeArea.End; + _startDragPositionValue = _activeArea.EndPosition; + } + } + } + else if (!_mouseDown && _isDrag) //松开拖拽的点 + { + _isDrag = false; + if (_activeArea != null) //提交拖拽结果 + { + if (_dragHasCollision) + { + if (_activePointType == 0) + { + _activeArea.Start = _startDragValue; + _activeArea.StartPosition = _startDragPositionValue; + } + else + { + _activeArea.End = _startDragValue; + _activeArea.EndPosition = _startDragPositionValue; + } + } + + OnDoorAreaChange(); + } + + _dragHasCollision = false; + } } - + else + { + ClearState(); + } + QueueRedraw(); } else { - _hover = false; - _canPut = false; - _hasActivePoint = false; - _activeArea = null; + ClearState(); } - + + //按下 ctrl + s 保存 + if (Input.IsKeyPressed(Key.Ctrl) && Input.IsKeyPressed(Key.S)) + { + _clickSave = true; + if (_canSave) + { + _canSave = false; + TriggerSave(); + } + } + else + { + _clickSave = false; + } } public override void _Draw() @@ -375,6 +449,7 @@ } } + //绘制区域 if (_doorConfigs != null) { var color2 = new Color(0, 1, 0, 0.8f); @@ -452,9 +527,40 @@ } } } + + //绘制导航, 现在有点问题, 绘制的内容会被自身的 tile 所挡住 + if (_dungeonTile != null) + { + var result = _dungeonTile.GetGenerateNavigationResult(); + if (result != null) + { + if (result.Success) + { + var polygonData = _dungeonTile.GetPolygonData(); + Utils.DrawNavigationPolygon(this, polygonData); + } + else + { + DrawCircle(result.Exception.Point * GenerateDungeon.TileCellSize, 10, Colors.Red); + } + } + } } } + private void ClearState() + { + _hover = false; + _canPut = false; + _hasActivePoint = false; + _activeArea = null; + } + + private void OnTileChanged() + { + _calcTileNavTimer = 1f; + } + //创建门 private void CreateDoorArea(Rect2 mapRect) { @@ -623,8 +729,17 @@ //区域数据修改 private void OnDoorAreaChange() { + _canSave = true; + } + + //触发保存操作 + private void TriggerSave() + { + //计算导航网格 + _dungeonTile.GenerateNavigationPolygon(0); + var polygonData = _dungeonTile.GetPolygonData(); var rect = GetUsedRect(); - SaveConfig(_doorConfigs, rect.Position, rect.Size, Name); + SaveConfig(_doorConfigs, rect.Position, rect.Size, polygonData.ToList(), Name); } /// @@ -642,7 +757,7 @@ /// /// 保存房间配置 /// - public static void SaveConfig(List doorConfigs, Vector2I position, Vector2I size, string name) + public static void SaveConfig(List doorConfigs, Vector2I position, Vector2I size, List polygonData, string name) { //存入本地 var path = RoomTileDataDir + name + ".json"; @@ -650,14 +765,16 @@ roomInfo.Position = new SerializeVector2(position); roomInfo.Size = new SerializeVector2(size); roomInfo.DoorAreaInfos = doorConfigs; + roomInfo.NavigationList = polygonData; var config = new JsonSerializerOptions(); config.WriteIndented = true; var jsonStr = JsonSerializer.Serialize(roomInfo, config); File.WriteAllText(path, jsonStr); + GD.Print("保存房间配置成功!路径为:" + path); } - + /// /// 读取房间配置 /// @@ -697,13 +814,15 @@ { // 下面这句代码在 Godot4.0_rc2的编辑器模式下, 重载脚本会导致编辑器一直报错!, 所以暂时先用下面的方法 //var roomInfo = JsonSerializer.Deserialize(text); - + var obj = Json.ParseString(text).AsGodotDictionary(); var roomInfo = new DungeonRoomInfo(); var position = obj["Position"].AsGodotDictionary(); roomInfo.Position = new SerializeVector2(position["X"].AsInt32(), position["Y"].AsInt32()); + var size = obj["Size"].AsGodotDictionary(); roomInfo.Size = new SerializeVector2(size["X"].AsInt32(), size["Y"].AsInt32()); + var doorAreaInfos = obj["DoorAreaInfos"].AsGodotArray(); roomInfo.DoorAreaInfos = new List(); foreach (var item in doorAreaInfos) @@ -716,6 +835,25 @@ roomInfo.DoorAreaInfos.Add(doorInfo); } + var navigationArray = obj["NavigationList"].AsGodotArray(); + roomInfo.NavigationList = new List(); + for (var i = 0; i < navigationArray.Count; i++) + { + var navigation = navigationArray[i].AsGodotDictionary(); + var polygonData = new NavigationPolygonData(); + + polygonData.Type = (NavigationPolygonType)navigation["Type"].AsInt32(); + polygonData.Points = new List(); + var pointArray = navigation["Points"].AsGodotArray(); + for (var j = 0; j < pointArray.Count; j++) + { + var point = pointArray[j].AsGodotDictionary(); + polygonData.Points.Add(new SerializeVector2(point["X"].AsInt32(), point["Y"].AsInt32())); + } + + roomInfo.NavigationList.Add(polygonData); + } + return roomInfo; } #endif diff --git a/DungeonShooting_Godot/src/framework/map/DungeonTile.cs b/DungeonShooting_Godot/src/framework/map/DungeonTile.cs new file mode 100644 index 0000000..fcf1cb9 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/map/DungeonTile.cs @@ -0,0 +1,1132 @@ + +using System; +using System.Collections.Generic; +using Godot; + +/// +/// 地牢地砖管理类, 提供一些操作 TileMap 和计算导航的接口 +/// +public class DungeonTile +{ + /// + /// TileMap 底板的层级 + /// + public const int FloorMapLayer = 0; + /// + /// TileMap 中层的层级 + /// + public const int MiddleMapLayer = 1; + /// + /// TileMap 上层的层级 + /// + public const int TopMapLayer = 2; + /// + /// 连接房间的过道的地板层级 + /// + public const int AisleFloorMapLayer = 3; + + /// + /// 配置层级的自定义数据名称 + /// + public const string CustomTileLayerName = "TileLayer"; + + //--------------------- 导航 ------------------------- + + //已经标记过的点 + private readonly HashSet _usePoints = new HashSet(); + + //导航区域数据 + private readonly List _polygonDataList = new List(); + + //连接门的导航区域 + private readonly List _connectDoorPolygonDataList = new List(); + + //---------------------------------------------------- + + private TileMap _tileRoot; + //地面地砖在 Atlas 的位置 + private List _floorAtlasCoords; + //生成导航的结果 + private GenerateNavigationResult _generateNavigationResult; + + public DungeonTile(TileMap tileRoot) + { + _tileRoot = tileRoot; + } + + /// + /// 根据 roomInfo 和 config 数据自动填充 tileMap 参数中的地图数据 + /// + public void AutoFillRoomTile(AutoTileConfig config, RoomInfo roomInfo) + { + _connectDoorPolygonDataList.Clear(); + _AutoFillRoomTile(config, roomInfo); + } + + private void _AutoFillRoomTile(AutoTileConfig config, RoomInfo roomInfo) + { + foreach (var info in roomInfo.Next) + { + _AutoFillRoomTile(config, info); + } + + //铺房间 + if (roomInfo.RoomSplit == null) + { + FillRect(FloorMapLayer, config.Floor, roomInfo.Position + Vector2.One, + roomInfo.Size - new Vector2(2, 2)); + + FillRect(TopMapLayer, config.IN_LT, roomInfo.Position, Vector2.One); + FillRect(TopMapLayer, config.L, roomInfo.Position + new Vector2(0, 1), + new Vector2(1, roomInfo.Size.Y - 2)); + FillRect(TopMapLayer, config.IN_LB, roomInfo.Position + new Vector2(0, roomInfo.Size.Y - 1), + new Vector2(1, 1)); + FillRect(TopMapLayer, config.B, roomInfo.Position + new Vector2(1, roomInfo.Size.Y - 1), + new Vector2(roomInfo.Size.X - 2, 1)); + FillRect(TopMapLayer, config.IN_RB, + roomInfo.Position + new Vector2(roomInfo.Size.X - 1, roomInfo.Size.Y - 1), + Vector2.One); + FillRect(TopMapLayer, config.R, roomInfo.Position + new Vector2(roomInfo.Size.X - 1, 1), + new Vector2(1, roomInfo.Size.Y - 2)); + FillRect(TopMapLayer, config.IN_RT, roomInfo.Position + new Vector2(roomInfo.Size.X - 1, 0), + Vector2.One); + FillRect(MiddleMapLayer, config.T, roomInfo.Position + Vector2.Right, + new Vector2(roomInfo.Size.X - 2, 1)); + } + else + { + var rectSize = roomInfo.RoomSplit.RoomInfo.Size; + var rectPos = roomInfo.RoomSplit.RoomInfo.Position; + var template = ResourceManager.Load(roomInfo.RoomSplit.ScenePath); + var tileInstance = template.Instantiate(); + for (int i = 0; i < rectSize.X; i++) + { + for (int j = 0; j < rectSize.Y; j++) + { + var coords = new Vector2I((int)(rectPos.X + i), (int)(rectPos.Y + j)); + var atlasCoords = tileInstance.GetCellAtlasCoords(0, coords); + if (atlasCoords.X != -1 && atlasCoords.Y != -1) + { + //获取自定义层级 + var layer = tileInstance.GetCellTileData(0, coords).GetCustomData(CustomTileLayerName) + .AsInt32(); + layer = Mathf.Clamp(layer, FloorMapLayer, TopMapLayer); + _tileRoot.SetCell(layer, new Vector2I(roomInfo.Position.X + i, roomInfo.Position.Y + j), + 1, atlasCoords); + } + } + } + + tileInstance.QueueFree(); + } + + //铺过道 + foreach (var doorInfo in roomInfo.Doors) + { + if (doorInfo.ConnectRoom.Id > roomInfo.Id) + { + //普通的直线连接 + var doorDir1 = doorInfo.Direction; + var doorDir2 = doorInfo.ConnectDoor.Direction; + if (!doorInfo.HasCross) + { + //方向, 0横向, 1纵向 + int dir = 0; + var rect = Utils.CalcRect( + doorInfo.OriginPosition.X, + doorInfo.OriginPosition.Y, + doorInfo.ConnectDoor.OriginPosition.X, + doorInfo.ConnectDoor.OriginPosition.Y + ); + if (doorDir1 == DoorDirection.N || doorDir1 == DoorDirection.S) + { + rect.Size = new Vector2(GenerateDungeon.CorridorWidth, rect.Size.Y); + dir = 1; + } + else + { + rect.Size = new Vector2(rect.Size.X, GenerateDungeon.CorridorWidth); + } + + if (dir == 0) //横向 + { + FullHorizontalAisleWall(config, rect, 0); + } + else //纵向 + { + FullVerticalAisleWall(config, rect, 0); + } + } + else //带交叉点 + { + //方向, 0横向, 1纵向 + int dir1 = 0; + int dir2 = 0; + + Rect2 rect; + Rect2 rect2; + + //计算范围 + switch (doorDir1) + { + case DoorDirection.E: //→ + rect = new Rect2( + doorInfo.OriginPosition.X, + doorInfo.OriginPosition.Y, + doorInfo.Cross.X - doorInfo.OriginPosition.X, + GenerateDungeon.CorridorWidth + ); + break; + case DoorDirection.W: //← + rect = new Rect2( + doorInfo.Cross.X + GenerateDungeon.CorridorWidth, + doorInfo.Cross.Y, + doorInfo.OriginPosition.X - (doorInfo.Cross.X + GenerateDungeon.CorridorWidth), + GenerateDungeon.CorridorWidth + ); + break; + case DoorDirection.S: //↓ + dir1 = 1; + rect = new Rect2( + doorInfo.OriginPosition.X, + doorInfo.OriginPosition.Y, + GenerateDungeon.CorridorWidth, + doorInfo.Cross.Y - doorInfo.OriginPosition.Y + ); + break; + case DoorDirection.N: //↑ + dir1 = 1; + rect = new Rect2( + doorInfo.Cross.X, + doorInfo.Cross.Y + GenerateDungeon.CorridorWidth, + GenerateDungeon.CorridorWidth, + doorInfo.OriginPosition.Y - (doorInfo.Cross.Y + GenerateDungeon.CorridorWidth) + ); + break; + default: + rect = new Rect2(); + break; + } + + switch (doorDir2) + { + case DoorDirection.E: //→ + rect2 = new Rect2( + doorInfo.ConnectDoor.OriginPosition.X, + doorInfo.ConnectDoor.OriginPosition.Y, + doorInfo.Cross.X - doorInfo.ConnectDoor.OriginPosition.X, + GenerateDungeon.CorridorWidth + ); + break; + case DoorDirection.W: //← + rect2 = new Rect2( + doorInfo.Cross.X + GenerateDungeon.CorridorWidth, + doorInfo.Cross.Y, + doorInfo.ConnectDoor.OriginPosition.X - + (doorInfo.Cross.X + GenerateDungeon.CorridorWidth), + GenerateDungeon.CorridorWidth + ); + break; + case DoorDirection.S: //↓ + dir2 = 1; + rect2 = new Rect2( + doorInfo.ConnectDoor.OriginPosition.X, + doorInfo.ConnectDoor.OriginPosition.Y, + GenerateDungeon.CorridorWidth, + doorInfo.Cross.Y - doorInfo.ConnectDoor.OriginPosition.Y + ); + break; + case DoorDirection.N: //↑ + dir2 = 1; + rect2 = new Rect2( + doorInfo.Cross.X, + doorInfo.Cross.Y + GenerateDungeon.CorridorWidth, + GenerateDungeon.CorridorWidth, + doorInfo.ConnectDoor.OriginPosition.Y - + (doorInfo.Cross.Y + GenerateDungeon.CorridorWidth) + ); + break; + default: + rect2 = new Rect2(); + break; + } + + FillRect(AisleFloorMapLayer, config.Floor, doorInfo.Cross + Vector2.One, + new Vector2(GenerateDungeon.CorridorWidth - 2, GenerateDungeon.CorridorWidth - 2)); + + //墙壁, 0横向, 1纵向 + if (dir1 == 0) + { + FullHorizontalAisleWall(config, rect, doorDir1 == DoorDirection.W ? 1: 2); + } + else + { + FullVerticalAisleWall(config, rect, doorDir1 == DoorDirection.N ? 1 : 2); + } + + if (dir2 == 0) + { + FullHorizontalAisleWall(config, rect2, doorDir2 == DoorDirection.W ? 1 : 2); + } + else + { + FullVerticalAisleWall(config, rect2, doorDir2 == DoorDirection.N ? 1 : 2); + } + + if ((doorDir1 == DoorDirection.N && doorDir2 == DoorDirection.E) || //↑→ + (doorDir2 == DoorDirection.N && doorDir1 == DoorDirection.E)) + { + FillRect(TopMapLayer, config.OUT_RT, + doorInfo.Cross + new Vector2(0, GenerateDungeon.CorridorWidth - 1), + Vector2.One); + FillRect(TopMapLayer, config.IN_RT, doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 0), + Vector2.One); + FillRect(MiddleMapLayer, config.T, doorInfo.Cross, new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); + FillRect(TopMapLayer, config.R, doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 1), + new Vector2(1, GenerateDungeon.CorridorWidth - 1)); + } + else if ((doorDir1 == DoorDirection.E && doorDir2 == DoorDirection.S) || //→↓ + (doorDir2 == DoorDirection.E && doorDir1 == DoorDirection.S)) + { + FillRect(MiddleMapLayer, config.OUT_RB, doorInfo.Cross, Vector2.One); + FillRect(TopMapLayer, config.IN_RB, + doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, + GenerateDungeon.CorridorWidth - 1), + Vector2.One); + FillRect(TopMapLayer, config.R, doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 0), + new Vector2(1, GenerateDungeon.CorridorWidth - 1)); + FillRect(TopMapLayer, config.B, doorInfo.Cross + new Vector2(0, GenerateDungeon.CorridorWidth - 1), + new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); + } + else if ((doorDir1 == DoorDirection.S && doorDir2 == DoorDirection.W) || //↓← + (doorDir2 == DoorDirection.S && doorDir1 == DoorDirection.W)) + { + FillRect(MiddleMapLayer, config.OUT_LB, + doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 0), Vector2.One); + FillRect(TopMapLayer, config.IN_LB, doorInfo.Cross + new Vector2(0, GenerateDungeon.CorridorWidth - 1), + Vector2.One); + FillRect(TopMapLayer, config.L, doorInfo.Cross, new Vector2(1, GenerateDungeon.CorridorWidth - 1)); + FillRect(TopMapLayer, config.B, doorInfo.Cross + new Vector2(1, GenerateDungeon.CorridorWidth - 1), + new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); + } + else if ((doorDir1 == DoorDirection.W && doorDir2 == DoorDirection.N) || //←↑ + (doorDir2 == DoorDirection.W && doorDir1 == DoorDirection.N)) + { + FillRect(TopMapLayer, config.OUT_LT, + doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, + GenerateDungeon.CorridorWidth - 1), + Vector2.One); + FillRect(TopMapLayer, config.IN_LT, doorInfo.Cross, Vector2.One); + FillRect(MiddleMapLayer, config.T, doorInfo.Cross + new Vector2(1, 0), + new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); + FillRect(TopMapLayer, config.L, doorInfo.Cross + new Vector2(0, 1), + new Vector2(1, GenerateDungeon.CorridorWidth - 1)); + } + + //在房间墙上开洞 + switch (doorDir1) + { + case DoorDirection.E: //→ + ClearRect(TopMapLayer, doorInfo.OriginPosition + new Vector2(-1, 1), + new Vector2(1, rect.Size.Y - 2)); + break; + case DoorDirection.W: //← + ClearRect(TopMapLayer, doorInfo.OriginPosition + new Vector2(0, 1), + new Vector2(1, rect.Size.Y - 2)); + break; + case DoorDirection.S: //↓ + ClearRect(TopMapLayer, doorInfo.OriginPosition + new Vector2(1, -1), + new Vector2(rect.Size.X - 2, 1)); + break; + case DoorDirection.N: //↑ + ClearRect(MiddleMapLayer, doorInfo.OriginPosition + new Vector2(1, 2), + new Vector2(rect.Size.X - 2, 1)); + break; + } + + switch (doorDir2) + { + case DoorDirection.E: //→ + ClearRect(TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(-1, 1), + new Vector2(1, rect2.Size.Y - 2)); + break; + case DoorDirection.W: //← + ClearRect(TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(0, 1), + new Vector2(1, rect2.Size.Y - 2)); + break; + case DoorDirection.S: //↓ + ClearRect(TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, -1), + new Vector2(rect2.Size.X - 2, 1)); + break; + case DoorDirection.N: //↑ + ClearRect(MiddleMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, 0), + new Vector2(rect2.Size.X - 2, 1)); + break; + } + } + } + } + } + + //填充tile区域 + private void FillRect(int layer, TileCellInfo info, Vector2 pos, Vector2 size) + { + for (int i = 0; i < size.X; i++) + { + for (int j = 0; j < size.Y; j++) + { + _tileRoot.SetCell(layer, new Vector2I((int)pos.X + i, (int)pos.Y + j), 1, info.AutotileCoord); + } + } + } + + //清除tile区域 + private void ClearRect(int layer, Vector2 pos, Vector2 size) + { + for (int i = 0; i < size.X; i++) + { + for (int j = 0; j < size.Y; j++) + { + _tileRoot.SetCell(layer, new Vector2I((int)pos.X + i, (int)pos.Y + j), -1); + } + } + } + + private void FullHorizontalAisleWall(AutoTileConfig config, Rect2 rect, int type) + { + FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(0, 1), rect.Size - new Vector2(0, 2)); + FillRect(MiddleMapLayer, config.T, rect.Position, new Vector2(rect.Size.X, 1)); + FillRect(TopMapLayer, config.B, rect.Position + new Vector2(0, rect.Size.Y - 1), new Vector2(rect.Size.X, 1)); + //左 + ClearRect(TopMapLayer, rect.Position + new Vector2(-1, 1), new Vector2(1, rect.Size.Y - 2)); + if (type == 1) + { + FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(-1, 1), new Vector2(1, rect.Size.Y - 2)); + } + else + { + FillRect(FloorMapLayer, config.Floor, rect.Position + new Vector2(-1, 1), new Vector2(1, rect.Size.Y - 2)); + //生成门的导航区域 + var x = rect.Position.X * GenerateDungeon.TileCellSize; + var y = rect.Position.Y * GenerateDungeon.TileCellSize; + AddDoorNavigation( + new SerializeVector2(x - GenerateDungeon.TileCellSize * 1.5f, y + GenerateDungeon.TileCellSize * 1.5f), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 0.5f, y + GenerateDungeon.TileCellSize * 1.5f), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 0.5f, y + GenerateDungeon.TileCellSize * 2.5f), + new SerializeVector2(x - GenerateDungeon.TileCellSize * 1.5f, y + GenerateDungeon.TileCellSize * 2.5f) + ); + } + + //右 + ClearRect(TopMapLayer, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2)); + if (type == 2) + { + FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2)); + } + else + { + FillRect(FloorMapLayer, config.Floor, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2)); + //生成门的导航区域 + var x = rect.Position.X * GenerateDungeon.TileCellSize; + var y = rect.Position.Y * GenerateDungeon.TileCellSize; + AddDoorNavigation( + new SerializeVector2(x - GenerateDungeon.TileCellSize * 1.5f + (rect.Size.X + 1) * GenerateDungeon.TileCellSize, y + GenerateDungeon.TileCellSize * 1.5f), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 0.5f + (rect.Size.X + 1) * GenerateDungeon.TileCellSize, y + GenerateDungeon.TileCellSize * 1.5f), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 0.5f + (rect.Size.X + 1) * GenerateDungeon.TileCellSize, y + GenerateDungeon.TileCellSize * 2.5f), + new SerializeVector2(x - GenerateDungeon.TileCellSize * 1.5f + (rect.Size.X + 1) * GenerateDungeon.TileCellSize, y + GenerateDungeon.TileCellSize * 2.5f) + ); + } + } + + private void FullVerticalAisleWall(AutoTileConfig config, Rect2 rect, int type) + { + FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(1, 0), rect.Size - new Vector2(2, 0)); + FillRect(TopMapLayer, config.L, rect.Position, new Vector2(1, rect.Size.Y)); + FillRect(TopMapLayer, config.R, rect.Position + new Vector2(rect.Size.X - 1, 0), new Vector2(1, rect.Size.Y)); + //上 + ClearRect(TopMapLayer, rect.Position + new Vector2(1, -1), new Vector2(rect.Size.X - 2, 1)); + if (type == 1) + { + FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(1, -1), new Vector2(rect.Size.X - 2, 1)); + } + else + { + FillRect(FloorMapLayer, config.Floor, rect.Position + new Vector2(1, -1), new Vector2(rect.Size.X - 2, 1)); + //生成门的导航区域 + var x = rect.Position.X * GenerateDungeon.TileCellSize; + var y = rect.Position.Y * GenerateDungeon.TileCellSize; + AddDoorNavigation( + new SerializeVector2(x + GenerateDungeon.TileCellSize * 1.5f, y - GenerateDungeon.TileCellSize * 1.5f), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 2.5f, y - GenerateDungeon.TileCellSize * 1.5f), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 2.5f, y + GenerateDungeon.TileCellSize * 0.5f), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 1.5f, y + GenerateDungeon.TileCellSize * 0.5f) + ); + } + //下 + ClearRect(MiddleMapLayer, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1)); + if (type == 2) + { + FillRect(AisleFloorMapLayer, config.Floor, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1)); + } + else + { + FillRect(FloorMapLayer, config.Floor, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1)); + //生成门的导航区域 + var x = rect.Position.X * GenerateDungeon.TileCellSize; + var y = rect.Position.Y * GenerateDungeon.TileCellSize; + AddDoorNavigation( + new SerializeVector2(x + GenerateDungeon.TileCellSize * 1.5f, y - GenerateDungeon.TileCellSize * 1.5f + (rect.Size.Y + 1) * GenerateDungeon.TileCellSize), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 2.5f, y - GenerateDungeon.TileCellSize * 1.5f + (rect.Size.Y + 1) * GenerateDungeon.TileCellSize), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 2.5f, y + GenerateDungeon.TileCellSize * 0.5f + (rect.Size.Y + 1) * GenerateDungeon.TileCellSize), + new SerializeVector2(x + GenerateDungeon.TileCellSize * 1.5f, y + GenerateDungeon.TileCellSize * 0.5f + (rect.Size.Y + 1) * GenerateDungeon.TileCellSize) + ); + } + } + + private void AddDoorNavigation(SerializeVector2 p1, SerializeVector2 p2, SerializeVector2 p3, SerializeVector2 p4) + { + var polygonData = new NavigationPolygonData(); + polygonData.Type = NavigationPolygonType.Out; + polygonData.Points.Add(p1); + polygonData.Points.Add(p2); + polygonData.Points.Add(p3); + polygonData.Points.Add(p4); + _connectDoorPolygonDataList.Add(polygonData); + } + + //报错数据 + private void TestData() + { + _polygonDataList.Clear(); + _polygonDataList.Add(new NavigationPolygonData(){Type = NavigationPolygonType.Out, Points = new List(new []{ new SerializeVector2(-456, 712), new SerializeVector2(-440, 712), new SerializeVector2(-440, 792), new SerializeVector2(-456, 792) })}); + _polygonDataList.Add(new NavigationPolygonData(){Type = NavigationPolygonType.In, Points = new List(new []{ new SerializeVector2(-1048, 744), new SerializeVector2(-840, 744), new SerializeVector2(-840, 840), new SerializeVector2(-1048, 840) })}); + _polygonDataList.Add(new NavigationPolygonData(){Type = NavigationPolygonType.Out, Points = new List(new []{ new SerializeVector2(488, 920), new SerializeVector2(504, 920), new SerializeVector2(504, 1128), new SerializeVector2(488, 1128) })}); + _polygonDataList.Add(new NavigationPolygonData(){Type = NavigationPolygonType.Out, Points = new List(new []{ new SerializeVector2(1320, 984), new SerializeVector2(1352, 984), new SerializeVector2(1352, 1096), new SerializeVector2(1432, 1096), new SerializeVector2(1432, 984), new SerializeVector2(1576, 984), new SerializeVector2(1576, 1128), new SerializeVector2(1544, 1128), new SerializeVector2(1544, 1000), new SerializeVector2(1464, 1000), new SerializeVector2(1464, 1128), new SerializeVector2(1320, 1128) })}); + _polygonDataList.Add(new NavigationPolygonData(){Type = NavigationPolygonType.Out, Points = new List(new []{ new SerializeVector2(712, 1432), new SerializeVector2(984, 1432), new SerializeVector2(984, 1592), new SerializeVector2(712, 1592) })}); + } + + /// + /// 计算并动生成导航区域, layer 为需要计算的层级,如果没有设置 floorAtlasCoords,则该 layer 下不为空的地砖都将视为可行走区域 + /// + public void GenerateNavigationPolygon(int layer) + { + _usePoints.Clear(); + _polygonDataList.Clear(); + + try + { + var size = new Vector2(_tileRoot.CellQuadrantSize, _tileRoot.CellQuadrantSize); + + var rect = _tileRoot.GetUsedRect(); + + var x = rect.Position.X; + var y = rect.Position.Y; + var w = rect.Size.X; + var h = rect.Size.Y; + + for (int j = y; j < h; j++) + { + for (int i = x; i < w; i++) + { + if (IsWayTile(layer, i, j)) + { + if (!_usePoints.Contains(new Vector2(i, j))) + { + NavigationPolygonData polygonData = null; + + if (!IsWayTile(layer, i, j - 1)) + { + polygonData = CalcOutline(layer, i, j, size); + } + else if (!IsWayTile(layer, i, j + 1)) + { + polygonData = CalcInline(layer, i, j, size); + } + + if (polygonData != null) + { + _polygonDataList.Add(polygonData); + } + } + } + } + } + + _generateNavigationResult = new GenerateNavigationResult(true); + } + catch (NavigationPointInterleavingException e) + { + _usePoints.Clear(); + _polygonDataList.Clear(); + GD.Print(e.Message); + _generateNavigationResult = new GenerateNavigationResult(false, e); + } + } + + /// + /// 获取生成导航区域操作的结果, 如果没有调用过 GenerateNavigationPolygon() 函数, 则返回 null + /// + /// + public GenerateNavigationResult GetGenerateNavigationResult() + { + return _generateNavigationResult; + } + + /// + /// 将导航区域挂载到 navigationRoot 上 + /// + public void MountNavigationPolygon(Node2D navigationRoot) + { + //TestData(); + // 在 Godot4.0_rc6 中 如果将所有点都放在 NavigationPolygon 里面, 即使点是对的, 但调用 MakePolygonsFromOutlines 还是可能会报错, 这应该是个bug + for (var i = 0; i < _polygonDataList.Count; i++) + { + var polygonData = _polygonDataList[i]; + CreateNavigationRegion(navigationRoot, polygonData); + } + + for (var i = 0; i < _connectDoorPolygonDataList.Count; i++) + { + var polygonData = _connectDoorPolygonDataList[i]; + CreateNavigationRegion(navigationRoot, polygonData); + } + } + + private void CreateNavigationRegion(Node2D navigationRoot, NavigationPolygonData polygonData) + { + var polygon = new NavigationPolygon(); + polygon.AddOutline(polygonData.ConvertPointsToVector2Array()); + polygon.MakePolygonsFromOutlines(); + var navigationPolygon = new NavigationRegion2D(); + navigationPolygon.Name = "NavigationRegion" + (navigationRoot.GetChildCount() + 1); + navigationPolygon.NavigationPolygon = polygon; + navigationRoot.AddChild(navigationPolygon); + } + + /// + /// 获取房间内的导航点数据 + /// + public NavigationPolygonData[] GetPolygonData() + { + return _polygonDataList.ToArray(); + } + + /// + /// 获取连接门导航数据, 必须要调用 AutoFillRoomTile() 函数才有数据 + /// + public NavigationPolygonData[] GetConnectDoorPolygonData() + { + return _connectDoorPolygonDataList.ToArray(); + } + + /// + /// 设置地面的地砖,将影响导航网格计算 + /// + public void SetFloorAtlasCoords(List floorAtlasCoords) + { + _floorAtlasCoords = floorAtlasCoords; + } + + /// + /// 返回指定位置的Tile是否为可以行走 + /// + private bool IsWayTile(int layer, int x, int y) + { + if (_floorAtlasCoords == null || _floorAtlasCoords.Count == 0) + { + return _tileRoot.GetCellTileData(layer, new Vector2I(x, y)) != null; + } + + var result = _tileRoot.GetCellAtlasCoords(layer, new Vector2I(x, y)); + return _floorAtlasCoords.Contains(result); + } + + //计算导航网格外轮廓 + private NavigationPolygonData CalcOutline(int layer, int i, int j, Vector2 size) + { + var polygonData = new NavigationPolygonData(); + polygonData.Type = NavigationPolygonType.Out; + var points = polygonData.Points; + // 0:右, 1:下, 2:左, 3:上 + var dir = 0; + var offset = new Vector2(size.X * 0.5f, size.Y * 0.5f); + //找到路, 向右开始找边界 + var startPos = new Vector2(i, j); + + var tempI = i; + var tempJ = j; + + while (true) + { + switch (dir) + { + case 0: //右 + { + if (IsWayTile(layer, tempI, tempJ - 1)) //先向上找 + { + dir = 3; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempJ--; + break; + } + else if (IsWayTile(layer, tempI + 1, tempJ)) //再向右找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI++; + break; + } + else if (IsWayTile(layer, tempI, tempJ + 1)) //向下找 + { + dir = 1; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + + offset.Y)); + PutUsePoint(pos); + + tempJ++; + break; + } + + return null; + } + case 1: //下 + { + if (IsWayTile(layer, tempI + 1, tempJ)) //先向右找 + { + dir = 0; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI++; + break; + } + else if (IsWayTile(layer, tempI, tempJ + 1)) //再向下找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ++; + break; + } + else if (IsWayTile(layer, tempI - 1, tempJ)) //向左找 + { + dir = 2; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI--; + break; + } + + return null; + } + case 2: //左 + { + if (IsWayTile(layer, tempI, tempJ + 1)) //先向下找 + { + dir = 1; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempJ++; + break; + } + else if (IsWayTile(layer, tempI - 1, tempJ)) //再向左找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI--; + break; + } + else if (IsWayTile(layer, tempI, tempJ - 1)) //向上找 + { + dir = 3; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempJ--; + break; + } + + return null; + } + case 3: //上 + { + if (IsWayTile(layer, tempI - 1, tempJ)) //先向左找 + { + dir = 2; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI--; + break; + } + else if (IsWayTile(layer, tempI, tempJ - 1)) //再向上找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ--; + break; + } + else if (IsWayTile(layer, tempI + 1, tempJ)) //向右找 + { + dir = 0; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI++; + break; + } + + return null; + } + } + } + } + + //计算导航网格内轮廓 + private NavigationPolygonData CalcInline(int layer, int i, int j, Vector2 size) + { + var polygonData = new NavigationPolygonData(); + polygonData.Type = NavigationPolygonType.In; + var points = polygonData.Points; + // 0:右, 1:下, 2:左, 3:上 + var dir = 0; + var offset = new Vector2(size.X * 0.5f, size.Y * 0.5f); + //找到路, 向右开始找边界 + var startPos = new Vector2(i - 1, j); + + var tempI = i; + var tempJ = j; + + while (true) + { + switch (dir) + { + case 0: //右 + { + if (IsWayTile(layer, tempI, tempJ + 1)) //向下找 + { + dir = 1; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempJ++; + break; + } + else if (IsWayTile(layer, tempI + 1, tempJ)) //再向右找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI++; + break; + } + else if (IsWayTile(layer, tempI, tempJ - 1)) //先向上找 + { + dir = 3; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempJ--; + break; + } + + return null; + } + case 1: //下 + { + if (IsWayTile(layer, tempI - 1, tempJ)) //向左找 + { + dir = 2; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI--; + break; + } + else if (IsWayTile(layer, tempI, tempJ + 1)) //再向下找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ++; + break; + } + else if (IsWayTile(layer, tempI + 1, tempJ)) //先向右找 + { + dir = 0; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI++; + break; + } + + return null; + } + case 2: //左 + { + if (IsWayTile(layer, tempI, tempJ - 1)) //向上找 + { + dir = 3; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempJ--; + break; + } + else if (IsWayTile(layer, tempI - 1, tempJ)) //再向左找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempI--; + break; + } + else if (IsWayTile(layer, tempI, tempJ + 1)) //先向下找 + { + dir = 1; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempJ++; + break; + } + + return null; + } + case 3: //上 + { + if (IsWayTile(layer, tempI + 1, tempJ)) //向右找 + { + dir = 0; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI++; + break; + } + else if (IsWayTile(layer, tempI, tempJ - 1)) //再向上找 + { + if (points.Count == 0) + { + points.Add(new SerializeVector2((tempI - 1) * size.X + offset.X, tempJ * size.Y + offset.Y)); + } + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + PutUsePoint(new Vector2(tempI, tempJ)); + tempJ--; + break; + } + else if (IsWayTile(layer, tempI - 1, tempJ)) //先向左找 + { + dir = 2; + + var pos = new Vector2(tempI, tempJ); + if (points.Count > 1 && pos == startPos) + { + return polygonData; + } + + points.Add(new SerializeVector2(tempI * size.X + offset.X, tempJ * size.Y + offset.Y)); + PutUsePoint(pos); + + tempI--; + break; + } + + return null; + } + } + } + } + + //记录导航网格中已经使用过的坐标 + private void PutUsePoint(Vector2 pos) + { + if (_usePoints.Contains(pos)) + { + throw new NavigationPointInterleavingException(pos, "生成导航多边形发生错误! 点: " + pos + "发生交错!"); + } + + _usePoints.Add(pos); + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/GenerateDungeon.cs b/DungeonShooting_Godot/src/framework/map/GenerateDungeon.cs index 752bb51..84511b5 100644 --- a/DungeonShooting_Godot/src/framework/map/GenerateDungeon.cs +++ b/DungeonShooting_Godot/src/framework/map/GenerateDungeon.cs @@ -66,6 +66,9 @@ private int _maxFailCount = 10; private int _failCount = 0; + //最大尝试次数 + private int _maxTryCount = 10; + private enum GenerateRoomErrorCode { NoError, @@ -73,10 +76,34 @@ RoomFull, //超出区域 OutArea, - //碰到其他房间或过道 - HasCollision, - //没有合适的门 - NoProperDoor, + //没有合适的位置 + NoSuitableLocation + // //碰到其他房间或过道 + // HasCollision, + // //没有合适的门 + // NoProperDoor, + } + + /// + /// 遍历所有房间 + /// + public void EachRoom(Action cb) + { + EachRoom(StartRoom, cb); + } + + private void EachRoom(RoomInfo roomInfo, Action cb) + { + if (roomInfo == null) + { + return; + } + + cb(roomInfo); + foreach (var next in roomInfo.Next) + { + EachRoom(next, cb); + } } /// @@ -137,68 +164,85 @@ if (prevRoomInfo != null) //表示这不是第一个房间, 就得判断当前位置下的房间是否被遮挡 { - //房间间隔 - var space = Utils.RandomRangeInt(_roomMinInterval, _roomMaxInterval); - //中心偏移 - int offset; - if (direction == 0 || direction == 2) + //生成的位置可能会和上一个房间对不上, 需要多次尝试 + var tryCount = 0; //当前尝试次数 + for (; tryCount < _maxTryCount; tryCount++) { - offset = Utils.RandomRangeInt(-(int)(prevRoomInfo.Size.X * _roomVerticalMinDispersion), - (int)(prevRoomInfo.Size.X * _roomVerticalMaxDispersion)); - } - else - { - offset = Utils.RandomRangeInt(-(int)(prevRoomInfo.Size.Y * _roomHorizontalMinDispersion), - (int)(prevRoomInfo.Size.Y * _roomHorizontalMaxDispersion)); - } - - //计算房间位置 - if (direction == 0) //上 - { - room.Position = new Vector2I(prevRoomInfo.Position.X + offset, - prevRoomInfo.Position.Y - room.Size.Y - space); - } - else if (direction == 1) //右 - { - room.Position = new Vector2I(prevRoomInfo.Position.X + prevRoomInfo.Size.Y + space, - prevRoomInfo.Position.Y + offset); - } - else if (direction == 2) //下 - { - room.Position = new Vector2I(prevRoomInfo.Position.X + offset, - prevRoomInfo.Position.Y + prevRoomInfo.Size.Y + space); - } - else if (direction == 3) //左 - { - room.Position = new Vector2I(prevRoomInfo.Position.X - room.Size.X - space, - prevRoomInfo.Position.Y + offset); - } - - //是否在限制区域内 - if (_enableLimitRange) - { - if (room.GetHorizontalStart() < -_rangeX || room.GetHorizontalEnd() > _rangeX || room.GetVerticalStart() < -_rangeY || room.GetVerticalEnd() > _rangeY) + //房间间隔 + var space = Utils.RandomRangeInt(_roomMinInterval, _roomMaxInterval); + //中心偏移 + int offset; + if (direction == 0 || direction == 2) { - resultRoom = null; - return GenerateRoomErrorCode.OutArea; + offset = Utils.RandomRangeInt(-(int)(prevRoomInfo.Size.X * _roomVerticalMinDispersion), + (int)(prevRoomInfo.Size.X * _roomVerticalMaxDispersion)); } + else + { + offset = Utils.RandomRangeInt(-(int)(prevRoomInfo.Size.Y * _roomHorizontalMinDispersion), + (int)(prevRoomInfo.Size.Y * _roomHorizontalMaxDispersion)); + } + + //计算房间位置 + if (direction == 0) //上 + { + room.Position = new Vector2I(prevRoomInfo.Position.X + offset, + prevRoomInfo.Position.Y - room.Size.Y - space); + } + else if (direction == 1) //右 + { + room.Position = new Vector2I(prevRoomInfo.Position.X + prevRoomInfo.Size.Y + space, + prevRoomInfo.Position.Y + offset); + } + else if (direction == 2) //下 + { + room.Position = new Vector2I(prevRoomInfo.Position.X + offset, + prevRoomInfo.Position.Y + prevRoomInfo.Size.Y + space); + } + else if (direction == 3) //左 + { + room.Position = new Vector2I(prevRoomInfo.Position.X - room.Size.X - space, + prevRoomInfo.Position.Y + offset); + } + + //是否在限制区域内 + if (_enableLimitRange) + { + if (room.GetHorizontalStart() < -_rangeX || room.GetHorizontalEnd() > _rangeX || + room.GetVerticalStart() < -_rangeY || room.GetVerticalEnd() > _rangeY) + { + //超出区域, 直接跳出尝试的循环, 返回 null + resultRoom = null; + return GenerateRoomErrorCode.OutArea; + } + } + + //是否碰到其他房间或者过道 + if (_roomGrid.RectCollision(room.Position - new Vector2(3, 3), room.Size + new Vector2(6, 6))) + { + //碰到其他墙壁, 再一次尝试 + continue; + //return GenerateRoomErrorCode.HasCollision; + } + + _roomGrid.AddRect(room.Position, room.Size, true); + + //找门, 与上一个房间是否能连通 + if (!ConnectDoor(prevRoomInfo, room)) + { + _roomGrid.RemoveRect(room.Position, room.Size); + //房间过道没有连接上, 再一次尝试 + continue; + //return GenerateRoomErrorCode.NoProperDoor; + } + break; } - //是否碰到其他房间或者过道 - if (_roomGrid.RectCollision(room.Position - new Vector2(3, 3), room.Size + new Vector2(6, 6))) + //尝试次数用光了, 还没有找到合适的位置 + if (tryCount >= _maxTryCount) { resultRoom = null; - return GenerateRoomErrorCode.HasCollision; - } - - _roomGrid.AddRect(room.Position, room.Size, true); - - //找门, 与上一个房间是否能连通 - if (!ConnectDoor(prevRoomInfo, room)) - { - _roomGrid.RemoveRect(room.Position, room.Size); - resultRoom = null; - return GenerateRoomErrorCode.NoProperDoor; + return GenerateRoomErrorCode.NoSuitableLocation; } } diff --git a/DungeonShooting_Godot/src/framework/map/GenerateNavigationResult.cs b/DungeonShooting_Godot/src/framework/map/GenerateNavigationResult.cs new file mode 100644 index 0000000..9a6001c --- /dev/null +++ b/DungeonShooting_Godot/src/framework/map/GenerateNavigationResult.cs @@ -0,0 +1,22 @@ + +/// +/// 生成导航返回的结果 +/// +public class GenerateNavigationResult +{ + public GenerateNavigationResult(bool success, NavigationPointInterleavingException exception = null) + { + Success = success; + Exception = exception; + } + + /// + /// 是否成功 + /// + public bool Success; + + /// + /// 异常信息 + /// + public NavigationPointInterleavingException Exception; +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/NavigationPointInterleavingException.cs b/DungeonShooting_Godot/src/framework/map/NavigationPointInterleavingException.cs new file mode 100644 index 0000000..284683c --- /dev/null +++ b/DungeonShooting_Godot/src/framework/map/NavigationPointInterleavingException.cs @@ -0,0 +1,19 @@ + +using System; +using Godot; + +/// +/// 导航点交错异常 +/// +public class NavigationPointInterleavingException : Exception +{ + /// + /// 交错点 + /// + public Vector2 Point { get; } + + public NavigationPointInterleavingException(Vector2 point, string message): base(message) + { + Point = point; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/NavigationPolygonData.cs b/DungeonShooting_Godot/src/framework/map/NavigationPolygonData.cs new file mode 100644 index 0000000..f97f8ca --- /dev/null +++ b/DungeonShooting_Godot/src/framework/map/NavigationPolygonData.cs @@ -0,0 +1,71 @@ + +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Godot; + +public enum NavigationPolygonType +{ + /// + /// 外轮廓 + /// + Out, + /// + /// 内轮廓 + /// + In, +} + +/// +/// 描述导航多边形数据 +/// +public class NavigationPolygonData +{ + /// + /// 导航轮廓类型 + /// + [JsonInclude] public NavigationPolygonType Type; + + /// + /// 多边形的顶点 + /// + [JsonInclude] public List Points = new List(); + + /// + /// 将 Points 字段转为 Vector2[] 类型数据并返回 + /// + public Vector2[] ConvertPointsToVector2Array() + { + if (Points == null) + { + return null; + } + + var array = new Vector2[Points.Count]; + for (var i = 0; i < Points.Count; i++) + { + array[i] = Points[i].AsVector2(); + } + + return array; + } + + /// + /// 将 Points 字段转为 Vector2I[] 类型数据并返回 + /// + public Vector2I[] ConvertPointsToVector2IArray() + { + if (Points == null) + { + return null; + } + + var array = new Vector2I[Points.Count]; + for (var i = 0; i < Points.Count; i++) + { + array[i] = Points[i].AsVector2I(); + } + + return array; + } + +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/SerializeVector2.cs b/DungeonShooting_Godot/src/framework/map/SerializeVector2.cs deleted file mode 100644 index a48c54d..0000000 --- a/DungeonShooting_Godot/src/framework/map/SerializeVector2.cs +++ /dev/null @@ -1,38 +0,0 @@ - -using System.Text.Json.Serialization; -using Godot; - -/// -/// 可序列化的 Vector2 对象 -/// -public class SerializeVector2 -{ - public SerializeVector2(float x, float y) - { - X = x; - Y = y; - } - - public SerializeVector2(Vector2 v) - { - X = v.X; - Y = v.Y; - } - - public SerializeVector2(Vector2I v) - { - X = v.X; - Y = v.Y; - } - - public SerializeVector2() - { - - } - - - [JsonInclude] - public float X; - [JsonInclude] - public float Y; -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/map/TileCellInfo.cs b/DungeonShooting_Godot/src/framework/map/TileCellInfo.cs new file mode 100644 index 0000000..ad2fcb3 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/map/TileCellInfo.cs @@ -0,0 +1,24 @@ + +using Godot; + +/// +/// 地图cell属性信息 +/// +public class TileCellInfo +{ + public TileCellInfo(int id, Vector2I? autotileCoord) + { + Id = id; + AutotileCoord = autotileCoord; + } + + /// + /// 在TileSet中的图块id + /// + public int Id; + + /// + /// 如果是图块集, 该属性就表示在图块集的位置 + /// + public Vector2I? AutotileCoord; +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 9b908ac..c3df18e 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -59,17 +59,13 @@ /// /// 房间配置 /// - public readonly List RoomConfig; + public List RoomConfig { get; private set; } public GameApplication() { Instance = this; - - //加载房间配置信息 - var file = FileAccess.Open(ResourcePath.resource_map_RoomConfig_json, FileAccess.ModeFlags.Read); - var asText = file.GetAsText(); - RoomConfig = JsonSerializer.Deserialize>(asText); - file.Dispose(); + + InitRoomConfig(); //扫描并注册当前程序集下的武器 WeaponManager.RegisterWeaponFromAssembly(GetType().Assembly); @@ -120,4 +116,27 @@ //return viewPos; return (viewPos - GameCamera.Main.GlobalPosition + (GameConfig.ViewportSize / 2)) * GameConfig.WindowScale - GameCamera.Main.SubPixelPosition; } + + //初始化房间配置 + private void InitRoomConfig() + { + //加载房间配置信息 + var file = FileAccess.Open(ResourcePath.resource_map_RoomConfig_json, FileAccess.ModeFlags.Read); + var asText = file.GetAsText(); + RoomConfig = JsonSerializer.Deserialize>(asText); + file.Dispose(); + + //需要处理 DoorAreaInfos 长度为 0 的房间, 并为其配置默认值 + foreach (var roomSplit in RoomConfig) + { + var areaInfos = roomSplit.RoomInfo.DoorAreaInfos; + if (areaInfos.Count == 0) + { + areaInfos.Add(new DoorAreaInfo(DoorDirection.N, GenerateDungeon.TileCellSize, (roomSplit.RoomInfo.Size.X - 2) * GenerateDungeon.TileCellSize)); + areaInfos.Add(new DoorAreaInfo(DoorDirection.S, GenerateDungeon.TileCellSize, (roomSplit.RoomInfo.Size.X - 2) * GenerateDungeon.TileCellSize)); + areaInfos.Add(new DoorAreaInfo(DoorDirection.W, GenerateDungeon.TileCellSize, (roomSplit.RoomInfo.Size.Y - 2) * GenerateDungeon.TileCellSize)); + areaInfos.Add(new DoorAreaInfo(DoorDirection.E, GenerateDungeon.TileCellSize, (roomSplit.RoomInfo.Size.Y - 2) * GenerateDungeon.TileCellSize)); + } + } + } } diff --git a/DungeonShooting_Godot/src/game/role/Player.cs b/DungeonShooting_Godot/src/game/role/Player.cs index f73b193..7e122e5 100644 --- a/DungeonShooting_Godot/src/game/role/Player.cs +++ b/DungeonShooting_Godot/src/game/role/Player.cs @@ -55,6 +55,7 @@ // MoveSpeed = 500; // CollisionLayer = 0; // CollisionMask = 0; + // GameCamera.Main.Zoom = new Vector2(0.5f, 0.5f); } protected override void Process(float delta) diff --git a/DungeonShooting_Godot/src/game/room/AutoTileConfig.cs b/DungeonShooting_Godot/src/game/room/AutoTileConfig.cs index 9e12343..fc19a71 100644 --- a/DungeonShooting_Godot/src/game/room/AutoTileConfig.cs +++ b/DungeonShooting_Godot/src/game/room/AutoTileConfig.cs @@ -14,7 +14,7 @@ public TileCellInfo L = new TileCellInfo(0, new Vector2I(3, 3)); public TileCellInfo T = new TileCellInfo(0, new Vector2I(2, 7)); public TileCellInfo B = new TileCellInfo(0, new Vector2I(2, 2)); - public TileCellInfo Ground = new TileCellInfo(0, new Vector2I(0, 8)); + public TileCellInfo Floor = new TileCellInfo(0, new Vector2I(0, 8)); public TileCellInfo OUT_LT = new TileCellInfo(0, new Vector2I(1, 2)); public TileCellInfo OUT_LB = new TileCellInfo(0, new Vector2I(1, 7)); diff --git a/DungeonShooting_Godot/src/game/room/DungeonTile.cs b/DungeonShooting_Godot/src/game/room/DungeonTile.cs deleted file mode 100644 index cc2f061..0000000 --- a/DungeonShooting_Godot/src/game/room/DungeonTile.cs +++ /dev/null @@ -1,992 +0,0 @@ - -using System; -using System.Collections.Generic; -using Godot; - -/// -/// 地牢地砖管理类, 提供一些操作 TileMap 和计算导航的接口 -/// -public class DungeonTile -{ - /// - /// TileMap 底板的层级 - /// - public const int FloorMapLayer = 0; - /// - /// TileMap 中层的层级 - /// - public const int MiddleMapLayer = 1; - /// - /// TileMap 上层的层级 - /// - public const int TopMapLayer = 2; - - /// - /// 配置层级的自定义数据名称 - /// - public const string CustomTileLayerName = "TileLayer"; - - //--------------------- 导航 ------------------------- - - //已经标记过的点 - private readonly HashSet _usePoints = new HashSet(); - - //导航区域数据 - private readonly List _polygonDataList = new List(); - - //---------------------------------------------------- - - private TileMap _tileRoot; - - public DungeonTile(TileMap tileRoot) - { - _tileRoot = tileRoot; - } - - /// - /// 根据 roomInfo 和 config 数据自动填充 tileMap 参数中的地图数据 - /// - public void AutoFillRoomTile(AutoTileConfig config, RoomInfo roomInfo) - { - foreach (var info in roomInfo.Next) - { - AutoFillRoomTile(config, info); - } - - //铺房间 - if (roomInfo.RoomSplit == null) - { - FillRect(FloorMapLayer, config.Ground, roomInfo.Position + Vector2.One, - roomInfo.Size - new Vector2(2, 2)); - - FillRect(TopMapLayer, config.IN_LT, roomInfo.Position, Vector2.One); - FillRect(TopMapLayer, config.L, roomInfo.Position + new Vector2(0, 1), - new Vector2(1, roomInfo.Size.Y - 2)); - FillRect(TopMapLayer, config.IN_LB, roomInfo.Position + new Vector2(0, roomInfo.Size.Y - 1), - new Vector2(1, 1)); - FillRect(TopMapLayer, config.B, roomInfo.Position + new Vector2(1, roomInfo.Size.Y - 1), - new Vector2(roomInfo.Size.X - 2, 1)); - FillRect(TopMapLayer, config.IN_RB, - roomInfo.Position + new Vector2(roomInfo.Size.X - 1, roomInfo.Size.Y - 1), - Vector2.One); - FillRect(TopMapLayer, config.R, roomInfo.Position + new Vector2(roomInfo.Size.X - 1, 1), - new Vector2(1, roomInfo.Size.Y - 2)); - FillRect(TopMapLayer, config.IN_RT, roomInfo.Position + new Vector2(roomInfo.Size.X - 1, 0), - Vector2.One); - FillRect(MiddleMapLayer, config.T, roomInfo.Position + Vector2.Right, - new Vector2(roomInfo.Size.X - 2, 1)); - } - else - { - var rectSize = roomInfo.RoomSplit.RoomInfo.Size; - var rectPos = roomInfo.RoomSplit.RoomInfo.Position; - var template = ResourceManager.Load(roomInfo.RoomSplit.ScenePath); - var tileInstance = template.Instantiate(); - for (int i = 0; i < rectSize.X; i++) - { - for (int j = 0; j < rectSize.Y; j++) - { - var coords = new Vector2I((int)(rectPos.X + i), (int)(rectPos.Y + j)); - var atlasCoords = tileInstance.GetCellAtlasCoords(0, coords); - if (atlasCoords.X != -1 && atlasCoords.Y != -1) - { - //获取自定义层级 - var layer = tileInstance.GetCellTileData(0, coords).GetCustomData(CustomTileLayerName) - .AsInt32(); - layer = Mathf.Clamp(layer, FloorMapLayer, TopMapLayer); - _tileRoot.SetCell(layer, new Vector2I(roomInfo.Position.X + i, roomInfo.Position.Y + j), - 1, atlasCoords); - } - } - } - - tileInstance.QueueFree(); - } - - //铺过道 - foreach (var doorInfo in roomInfo.Doors) - { - if (doorInfo.ConnectRoom.Id > roomInfo.Id) - { - //普通的直线连接 - var doorDir1 = doorInfo.Direction; - var doorDir2 = doorInfo.ConnectDoor.Direction; - if (!doorInfo.HasCross) - { - //方向, 0横向, 1纵向 - int dir = 0; - var rect = Utils.CalcRect( - doorInfo.OriginPosition.X, - doorInfo.OriginPosition.Y, - doorInfo.ConnectDoor.OriginPosition.X, - doorInfo.ConnectDoor.OriginPosition.Y - ); - if (doorDir1 == DoorDirection.N || doorDir1 == DoorDirection.S) - { - rect.Size = new Vector2(GenerateDungeon.CorridorWidth, rect.Size.Y); - dir = 1; - } - else - { - rect.Size = new Vector2(rect.Size.X, GenerateDungeon.CorridorWidth); - } - - if (dir == 0) //横向 - { - FullHorizontalGalleryWall(config, rect); - } - else //纵向 - { - FullVerticalGalleryWall(config, rect); - } - } - else //带交叉点 - { - //方向, 0横向, 1纵向 - int dir1 = 0; - int dir2 = 0; - - Rect2 rect; - Rect2 rect2; - - //计算范围 - switch (doorDir1) - { - case DoorDirection.E: //→ - rect = new Rect2( - doorInfo.OriginPosition.X, - doorInfo.OriginPosition.Y, - doorInfo.Cross.X - doorInfo.OriginPosition.X, - GenerateDungeon.CorridorWidth - ); - break; - case DoorDirection.W: //← - rect = new Rect2( - doorInfo.Cross.X + GenerateDungeon.CorridorWidth, - doorInfo.Cross.Y, - doorInfo.OriginPosition.X - (doorInfo.Cross.X + GenerateDungeon.CorridorWidth), - GenerateDungeon.CorridorWidth - ); - break; - case DoorDirection.S: //↓ - dir1 = 1; - rect = new Rect2( - doorInfo.OriginPosition.X, - doorInfo.OriginPosition.Y, - GenerateDungeon.CorridorWidth, - doorInfo.Cross.Y - doorInfo.OriginPosition.Y - ); - break; - case DoorDirection.N: //↑ - dir1 = 1; - rect = new Rect2( - doorInfo.Cross.X, - doorInfo.Cross.Y + GenerateDungeon.CorridorWidth, - GenerateDungeon.CorridorWidth, - doorInfo.OriginPosition.Y - (doorInfo.Cross.Y + GenerateDungeon.CorridorWidth) - ); - break; - default: - rect = new Rect2(); - break; - } - - switch (doorDir2) - { - case DoorDirection.E: //→ - rect2 = new Rect2( - doorInfo.ConnectDoor.OriginPosition.X, - doorInfo.ConnectDoor.OriginPosition.Y, - doorInfo.Cross.X - doorInfo.ConnectDoor.OriginPosition.X, - GenerateDungeon.CorridorWidth - ); - break; - case DoorDirection.W: //← - rect2 = new Rect2( - doorInfo.Cross.X + GenerateDungeon.CorridorWidth, - doorInfo.Cross.Y, - doorInfo.ConnectDoor.OriginPosition.X - - (doorInfo.Cross.X + GenerateDungeon.CorridorWidth), - GenerateDungeon.CorridorWidth - ); - break; - case DoorDirection.S: //↓ - dir2 = 1; - rect2 = new Rect2( - doorInfo.ConnectDoor.OriginPosition.X, - doorInfo.ConnectDoor.OriginPosition.Y, - GenerateDungeon.CorridorWidth, - doorInfo.Cross.Y - doorInfo.ConnectDoor.OriginPosition.Y - ); - break; - case DoorDirection.N: //↑ - dir2 = 1; - rect2 = new Rect2( - doorInfo.Cross.X, - doorInfo.Cross.Y + GenerateDungeon.CorridorWidth, - GenerateDungeon.CorridorWidth, - doorInfo.ConnectDoor.OriginPosition.Y - - (doorInfo.Cross.Y + GenerateDungeon.CorridorWidth) - ); - break; - default: - rect2 = new Rect2(); - break; - } - - FillRect(FloorMapLayer, config.Ground, doorInfo.Cross + Vector2.One, - new Vector2(GenerateDungeon.CorridorWidth - 2, GenerateDungeon.CorridorWidth - 2)); - - //墙壁 - if (dir1 == 0) - { - FullHorizontalGalleryWall(config, rect); - } - else - { - FullVerticalGalleryWall(config, rect); - } - - if (dir2 == 0) - { - FullHorizontalGalleryWall(config, rect2); - } - else - { - FullVerticalGalleryWall(config, rect2); - } - - if ((doorDir1 == DoorDirection.N && doorDir2 == DoorDirection.E) || //↑→ - (doorDir2 == DoorDirection.N && doorDir1 == DoorDirection.E)) - { - FillRect(TopMapLayer, config.OUT_RT, - doorInfo.Cross + new Vector2(0, GenerateDungeon.CorridorWidth - 1), - Vector2.One); - FillRect(TopMapLayer, config.IN_RT, doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 0), - Vector2.One); - FillRect(MiddleMapLayer, config.T, doorInfo.Cross, new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); - FillRect(TopMapLayer, config.R, doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 1), - new Vector2(1, GenerateDungeon.CorridorWidth - 1)); - } - else if ((doorDir1 == DoorDirection.E && doorDir2 == DoorDirection.S) || //→↓ - (doorDir2 == DoorDirection.E && doorDir1 == DoorDirection.S)) - { - FillRect(MiddleMapLayer, config.OUT_RB, doorInfo.Cross, Vector2.One); - FillRect(TopMapLayer, config.IN_RB, - doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, - GenerateDungeon.CorridorWidth - 1), - Vector2.One); - FillRect(TopMapLayer, config.R, doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 0), - new Vector2(1, GenerateDungeon.CorridorWidth - 1)); - FillRect(TopMapLayer, config.B, doorInfo.Cross + new Vector2(0, GenerateDungeon.CorridorWidth - 1), - new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); - } - else if ((doorDir1 == DoorDirection.S && doorDir2 == DoorDirection.W) || //↓← - (doorDir2 == DoorDirection.S && doorDir1 == DoorDirection.W)) - { - FillRect(MiddleMapLayer, config.OUT_LB, - doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, 0), Vector2.One); - FillRect(TopMapLayer, config.IN_LB, doorInfo.Cross + new Vector2(0, GenerateDungeon.CorridorWidth - 1), - Vector2.One); - FillRect(TopMapLayer, config.L, doorInfo.Cross, new Vector2(1, GenerateDungeon.CorridorWidth - 1)); - FillRect(TopMapLayer, config.B, doorInfo.Cross + new Vector2(1, GenerateDungeon.CorridorWidth - 1), - new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); - } - else if ((doorDir1 == DoorDirection.W && doorDir2 == DoorDirection.N) || //←↑ - (doorDir2 == DoorDirection.W && doorDir1 == DoorDirection.N)) - { - FillRect(TopMapLayer, config.OUT_LT, - doorInfo.Cross + new Vector2(GenerateDungeon.CorridorWidth - 1, - GenerateDungeon.CorridorWidth - 1), - Vector2.One); - FillRect(TopMapLayer, config.IN_LT, doorInfo.Cross, Vector2.One); - FillRect(MiddleMapLayer, config.T, doorInfo.Cross + new Vector2(1, 0), - new Vector2(GenerateDungeon.CorridorWidth - 1, 1)); - FillRect(TopMapLayer, config.L, doorInfo.Cross + new Vector2(0, 1), - new Vector2(1, GenerateDungeon.CorridorWidth - 1)); - } - - //在房间墙上开洞 - switch (doorDir1) - { - case DoorDirection.E: //→ - ClearRect(TopMapLayer, doorInfo.OriginPosition + new Vector2(-1, 1), - new Vector2(1, rect.Size.Y - 2)); - FillRect(FloorMapLayer, config.Ground, doorInfo.OriginPosition + new Vector2(-1, 1), - new Vector2(1, rect.Size.Y - 2)); - break; - case DoorDirection.W: //← - ClearRect(TopMapLayer, doorInfo.OriginPosition + new Vector2(0, 1), - new Vector2(1, rect.Size.Y - 2)); - FillRect(FloorMapLayer, config.Ground, doorInfo.OriginPosition + new Vector2(0, 1), - new Vector2(1, rect.Size.Y - 2)); - break; - case DoorDirection.S: //↓ - ClearRect(TopMapLayer, doorInfo.OriginPosition + new Vector2(1, -1), - new Vector2(rect.Size.X - 2, 1)); - FillRect(FloorMapLayer, config.Ground, doorInfo.OriginPosition + new Vector2(1, -1), - new Vector2(rect.Size.X - 2, 1)); - break; - case DoorDirection.N: //↑ - ClearRect(MiddleMapLayer, doorInfo.OriginPosition + new Vector2(1, 2), - new Vector2(rect.Size.X - 2, 1)); - FillRect(FloorMapLayer, config.Ground, doorInfo.OriginPosition + new Vector2(1, 0), - new Vector2(rect.Size.X - 2, 1)); - break; - } - - switch (doorDir2) - { - case DoorDirection.E: //→ - ClearRect(TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(-1, 1), - new Vector2(1, rect2.Size.Y - 2)); - FillRect(FloorMapLayer, config.Ground, doorInfo.ConnectDoor.OriginPosition + new Vector2(-1, 1), - new Vector2(1, rect2.Size.Y - 2)); - break; - case DoorDirection.W: //← - ClearRect(TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(0, 1), - new Vector2(1, rect2.Size.Y - 2)); - FillRect(FloorMapLayer, config.Ground, doorInfo.ConnectDoor.OriginPosition + new Vector2(0, 1), - new Vector2(1, rect2.Size.Y - 2)); - break; - case DoorDirection.S: //↓ - ClearRect(TopMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, -1), - new Vector2(rect2.Size.X - 2, 1)); - FillRect(FloorMapLayer, config.Ground, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, -1), - new Vector2(rect2.Size.X - 2, 1)); - break; - case DoorDirection.N: //↑ - ClearRect(MiddleMapLayer, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, 0), - new Vector2(rect2.Size.X - 2, 1)); - FillRect(FloorMapLayer, config.Ground, doorInfo.ConnectDoor.OriginPosition + new Vector2(1, 0), - new Vector2(rect2.Size.X - 2, 1)); - break; - } - } - } - } - } - - //填充tile区域 - private void FillRect(int layer, TileCellInfo info, Vector2 pos, Vector2 size) - { - for (int i = 0; i < size.X; i++) - { - for (int j = 0; j < size.Y; j++) - { - _tileRoot.SetCell(layer, new Vector2I((int)pos.X + i, (int)pos.Y + j), 1, info.AutotileCoord); - } - } - } - - //清除tile区域 - private void ClearRect(int layer, Vector2 pos, Vector2 size) - { - for (int i = 0; i < size.X; i++) - { - for (int j = 0; j < size.Y; j++) - { - //tileMap.SetCell((int)pos.X + i, (int)pos.Y + j, -1); - _tileRoot.SetCell(layer, new Vector2I((int)pos.X + i, (int)pos.Y + j), -1); - } - } - } - - private void FullHorizontalGalleryWall(AutoTileConfig config, Rect2 rect) - { - FillRect(FloorMapLayer, config.Ground, rect.Position + new Vector2(0, 1), rect.Size - new Vector2(0, 2)); - FillRect(MiddleMapLayer, config.T, rect.Position, new Vector2(rect.Size.X, 1)); - FillRect(TopMapLayer, config.B, rect.Position + new Vector2(0, rect.Size.Y - 1), new Vector2(rect.Size.X, 1)); - //左 - ClearRect(TopMapLayer, rect.Position + new Vector2(-1, 1), new Vector2(1, rect.Size.Y - 2)); - FillRect(FloorMapLayer, config.Ground, rect.Position + new Vector2(-1, 1), new Vector2(1, rect.Size.Y - 2)); - //右 - ClearRect(TopMapLayer, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2)); - FillRect(FloorMapLayer, config.Ground, rect.Position + new Vector2(rect.Size.X, 1), new Vector2(1, rect.Size.Y - 2)); - } - - private void FullVerticalGalleryWall(AutoTileConfig config, Rect2 rect) - { - FillRect(FloorMapLayer, config.Ground, rect.Position + new Vector2(1, 0), rect.Size - new Vector2(2, 0)); - FillRect(TopMapLayer, config.L, rect.Position, new Vector2(1, rect.Size.Y)); - FillRect(TopMapLayer, config.R, rect.Position + new Vector2(rect.Size.X - 1, 0), new Vector2(1, rect.Size.Y)); - //上 - ClearRect(TopMapLayer, rect.Position + new Vector2(1, -1), new Vector2(rect.Size.X - 2, 1)); - FillRect(FloorMapLayer, config.Ground, rect.Position + new Vector2(1, -1), new Vector2(rect.Size.X - 2, 1)); - //下 - ClearRect(MiddleMapLayer, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1)); - FillRect(FloorMapLayer, config.Ground, rect.Position + new Vector2(1, rect.Size.Y), new Vector2(rect.Size.X - 2, 1)); - } - - /// - /// 计算网格区域, 并且赋值给 navigationPolygon - /// - public void GenerateNavigationPolygon(NavigationRegion2D navigationPolygon) - { - GenerateNavigationPolygon(); - var polygon = new NavigationPolygon(); - foreach (var polygonData in _polygonDataList) - { - polygon.AddOutline(polygonData.Points.ToArray()); - } - polygon.MakePolygonsFromOutlines(); - navigationPolygon.NavigationPolygon = polygon; - } - - /// - /// 获取导航点数据 - /// - public NavigationPolygonData[] GetPolygonData() - { - return _polygonDataList.ToArray(); - } - - /// - /// 返回指定位置的Tile是否为可以行走 - /// - public bool IsWayTile(int x, int y) - { - return _tileRoot.GetCellTileData(DungeonTile.FloorMapLayer, new Vector2I(x, y)) != null; - } - - /// - /// 返回指定坐标下对应的Tile是否为可以行走 - /// - public bool IsWayPosition(float x, float y) - { - var tileMapCellSize = _tileRoot.CellQuadrantSize; - return IsWayTile((int)(x / tileMapCellSize), (int)(y / tileMapCellSize)); - } - - /// - /// 自动生成导航区域 - /// - private void GenerateNavigationPolygon() - { - var size = new Vector2(_tileRoot.CellQuadrantSize, _tileRoot.CellQuadrantSize); - - var rect = _tileRoot.GetUsedRect(); - - var x = rect.Position.X; - var y = rect.Position.Y; - var w = rect.Size.X; - var h = rect.Size.Y; - - for (int j = y; j < h; j++) - { - for (int i = x; i < w; i++) - { - if (IsWayTile(i, j)) - { - if (!_usePoints.Contains(new Vector2(i, j))) - { - NavigationPolygonData polygonData = null; - - if (!IsWayTile(i, j - 1)) - { - polygonData = CalcOutline(i, j, _tileRoot, size); - } - else if (!IsWayTile(i, j + 1)) - { - polygonData = CalcInline(i, j, _tileRoot, size); - } - - if (polygonData != null) - { - _polygonDataList.Add(polygonData); - } - } - } - } - } - } - - //计算导航网格外轮廓 - private NavigationPolygonData CalcOutline(int i, int j, TileMap tileMap, Vector2 size) - { - var polygonData = new NavigationPolygonData(); - polygonData.Type = NavigationPolygonType.Out; - var points = polygonData.Points; - // 0:右, 1:下, 2:左, 3:上 - var dir = 0; - var offset = new Vector2(size.X * 0.5f, size.Y * 0.5f); - //找到路, 向右开始找边界 - var startPos = new Vector2(i, j); - - var tempI = i; - var tempJ = j; - - while (true) - { - switch (dir) - { - case 0: //右 - { - if (IsWayTile(tempI, tempJ - 1)) //先向上找 - { - dir = 3; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ--; - break; - } - else if (IsWayTile(tempI + 1, tempJ)) //再向右找 - { - if (points.Count == 0) - { - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempI++; - break; - } - else if (IsWayTile(tempI, tempJ + 1)) //向下找 - { - dir = 1; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ++; - break; - } - - return null; - } - case 1: //下 - { - if (IsWayTile(tempI + 1, tempJ)) //先向右找 - { - dir = 0; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI++; - break; - } - else if (IsWayTile(tempI, tempJ + 1)) //再向下找 - { - if (points.Count == 0) - { - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempJ++; - break; - } - else if (IsWayTile(tempI - 1, tempJ)) //向左找 - { - dir = 2; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI--; - break; - } - - return null; - } - case 2: //左 - { - if (IsWayTile(tempI, tempJ + 1)) //先向下找 - { - dir = 1; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ++; - break; - } - else if (IsWayTile(tempI - 1, tempJ)) //再向左找 - { - if (points.Count == 0) - { - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempI--; - break; - } - else if (IsWayTile(tempI, tempJ - 1)) //向上找 - { - dir = 3; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ--; - break; - } - - return null; - } - case 3: //上 - { - if (IsWayTile(tempI - 1, tempJ)) //先向左找 - { - dir = 2; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI--; - break; - } - else if (IsWayTile(tempI, tempJ - 1)) //再向上找 - { - if (points.Count == 0) - { - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempJ--; - break; - } - else if (IsWayTile(tempI + 1, tempJ)) //向右找 - { - dir = 0; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI++; - break; - } - - return null; - } - } - } - } - - //计算导航网格内轮廓 - private NavigationPolygonData CalcInline(int i, int j, TileMap tileMap, Vector2 size) - { - var polygonData = new NavigationPolygonData(); - polygonData.Type = NavigationPolygonType.In; - var points = polygonData.Points; - // 0:右, 1:下, 2:左, 3:上 - var dir = 0; - var offset = new Vector2(size.X * 0.5f, size.Y * 0.5f); - //找到路, 向右开始找边界 - var startPos = new Vector2(i - 1, j); - - var tempI = i; - var tempJ = j; - - while (true) - { - switch (dir) - { - case 0: //右 - { - if (IsWayTile(tempI, tempJ + 1)) //向下找 - { - dir = 1; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ++; - break; - } - else if (IsWayTile(tempI + 1, tempJ)) //再向右找 - { - if (points.Count == 0) - { - points.Add(new Vector2((tempI - 1) * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempI++; - break; - } - else if (IsWayTile(tempI, tempJ - 1)) //先向上找 - { - dir = 3; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ--; - break; - } - - return null; - } - case 1: //下 - { - if (IsWayTile(tempI - 1, tempJ)) //向左找 - { - dir = 2; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI--; - break; - } - else if (IsWayTile(tempI, tempJ + 1)) //再向下找 - { - if (points.Count == 0) - { - points.Add(new Vector2((tempI - 1) * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempJ++; - break; - } - else if (IsWayTile(tempI + 1, tempJ)) //先向右找 - { - dir = 0; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI++; - break; - } - - return null; - } - case 2: //左 - { - if (IsWayTile(tempI, tempJ - 1)) //向上找 - { - dir = 3; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ--; - break; - } - else if (IsWayTile(tempI - 1, tempJ)) //再向左找 - { - if (points.Count == 0) - { - points.Add(new Vector2((tempI - 1) * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempI--; - break; - } - else if (IsWayTile(tempI, tempJ + 1)) //先向下找 - { - dir = 1; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempJ++; - break; - } - - return null; - } - case 3: //上 - { - if (IsWayTile(tempI + 1, tempJ)) //向右找 - { - dir = 0; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI++; - break; - } - else if (IsWayTile(tempI, tempJ - 1)) //再向上找 - { - if (points.Count == 0) - { - points.Add(new Vector2((tempI - 1) * size.X, tempJ * size.Y) + offset); - } - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - PutUsePoint(new Vector2(tempI, tempJ)); - tempJ--; - break; - } - else if (IsWayTile(tempI - 1, tempJ)) //先向左找 - { - dir = 2; - - var pos = new Vector2(tempI, tempJ); - if (points.Count > 1 && pos == startPos) - { - return polygonData; - } - - points.Add(new Vector2(tempI * size.X, tempJ * size.Y) + offset); - PutUsePoint(pos); - - tempI--; - break; - } - - return null; - } - } - } - } - - //记录导航网格中已经使用过的坐标 - private void PutUsePoint(Vector2 pos) - { - if (_usePoints.Contains(pos)) - { - throw new Exception("生成导航多边形发生错误! 点: " + pos + "发生交错!"); - } - - _usePoints.Add(pos); - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/room/NavigationPolygonData.cs b/DungeonShooting_Godot/src/game/room/NavigationPolygonData.cs deleted file mode 100644 index 7d7170b..0000000 --- a/DungeonShooting_Godot/src/game/room/NavigationPolygonData.cs +++ /dev/null @@ -1,30 +0,0 @@ - -using System.Collections.Generic; -using Godot; - -public enum NavigationPolygonType -{ - /// - /// 外轮廓 - /// - Out, - /// - /// 内轮廓 - /// - In, -} - -/// -/// 描述导航多边形数据 -/// -public class NavigationPolygonData -{ - /// - /// 导航轮廓类型 - /// - public NavigationPolygonType Type; - /// - /// 多边形的顶点 - /// - public List Points = new List(); -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/room/RoomManager.cs b/DungeonShooting_Godot/src/game/room/RoomManager.cs index cebe220..6a9e47b 100644 --- a/DungeonShooting_Godot/src/game/room/RoomManager.cs +++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs @@ -27,24 +27,18 @@ /// 玩家对象 /// public Player Player { get; private set; } - - /// - /// 导航区域形状 - /// - public NavigationRegion2D NavigationPolygon { get; private set; } - - + private DungeonTile _dungeonTile; private AutoTileConfig _autoTileConfig; private Font _font; private GenerateDungeon _generateDungeon; + //房间内所有静态导航网格数据 + private static List _roomStaticNavigationList = new List(); + public override void _EnterTree() { - NavigationPolygon = new NavigationRegion2D(); - AddChild(NavigationPolygon); - //创建玩家 Player = new Player(); Player.Position = new Vector2(30, 30); @@ -59,6 +53,7 @@ _font = ResourceManager.Load(ResourcePath.resource_font_cn_font_36_tres); + var nowTicks = DateTime.Now.Ticks; //生成地牢房间 _generateDungeon = new GenerateDungeon(); _generateDungeon.Generate(); @@ -67,13 +62,17 @@ _autoTileConfig = new AutoTileConfig(); _dungeonTile = new DungeonTile(TileRoot); _dungeonTile.AutoFillRoomTile(_autoTileConfig, _generateDungeon.StartRoom); - - //根据房间数据创建填充 tiled - var nowTicks = DateTime.Now.Ticks; //生成寻路网格 - _dungeonTile.GenerateNavigationPolygon(NavigationPolygon); - GD.Print("计算NavigationPolygon用时: " + (DateTime.Now.Ticks - nowTicks) / 10000 + "毫秒"); + _dungeonTile.GenerateNavigationPolygon(DungeonTile.AisleFloorMapLayer); + //挂载导航区域 + _dungeonTile.MountNavigationPolygon(this); + _roomStaticNavigationList.AddRange(_dungeonTile.GetPolygonData()); + _roomStaticNavigationList.AddRange(_dungeonTile.GetConnectDoorPolygonData()); + //挂载所有导航区域 + _generateDungeon.EachRoom(MountNavFromRoomInfo); + + GD.Print("生成地牢用时: " + (DateTime.Now.Ticks - nowTicks) / 10000 + "毫秒"); //播放bgm SoundManager.PlayMusic(ResourcePath.resource_sound_bgm_Intro_ogg, -17f); @@ -84,7 +83,7 @@ Player.PickUpWeapon(WeaponManager.GetGun("1003")); var enemy1 = new Enemy(); - enemy1.PutDown(new Vector2(150, 150), RoomLayerEnum.YSortLayer); + enemy1.PutDown(new Vector2(160, 160), RoomLayerEnum.YSortLayer); enemy1.PickUpWeapon(WeaponManager.GetGun("1001")); // for (int i = 0; i < 10; i++) @@ -157,20 +156,46 @@ { if (_dungeonTile != null) { + // DrawLine(new Vector2(0, -5000), new Vector2(0, 5000), Colors.Green); + // DrawLine(new Vector2(-5000, 0), new Vector2(5000, 0), Colors.Green); + //绘制ai寻路区域 - foreach (var item in _dungeonTile.GetPolygonData()) - { - if (item.Points.Count >= 2) - { - DrawPolyline(item.Points.Concat(new []{ item.Points[0] }).ToArray(), Colors.Red); - } - } + Utils.DrawNavigationPolygon(this, _roomStaticNavigationList.ToArray()); } //绘制房间区域 - DrawRoomInfo(_generateDungeon.StartRoom); + //DrawRoomInfo(_generateDungeon.StartRoom); } } + private void MountNavFromRoomInfo(RoomInfo roomInfo) + { + var polygonArray = roomInfo.RoomSplit.RoomInfo.NavigationList.ToArray(); + var polygon = new NavigationPolygon(); + for (var i = 0; i < polygonArray.Length; i++) + { + var navigationPolygonData = polygonArray[i]; + var polygonPointArray = navigationPolygonData.ConvertPointsToVector2Array(); + //这里的位置需要加上房间位置 + for (var j = 0; j < polygonPointArray.Length; j++) + { + polygonPointArray[j] = polygonPointArray[j] + (roomInfo.Position + Vector2I.One) * GenerateDungeon.TileCellSize; + } + polygon.AddOutline(polygonPointArray); + + //存入汇总列表 + _roomStaticNavigationList.Add(new NavigationPolygonData() + { + Type = navigationPolygonData.Type, + Points = polygonPointArray.Select(point => new SerializeVector2(point)).ToList(), + }); + } + polygon.MakePolygonsFromOutlines(); + var navigationPolygon = new NavigationRegion2D(); + navigationPolygon.Name = "NavigationRegion" + (GetChildCount() + 1); + navigationPolygon.NavigationPolygon = polygon; + AddChild(navigationPolygon); + } + //绘制房间区域, debug 用 private void DrawRoomInfo(RoomInfo room) { diff --git a/DungeonShooting_Godot/src/game/room/TileCellInfo.cs b/DungeonShooting_Godot/src/game/room/TileCellInfo.cs deleted file mode 100644 index ad2fcb3..0000000 --- a/DungeonShooting_Godot/src/game/room/TileCellInfo.cs +++ /dev/null @@ -1,24 +0,0 @@ - -using Godot; - -/// -/// 地图cell属性信息 -/// -public class TileCellInfo -{ - public TileCellInfo(int id, Vector2I? autotileCoord) - { - Id = id; - AutotileCoord = autotileCoord; - } - - /// - /// 在TileSet中的图块id - /// - public int Id; - - /// - /// 如果是图块集, 该属性就表示在图块集的位置 - /// - public Vector2I? AutotileCoord; -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/test/TestNavigation2.cs b/DungeonShooting_Godot/src/test/TestNavigation2.cs index 7e597c1..c98ff85 100644 --- a/DungeonShooting_Godot/src/test/TestNavigation2.cs +++ b/DungeonShooting_Godot/src/test/TestNavigation2.cs @@ -26,7 +26,7 @@ } var pos = _navigationAgent2D.GetNextPathPosition(); - _enemy.GlobalPosition = _enemy.GlobalPosition.MoveToward(pos, 100 * (float)delta); + _enemy.GlobalPosition = _enemy.GlobalPosition.MoveToward(pos, 400 * (float)delta); } diff --git a/README.md b/README.md index f5bca16..0f95428 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ 目前项目已经从Godot3x迁移至Godot4x
-当前Godot版本: 4.0rc6, 请使用指定的Godot版打本开项目 +当前Godot版本: Godot_v4.0-stable, 请使用指定的Godot版打本开项目 游戏名称: 待定
美术风格: 2D像素