diff --git a/DungeonShooting_Godot/prefab/role/Player.tscn b/DungeonShooting_Godot/prefab/role/Player.tscn index c107fcc..31fab4d 100644 --- a/DungeonShooting_Godot/prefab/role/Player.tscn +++ b/DungeonShooting_Godot/prefab/role/Player.tscn @@ -86,8 +86,6 @@ radius = 4.0 [node name="Player" instance=ExtResource( 1 )] -CollisionLayer = 8 -CollisionMask = 25 [node name="ShadowSprite" parent="." index="0"] material = SubResource( 1 ) diff --git a/DungeonShooting_Godot/scene/Main.tscn b/DungeonShooting_Godot/scene/Main.tscn index ae52483..e6534d4 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/ViewportContainer/Viewport/Room") ViewportPath = NodePath("ViewCanvas/ViewportContainer/Viewport") diff --git a/DungeonShooting_Godot/scene/Room.tscn b/DungeonShooting_Godot/scene/Room.tscn index eb4d09d..6e7e1c9 100644 --- a/DungeonShooting_Godot/scene/Room.tscn +++ b/DungeonShooting_Godot/scene/Room.tscn @@ -1,5 +1,6 @@ -[gd_scene load_steps=4 format=2] +[gd_scene load_steps=6 format=2] +[ext_resource path="res://resource/sprite/environment/itch-io-DungeonTileset4/16x16 dungeon ii wall reconfig v04 spritesheet.png" type="Texture" id=1] [ext_resource path="res://src/game/room/RoomManager.cs" type="Script" id=3] [ext_resource path="res://src/game/camera/GameCamera.cs" type="Script" id=5] @@ -7,6 +8,29 @@ background_mode = 4 glow_enabled = true +[sub_resource type="TileSet" id=2] +0/name = "16x16 dungeon ii wall reconfig v04 spritesheet.png 0" +0/texture = ExtResource( 1 ) +0/tex_offset = Vector2( 0, 0 ) +0/modulate = Color( 1, 1, 1, 1 ) +0/region = Rect2( 0, 0, 64, 144 ) +0/tile_mode = 2 +0/autotile/icon_coordinate = Vector2( 0, 8 ) +0/autotile/tile_size = Vector2( 16, 16 ) +0/autotile/spacing = 0 +0/autotile/occluder_map = [ ] +0/autotile/navpoly_map = [ ] +0/autotile/priority_map = [ ] +0/autotile/z_index_map = [ ] +0/occluder_offset = Vector2( 0, 0 ) +0/navigation_offset = Vector2( 0, 0 ) +0/shape_offset = Vector2( 0, 0 ) +0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +0/shape_one_way = false +0/shape_one_way_margin = 0.0 +0/shapes = [ ] +0/z_index = 0 + [node name="Room" type="Navigation2D"] script = ExtResource( 3 ) ObjectRootPath = NodePath("ObjectRoot") @@ -44,6 +68,8 @@ [node name="FloorTileMap" type="TileMap" parent="SortRoot/MiddleTileMap"] z_index = -10 +tile_set = SubResource( 2 ) cell_size = Vector2( 16, 16 ) bake_navigation = true format = 1 +tile_data = PoolIntArray( -131072, 0, 524288, -131071, 0, 524288, -65536, 0, 524288, -65535, 0, 524288 ) diff --git a/DungeonShooting_Godot/scene/test/TestTileLayer.tscn b/DungeonShooting_Godot/scene/test/TestTileLayer.tscn index 6830e4f..b72c314 100644 --- a/DungeonShooting_Godot/scene/test/TestTileLayer.tscn +++ b/DungeonShooting_Godot/scene/test/TestTileLayer.tscn @@ -100,7 +100,6 @@ [node name="TestTileLayer" type="Node2D"] [node name="YSort" type="YSort" parent="."] -visible = false [node name="MiddleTileMap" type="TileMap" parent="YSort"] tile_set = SubResource( 2 ) diff --git a/DungeonShooting_Godot/src/framework/common/NodeExtend.cs b/DungeonShooting_Godot/src/framework/common/NodeExtend.cs new file mode 100644 index 0000000..1b896bc --- /dev/null +++ b/DungeonShooting_Godot/src/framework/common/NodeExtend.cs @@ -0,0 +1,41 @@ +using Godot; + +/// +/// 该类为 node 节点通用扩展函数类 +/// +public static class NodeExtend +{ + /// + /// 尝试将一个 Node2d 节点转换成一个 ActivityObject 对象, 如果转换失败, 则返回 null + /// + public static ActivityObject AsActivityObject(this Node2D node2d) + { + if (node2d is ActivityObject p) + { + return p; + } + var parent = node2d.GetParent(); + if (parent != null && parent is ActivityObject p2) + { + return p2; + } + return null; + } + + /// + /// 尝试将一个 Node2d 节点转换成一个 ActivityObject 对象, 如果转换失败, 则返回 null + /// + public static T AsActivityObject(this Node2D node2d) where T : ActivityObject + { + if (node2d is T p) + { + return p; + } + var parent = node2d.GetParent(); + if (parent != null && parent is T p2) + { + return p2; + } + return null; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/common/Utils.cs b/DungeonShooting_Godot/src/framework/common/Utils.cs new file mode 100644 index 0000000..1af7b2f --- /dev/null +++ b/DungeonShooting_Godot/src/framework/common/Utils.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using Godot; + +/// +/// 常用函数工具类 +/// +public static class Utils +{ + + /// + /// 返回随机 boolean 值 + /// + public static bool RandBoolean() + { + return GD.Randf() >= 0.5f; + } + + /// + /// 返回一个区间内的随机小数 + /// + public static float RandRange(float min, float max) + { + if (min == max) return min; + if (min > max) + return GD.Randf() * (min - max) + max; + return GD.Randf() * (max - min) + min; + } + + /// + /// 返回一个区间内的随机整数 + /// + public static int RandRangeInt(int min, int max) + { + if (min == max) return min; + if (min > max) + return Mathf.FloorToInt(GD.Randf() * (min - max + 1) + max); + return Mathf.FloorToInt(GD.Randf() * (max - min + 1) + min); + } + + /// + /// 随机返回其中一个参数 + /// + public static T RandChoose(params T[] list) + { + if (list.Length == 0) + { + return default; + } + + return list[RandRangeInt(0, list.Length - 1)]; + } + + /// + /// 随机返回集合中的一个元素 + /// + public static T RandChoose(List list) + { + if (list.Count == 0) + { + return default; + } + + return list[RandRangeInt(0, list.Count - 1)]; + } + + public static Rect2 CalcRect(float start1, float end1, float start2, float end2) + { + return new Rect2( + Mathf.Min(start1, start2), Mathf.Min(end1, end2), + Mathf.Abs(start1 - start2), Mathf.Abs(end1 - end2) + ); + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generate/GenerateDungeon.cs b/DungeonShooting_Godot/src/framework/generate/GenerateDungeon.cs index d22f3db..ae63205 100644 --- a/DungeonShooting_Godot/src/framework/generate/GenerateDungeon.cs +++ b/DungeonShooting_Godot/src/framework/generate/GenerateDungeon.cs @@ -186,10 +186,14 @@ private bool ConnectDoor(RoomInfo room, RoomInfo nextRoom) { //门描述 - var roomDoor = new RoomDoor(); - var nextRoomDoor = new RoomDoor(); + var roomDoor = new RoomDoorInfo(); + var nextRoomDoor = new RoomDoorInfo(); + roomDoor.RoomInfo = room; + nextRoomDoor.RoomInfo = nextRoom; roomDoor.ConnectRoom = nextRoom; + roomDoor.ConnectDoor = nextRoomDoor; nextRoomDoor.ConnectRoom = room; + nextRoomDoor.ConnectDoor = roomDoor; var overlapX = Mathf.Min(room.Position.x + room.Size.x, nextRoom.Position.x + nextRoom.Size.x) - Mathf.Max(room.Position.x, nextRoom.Position.x); @@ -197,7 +201,7 @@ if (overlapX >= 6) { //找到重叠区域 - var range = CalcRange(room.Position.x, room.Position.x + room.Size.x, + var range = CalcOverlapRange(room.Position.x, room.Position.x + room.Size.x, nextRoom.Position.x, nextRoom.Position.x + nextRoom.Size.x); var x = Utils.RandRangeInt((int)range.x + 1, (int)range.y - _corridorWidth - 1); @@ -235,7 +239,7 @@ if (overlapY >= 6) { //找到重叠区域 - var range = CalcRange(room.Position.y, room.Position.y + room.Size.y, + var range = CalcOverlapRange(room.Position.y, room.Position.y + room.Size.y, nextRoom.Position.y, nextRoom.Position.y + nextRoom.Size.y); var y = Utils.RandRangeInt((int)range.x + 1, (int)range.y - _corridorWidth - 1); @@ -390,8 +394,8 @@ return true; } - //返回的x为宽, y为高 - private Vector2 CalcRange(float start1, float end1, float start2, float end2) + //用于计算重叠区域坐标, 可以理解为一维轴上4个点的中间两个点 + private Vector2 CalcOverlapRange(float start1, float end1, float start2, float end2) { return new Vector2(Mathf.Max(start1, start2), Mathf.Min(end1, end2)); } @@ -411,7 +415,7 @@ } //将两个门间的过道占用数据存入RoomGrid - private bool AddCorridorToGridRange(RoomDoor door1, RoomDoor door2) + private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2) { var point1 = door1.OriginPosition; var point2 = door2.OriginPosition; @@ -444,7 +448,7 @@ } //将两个门间的过道占用数据存入RoomGrid, 该重载 - private bool AddCorridorToGridRange(RoomDoor door1, RoomDoor door2, Vector2 cross) + private bool AddCorridorToGridRange(RoomDoorInfo door1, RoomDoorInfo door2, Vector2 cross) { var point1 = door1.OriginPosition; var point2 = door2.OriginPosition; diff --git a/DungeonShooting_Godot/src/framework/generate/RoomDoor.cs b/DungeonShooting_Godot/src/framework/generate/RoomDoor.cs deleted file mode 100644 index e4ee6ce..0000000 --- a/DungeonShooting_Godot/src/framework/generate/RoomDoor.cs +++ /dev/null @@ -1,33 +0,0 @@ - -using Godot; - -/// -/// 房间的门 -/// -public class RoomDoor -{ - /// - /// 所在墙面方向 - /// - public DoorDirection Direction; - - /// - /// 连接的房间 - /// - public RoomInfo ConnectRoom; - - /// - /// 原点坐标 - /// - public Vector2 OriginPosition; - - /// - /// 与下一道门是否有交叉点 - /// - public bool HasCross; - - /// - /// 与下一道门的交叉点 - /// - public Vector2 Cross; -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generate/RoomDoorInfo.cs b/DungeonShooting_Godot/src/framework/generate/RoomDoorInfo.cs new file mode 100644 index 0000000..ceb2cbd --- /dev/null +++ b/DungeonShooting_Godot/src/framework/generate/RoomDoorInfo.cs @@ -0,0 +1,43 @@ + +using Godot; + +/// +/// 房间的门 +/// +public class RoomDoorInfo +{ + /// + /// 所在墙面方向 + /// + public DoorDirection Direction; + + /// + /// 所在的房间 + /// + public RoomInfo RoomInfo; + + /// + /// 连接的门 + /// + public RoomDoorInfo ConnectDoor; + + /// + /// 连接的房间 + /// + public RoomInfo ConnectRoom; + + /// + /// 原点坐标 + /// + public Vector2 OriginPosition; + + /// + /// 与下一道门是否有交叉点 + /// + public bool HasCross; + + /// + /// 与下一道门的交叉点 + /// + public Vector2 Cross; +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generate/RoomInfo.cs b/DungeonShooting_Godot/src/framework/generate/RoomInfo.cs index 603e4bd..9f126b9 100644 --- a/DungeonShooting_Godot/src/framework/generate/RoomInfo.cs +++ b/DungeonShooting_Godot/src/framework/generate/RoomInfo.cs @@ -27,9 +27,15 @@ /// /// 门 /// - public List Doors = new List(); + public List Doors = new List(); + /// + /// 下一个房间 + /// public List Next = new List(); + /// + /// 上一个房间 + /// public RoomInfo Prev; } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/common/NodeExtend.cs b/DungeonShooting_Godot/src/game/common/NodeExtend.cs deleted file mode 100644 index 1b896bc..0000000 --- a/DungeonShooting_Godot/src/game/common/NodeExtend.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Godot; - -/// -/// 该类为 node 节点通用扩展函数类 -/// -public static class NodeExtend -{ - /// - /// 尝试将一个 Node2d 节点转换成一个 ActivityObject 对象, 如果转换失败, 则返回 null - /// - public static ActivityObject AsActivityObject(this Node2D node2d) - { - if (node2d is ActivityObject p) - { - return p; - } - var parent = node2d.GetParent(); - if (parent != null && parent is ActivityObject p2) - { - return p2; - } - return null; - } - - /// - /// 尝试将一个 Node2d 节点转换成一个 ActivityObject 对象, 如果转换失败, 则返回 null - /// - public static T AsActivityObject(this Node2D node2d) where T : ActivityObject - { - if (node2d is T p) - { - return p; - } - var parent = node2d.GetParent(); - if (parent != null && parent is T p2) - { - return p2; - } - return null; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/common/Utils.cs b/DungeonShooting_Godot/src/game/common/Utils.cs deleted file mode 100644 index fe899dc..0000000 --- a/DungeonShooting_Godot/src/game/common/Utils.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections.Generic; -using Godot; - -/// -/// 常用函数工具类 -/// -public static class Utils -{ - - /// - /// 返回随机 boolean 值 - /// - public static bool RandBoolean() - { - return GD.Randf() >= 0.5f; - } - - /// - /// 返回一个区间内的随机小数 - /// - public static float RandRange(float min, float max) - { - if (min == max) return min; - if (min > max) - return GD.Randf() * (min - max) + max; - return GD.Randf() * (max - min) + min; - } - - /// - /// 返回一个区间内的随机整数 - /// - public static int RandRangeInt(int min, int max) - { - if (min == max) return min; - if (min > max) - return Mathf.FloorToInt(GD.Randf() * (min - max + 1) + max); - return Mathf.FloorToInt(GD.Randf() * (max - min + 1) + min); - } - - /// - /// 随机返回其中一个参数 - /// - public static T RandChoose(params T[] list) - { - if (list.Length == 0) - { - return default; - } - - return list[RandRangeInt(0, list.Length - 1)]; - } - - /// - /// 随机返回集合中的一个元素 - /// - public static T RandChoose(List list) - { - if (list.Count == 0) - { - return default; - } - - return list[RandRangeInt(0, list.Count - 1)]; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/role/Player.cs b/DungeonShooting_Godot/src/game/role/Player.cs index f805bc9..e96e5ec 100644 --- a/DungeonShooting_Godot/src/game/role/Player.cs +++ b/DungeonShooting_Godot/src/game/role/Player.cs @@ -47,6 +47,8 @@ Hp = 50; MaxShield = 30; Shield = 30; + + MoveSpeed = 300; } protected override void Process(float delta) diff --git a/DungeonShooting_Godot/src/game/room/DungeonTileManager.cs b/DungeonShooting_Godot/src/game/room/DungeonTileManager.cs new file mode 100644 index 0000000..2f3d2a4 --- /dev/null +++ b/DungeonShooting_Godot/src/game/room/DungeonTileManager.cs @@ -0,0 +1,51 @@ + +using Godot; + +public static class DungeonTileManager +{ + public static void AutoFillRoomTile(TileMap floor, TileMap middle, TileMap top, RoomInfo roomInfo) + { + foreach (var info in roomInfo.Next) + { + AutoFillRoomTile(floor, middle, top, info); + } + //铺房间 + FillRect(floor, 0, roomInfo.Position, roomInfo.Size); + //铺过道 + foreach (var doorInfo in roomInfo.Doors) + { + if (doorInfo.ConnectRoom.Id < roomInfo.Id) + { + if (!doorInfo.HasCross) + { + var rect = Utils.CalcRect( + doorInfo.OriginPosition.x, + doorInfo.OriginPosition.y, + doorInfo.ConnectDoor.OriginPosition.x, + doorInfo.ConnectDoor.OriginPosition.y + ); + if (doorInfo.Direction == DoorDirection.N || doorInfo.Direction == DoorDirection.S) + { + rect.Size = new Vector2(4, rect.Size.y); + } + else + { + rect.Size = new Vector2(rect.Size.x, 4); + } + FillRect(floor, 0, rect.Position, rect.Size); + } + } + } + } + + private static void FillRect(TileMap tileMap, int index, 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, index, false, false, false, new Vector2(0, 8)); + } + } + } +} \ 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 3b83bb5..9ea3da7 100644 --- a/DungeonShooting_Godot/src/game/room/RoomManager.cs +++ b/DungeonShooting_Godot/src/game/room/RoomManager.cs @@ -36,7 +36,9 @@ //导航区域数据 private List _polygonDataList = new List(); - private TileMap _tileMap; + public TileMap FloorTileMap { get; private set; } + public TileMap MiddleTileMap { get; private set; } + public TileMap TopTileMap { get; private set; } private Font _font; private GenerateDungeon _generateDungeon; @@ -52,7 +54,10 @@ NavigationPolygon = new NavigationPolygonInstance(); AddChild(NavigationPolygon); - _tileMap = GetNode(FloorTilePath); + FloorTileMap = GetNode(FloorTilePath); + MiddleTileMap = GetNode(MiddleTilePath); + TopTileMap = GetNode(TopTilePath); + // var node = child.GetNode("Config"); // Color color = (Color)node.GetMeta("ClearColor"); // VisualServer.SetDefaultClearColor(color); @@ -66,14 +71,19 @@ public override void _Ready() { - _tileMap.CellYSort = false; - _tileMap.BakeNavigation = false; + FloorTileMap.CellYSort = false; + FloorTileMap.BakeNavigation = false; _font = ResourceManager.Load(ResourcePath.resource_font_cn_font_36_tres); //生成地牢房间 _generateDungeon = new GenerateDungeon(); _generateDungeon.Generate(); + //填充地牢 + DungeonTileManager.AutoFillRoomTile(FloorTileMap, MiddleTileMap, TopTileMap, _generateDungeon.StartRoom); + FloorTileMap.UpdateDirtyQuadrants(); + MiddleTileMap.UpdateDirtyQuadrants(); + TopTileMap.UpdateDirtyQuadrants(); //根据房间数据创建填充 tiled @@ -175,7 +185,7 @@ /// public bool IsWayTile(int x, int y) { - return _tileMap.GetCell(x, y) != TileMap.InvalidCell; + return FloorTileMap.GetCell(x, y) != TileMap.InvalidCell; } /// @@ -183,7 +193,7 @@ /// public bool IsWayPosition(float x, float y) { - var tileMapCellSize = _tileMap.CellSize; + var tileMapCellSize = FloorTileMap.CellSize; return IsWayTile((int)(x / tileMapCellSize.x), (int)(y / tileMapCellSize.y)); } @@ -192,9 +202,9 @@ /// private void GenerateNavigationPolygon() { - var size = _tileMap.CellSize; + var size = FloorTileMap.CellSize; - var rect = _tileMap.GetUsedRect(); + var rect = FloorTileMap.GetUsedRect(); var x = (int)rect.Position.x; var y = (int)rect.Position.y; @@ -213,11 +223,11 @@ if (!IsWayTile(i, j - 1)) { - polygonData = CalcOutline(i, j, _tileMap, size); + polygonData = CalcOutline(i, j, FloorTileMap, size); } else if (!IsWayTile(i, j + 1)) { - polygonData = CalcInline(i, j, _tileMap, size); + polygonData = CalcInline(i, j, FloorTileMap, size); } if (polygonData != null) @@ -230,6 +240,7 @@ } } + //计算导航网格外轮廓 private NavigationPolygonData CalcOutline(int i, int j, TileMap tileMap, Vector2 size) { var polygonData = new NavigationPolygonData(); @@ -468,6 +479,7 @@ } } + //计算导航网格内轮廓 private NavigationPolygonData CalcInline(int i, int j, TileMap tileMap, Vector2 size) { var polygonData = new NavigationPolygonData(); @@ -706,6 +718,7 @@ } } + //记录导航网格中已经使用过的坐标 private void PutUsePoint(Vector2 pos) { if (_usePoints.Contains(pos)) @@ -719,7 +732,7 @@ //绘制房间区域, debug 用 private void DrawRoomInfo(RoomInfo room) { - var cellSize = _tileMap.CellSize; + var cellSize = FloorTileMap.CellSize; var pos1 = (room.Position + room.Size / 2) * cellSize; //绘制下一个房间 diff --git a/DungeonShooting_Godot/src/game/room/TileCellInfo.cs b/DungeonShooting_Godot/src/game/room/TileCellInfo.cs new file mode 100644 index 0000000..4ddecca --- /dev/null +++ b/DungeonShooting_Godot/src/game/room/TileCellInfo.cs @@ -0,0 +1,14 @@ + +using Godot; + +public class TileCellInfo +{ + public TileCellInfo(int id, Vector2? autotileCoord) + { + Id = id; + AutotileCoord = autotileCoord; + } + + public int Id; + public Vector2? AutotileCoord; +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/room/TileConfig.cs b/DungeonShooting_Godot/src/game/room/TileConfig.cs new file mode 100644 index 0000000..88aecd4 --- /dev/null +++ b/DungeonShooting_Godot/src/game/room/TileConfig.cs @@ -0,0 +1,10 @@ + +using Godot; + +/// +/// 房间图块配置信息 +/// +public class TileConfig +{ + +} \ No newline at end of file