diff --git a/README.md b/README.md index 09a6691..9d4f2f6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ English [简体中文](README_ZH.md) [にほんご](README_JP.md) Mint's new game. -A pixel cross-platform Roguelite game. +A pixel cross-platform roguelite game. ## Recent Development progress @@ -14,6 +14,16 @@ A pixel cross-platform Roguelite game. | loot | await | | Support still out of the knapsack system | await | +## Screenshot + +Game scene + +![](screenshot\0.0.1\game_page.png) + +Level graph editor + +![](screenshot\0.0.1\level_Graph_Editor.png) + ## Run the project locally #### Download engine diff --git a/README_JP.md b/README_JP.md index d30cb0f..b78b223 100644 --- a/README_JP.md +++ b/README_JP.md @@ -1,4 +1,4 @@ -[English](README.md) [简体中文](README_ZH) にほんご +[English](README.md) [简体中文](README_ZH.md) にほんご ## こくじ @@ -13,7 +13,15 @@ | マップをランダムに生成します | 進行中です | | 戦利品 | すたんばい | | バックパックのシステムをサポートしています | すたんばい | +## スクリーンショットです +ゲームのシーンです + +![](screenshot\0.0.1\game_page.png) + +ステージエディター + +![](screenshot\0.0.1\level_Graph_Editor.png) ## 地元でプロジェクトを進めています #### ダウンロードエンジンです diff --git a/README_ZH.md b/README_ZH.md index c7e058b..87222c3 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -14,6 +14,16 @@ | 战利品 | 等待 | | 支持仍出的背包系统 | 等待 | +## 屏幕截图 + +游戏场景 + +![](screenshot\0.0.1\game_page.png) + +关卡编辑器 + +![](screenshot\0.0.1\level_Graph_Editor.png) + ## 在本地运行项目 #### 下载引擎 diff --git a/locals/Error.csv b/locals/Error.csv index 90bdb00..add28cc 100644 --- a/locals/Error.csv +++ b/locals/Error.csv @@ -4,4 +4,6 @@ missing_parameters,缺少参数。,Missing parameters.,パラメータが不足 room_root_node_must_be_node2d,房间根节点必须是 Node2D。,Room root node must be Node2D.,ルートノードはNode2Dでなければなりません。 width_or_height_of_room_slot_must_be_1,房间槽的宽度或高度必须为1。,The width or height of the room slot must be 1.,部屋の溝の幅または高さは1でなければなりません。 connected_room_timeout,连接房间超时。,Connecting the room timed out.,接続部屋はタイムアウトです。 -projectiles_is_empty,未设置抛射体。,The projectile is not set.,射出体は設置されていません。 \ No newline at end of file +projectiles_is_empty,未设置抛射体。,The projectile is not set.,射出体は設置されていません。 +map_generator_missing_parameters,地图生成器缺少参数。,Map generator missing parameters.,マップジェネレータが不足しています。 +map_generator_attempts_to_parse_empty_layout_diagrams,地图生成器尝试解析空的布局图。,Map generator attempts to parse empty layout diagrams.,マップジェネレータは空のレイアウト図を解析しようとしています。 \ No newline at end of file diff --git a/locals/Error.en.translation b/locals/Error.en.translation index 6bd3e94..262938c 100644 Binary files a/locals/Error.en.translation and b/locals/Error.en.translation differ diff --git a/locals/Error.jp.translation b/locals/Error.jp.translation index a8edd94..50361d6 100644 Binary files a/locals/Error.jp.translation and b/locals/Error.jp.translation differ diff --git a/locals/Error.zh.translation b/locals/Error.zh.translation index 701d03f..6e08a5e 100644 Binary files a/locals/Error.zh.translation and b/locals/Error.zh.translation differ diff --git a/screenshot/0.0.1/game_page.png b/screenshot/0.0.1/game_page.png new file mode 100644 index 0000000..a0d6f8b Binary files /dev/null and b/screenshot/0.0.1/game_page.png differ diff --git a/screenshot/0.0.1/game_page.png.import b/screenshot/0.0.1/game_page.png.import new file mode 100644 index 0000000..b97fcb0 --- /dev/null +++ b/screenshot/0.0.1/game_page.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b4r8qekdrtgbv" +path="res://.godot/imported/game_page.png-f8f5cdcc23f5b71be114ec8661e808ce.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://screenshot/0.0.1/game_page.png" +dest_files=["res://.godot/imported/game_page.png-f8f5cdcc23f5b71be114ec8661e808ce.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/screenshot/0.0.1/level_Graph_Editor.png b/screenshot/0.0.1/level_Graph_Editor.png new file mode 100644 index 0000000..c9b3513 Binary files /dev/null and b/screenshot/0.0.1/level_Graph_Editor.png differ diff --git a/screenshot/0.0.1/level_Graph_Editor.png.import b/screenshot/0.0.1/level_Graph_Editor.png.import new file mode 100644 index 0000000..2924e6d --- /dev/null +++ b/screenshot/0.0.1/level_Graph_Editor.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dyiarx2q4r6y6" +path="res://.godot/imported/level_Graph_Editor.png-2a8ba6f35e054e058aaed64bd42cfc40.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://screenshot/0.0.1/level_Graph_Editor.png" +dest_files=["res://.godot/imported/level_Graph_Editor.png-2a8ba6f35e054e058aaed64bd42cfc40.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/scripts/map/ILayoutParsingStrategy.cs b/scripts/map/ILayoutParsingStrategy.cs new file mode 100644 index 0000000..62c53a3 --- /dev/null +++ b/scripts/map/ILayoutParsingStrategy.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using ColdMint.scripts.levelGraphEditor; + +namespace ColdMint.scripts.map; + +/// +/// Layout parsing strategy +/// 布局图解析策略 +/// +public interface ILayoutParsingStrategy +{ + /// + /// Sets the layout diagram to parse + /// 设置要解析的布局图 + /// + /// + public void SetLevelGraph(LevelGraphEditorSaveData levelGraphEditorSaveData); + + /// + /// Gets the next room to place + /// 获取下一个要放置的房间 + /// + /// + public Task Next(); + + /// + /// Gets the ID of the next parent node to place + /// 获取下一个要放置的父节点ID + /// + /// + public Task GetNextParentNodeId(); + + /// + /// Is there another room that needs to be placed + /// 是否还有下一个需要放置的房间 + /// + /// + public Task HasNext(); +} \ No newline at end of file diff --git a/scripts/map/IRoomInjectionStrategy.cs b/scripts/map/IRoomInjectionStrategy.cs new file mode 100644 index 0000000..3f33fc8 --- /dev/null +++ b/scripts/map/IRoomInjectionStrategy.cs @@ -0,0 +1,10 @@ +namespace ColdMint.scripts.map; + +/// +/// Room injection strategy +/// 房间注入策略 +/// +public interface IRoomInjectionStrategy +{ + +} \ No newline at end of file diff --git a/scripts/map/MapGenerator.cs b/scripts/map/MapGenerator.cs index 03daf44..86e2419 100644 --- a/scripts/map/MapGenerator.cs +++ b/scripts/map/MapGenerator.cs @@ -1,5 +1,7 @@ -using System.Threading.Tasks; -using ColdMint.scripts.levelGraphEditor; +using System.Collections.Generic; +using System.Threading.Tasks; +using ColdMint.scripts.debug; +using ColdMint.scripts.map.interfaces; namespace ColdMint.scripts.map; @@ -19,6 +21,31 @@ public static class MapGenerator /// private static ILayoutStrategy? _layoutStrategy; + /// + /// Room placement strategy + /// 房间的放置策略 + /// + private static IRoomPlacementStrategy? _roomPlacementStrategy; + + + /// + /// Layout diagram parsing policy + /// 布局图解析策略 + /// + private static ILayoutParsingStrategy? _layoutParsingStrategy; + + public static ILayoutParsingStrategy? LayoutParsingStrategy + { + get => _layoutParsingStrategy; + set => _layoutParsingStrategy = value; + } + + public static IRoomPlacementStrategy? RoomPlacementStrategy + { + get => _roomPlacementStrategy; + set => _roomPlacementStrategy = value; + } + public static ILayoutStrategy? LayoutStrategy { get => _layoutStrategy; @@ -31,30 +58,62 @@ public static class MapGenerator /// public static async Task GenerateMap() { - if (_layoutStrategy == null) + if (_layoutStrategy == null || _roomPlacementStrategy == null || _layoutParsingStrategy == null) { + LogCat.LogError("map_generator_missing_parameters"); return; } //Get the layout data //拿到布局图数据 var levelGraphEditorSaveData = await _layoutStrategy.GetLayout(); - //Finding the starting room - //查找起点房间 if (levelGraphEditorSaveData.RoomNodeDataList == null || levelGraphEditorSaveData.RoomNodeDataList.Count == 0) { + LogCat.LogError("map_generator_attempts_to_parse_empty_layout_diagrams"); return; } - var startRoomNodeData = levelGraphEditorSaveData.RoomNodeDataList.Find(roomNodeData => - roomNodeData.HasTag(Config.RoomDataTag.StartingRoom)); - if (startRoomNodeData == null) + _layoutParsingStrategy.SetLevelGraph(levelGraphEditorSaveData); + //Save the dictionary, put the ID in the room data, corresponding to the successful placement of the room. + //保存字典,将房间数据内的ID,对应放置成功的房间。 + var roomDictionary = new Dictionary(); + while (await _layoutParsingStrategy.HasNext()) { - //Can't find the starting room - //找不到起点房间 - return; + //When a new room needs to be placed + //当有新的房间需要放置时 + var roomNodeData = await _layoutParsingStrategy.Next(); + if (roomNodeData == null) + { + continue; + } + + var nextParentNodeId = await _layoutParsingStrategy.GetNextParentNodeId(); + IRoom? parentRoomNode = null; + if (nextParentNodeId != null) + { + //If the new room has the parent's ID, then we pass the parent's room into the compute function. + //如果新房间有父节点的ID,那么我们将父节点的房间传入到计算函数内。 + parentRoomNode = roomDictionary[nextParentNodeId]; + } + + var roomPlacementData = + await _roomPlacementStrategy.CalculateNewRoomPlacementData(parentRoomNode, roomNodeData); + if (roomPlacementData == null) + { + continue; + } + + if (!await _roomPlacementStrategy.PlaceRoom(roomPlacementData)) + { + continue; + } + + if (!string.IsNullOrEmpty(roomNodeData.Id) && roomPlacementData.Room != null) + { + roomDictionary.Add(roomNodeData.Id, roomPlacementData.Room); + } } - //The starting room is regarded as the root node, and the map is generated from the root node to the leaf node like the tree structure. - //TODO:将起点房间看作根节点,像树结构一样,从根节点到叶节点生成地图。 + //All rooms have been placed. + //所有房间已放置完毕。 } } \ No newline at end of file diff --git a/scripts/map/dateBean/RoomPlacementData.cs b/scripts/map/dateBean/RoomPlacementData.cs new file mode 100644 index 0000000..60b1040 --- /dev/null +++ b/scripts/map/dateBean/RoomPlacementData.cs @@ -0,0 +1,22 @@ +using ColdMint.scripts.map.interfaces; +using Godot; + +namespace ColdMint.scripts.map.dateBean; + +/// +/// Room placement information +/// 房间放置信息 +/// +public class RoomPlacementData +{ + /// + /// the location of placement + /// 放置的位置 + /// + public Vector2? Position { get; set; } + /// + /// Place the room template + /// 放置的房间模板 + /// + public IRoom? Room { get; set; } +} \ No newline at end of file diff --git a/scripts/map/interfaces/IBranch.cs b/scripts/map/interfaces/IBranch.cs deleted file mode 100644 index 715ed9a..0000000 --- a/scripts/map/interfaces/IBranch.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace ColdMint.scripts.map.interfaces; - -/// -/// Represents a branch on the map. -/// 表示地图上的一个分支。 -/// -public interface IBranch -{ - /// - /// Master branch or not - /// 是否为主分支 - /// - bool IsMasterBranch - { - get; - set; - } -} \ No newline at end of file diff --git a/scripts/map/interfaces/IRoom.cs b/scripts/map/interfaces/IRoom.cs index 5164fab..ac10671 100644 --- a/scripts/map/interfaces/IRoom.cs +++ b/scripts/map/interfaces/IRoom.cs @@ -15,6 +15,10 @@ public interface IRoom /// PackedScene? RoomScene { get; set; } + /// + /// Tile map + /// 瓦片地图 + /// TileMap? TileMap { get; set; } /// diff --git a/scripts/map/interfaces/IRoomPlacementStrategy.cs b/scripts/map/interfaces/IRoomPlacementStrategy.cs new file mode 100644 index 0000000..e90ad20 --- /dev/null +++ b/scripts/map/interfaces/IRoomPlacementStrategy.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using ColdMint.scripts.levelGraphEditor; +using ColdMint.scripts.map.dateBean; + +namespace ColdMint.scripts.map.interfaces; + +/// +/// Room placement strategy +/// 房间放置策略 +/// +public interface IRoomPlacementStrategy +{ + /// + /// Place the room in the designated location + /// 在指定的位置放置房间 + /// + /// + ///Room placement information + ///房间放置信息 + /// + /// + ///Placement success or not + ///是否放置成功 + /// + public Task PlaceRoom(RoomPlacementData roomPlacementData); + + /// + /// Calculate new room placement information + /// 计算新的房间放置信息 + /// + /// + ///Parent room node + ///父房间节点 + /// + /// + ///New room data to be placed + ///欲放置的新房间数据 + /// + /// + public Task CalculateNewRoomPlacementData(IRoom? parentRoomNode, RoomNodeData newRoomNodeData); +} \ No newline at end of file diff --git a/scripts/map/interfaces/IRoomPlacer.cs b/scripts/map/interfaces/IRoomPlacer.cs deleted file mode 100644 index 1622f4b..0000000 --- a/scripts/map/interfaces/IRoomPlacer.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Threading.Tasks; -using ColdMint.scripts.map.dateBean; -using ColdMint.scripts.map.RoomPlacer; -using Godot; - -namespace ColdMint.scripts.map.interfaces; - -/// -/// Room placer -/// 房间放置器 -/// -/// -///Responsible for arranging the rooms on the map -///负责在地图中摆放房间 -/// -public interface IRoomPlacer -{ - - /// - /// Place the room in the designated location - /// 在指定的位置放置房间 - /// - /// - /// - /// - public Task PlaceRoom(Vector2 position, IRoom room); - - /// - /// Pass into two rooms and calculate the location of the new room - /// 传入两个房间,计算新房间的位置 - /// - /// - /// - /// - /// - /// - /// - public Task CalculatedPosition(IRoom mainRoom, IRoom newRoom, RoomSlot? mainRoomSlot, RoomSlot? newRoomSlot, - RoomPlacerConfig roomPlacerConfig); -} \ No newline at end of file diff --git a/scripts/map/roomPlacer/PatchworkRoomPlacementStrategy.cs b/scripts/map/roomPlacer/PatchworkRoomPlacementStrategy.cs new file mode 100644 index 0000000..9e91a2b --- /dev/null +++ b/scripts/map/roomPlacer/PatchworkRoomPlacementStrategy.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using ColdMint.scripts.levelGraphEditor; +using ColdMint.scripts.map.dateBean; +using ColdMint.scripts.map.interfaces; +using Godot; + +namespace ColdMint.scripts.map.RoomPlacer; + +/// +/// Patchwork room placement strategy +/// 拼接的房间放置策略 +/// +/// +///Under this strategy, think of each room template as a puzzle piece, find their "slots", and then connect them together. +///在此策略下,将每个房间模板看作是一块拼图,找到他们的“槽”,然后将其连接在一起。 +/// +public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy +{ + public Task PlaceRoom(RoomPlacementData roomPlacementData) + { + throw new System.NotImplementedException(); + } + + public Task GetStartRoomPlacementData(RoomNodeData startRoomNodeData) + { + throw new System.NotImplementedException(); + } + + + public Task CalculateNewRoomPlacementData(IRoom parentRoomNode, RoomNodeData newRoomNodeData) + { + throw new System.NotImplementedException(); + } +} \ No newline at end of file diff --git a/scripts/map/roomPlacer/RoomPlacer.cs b/scripts/map/roomPlacer/RoomPlacer.cs deleted file mode 100644 index 13ed493..0000000 --- a/scripts/map/roomPlacer/RoomPlacer.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Threading.Tasks; -using ColdMint.scripts.map.dateBean; -using ColdMint.scripts.map.interfaces; -using Godot; -using static ColdMint.scripts.Config; - -namespace ColdMint.scripts.map.RoomPlacer; - -public class RoomPlacer : RoomPlacerTemplate -{ - public IMapGeneratorConfig? MapGeneratorConfig { get; set; } - private readonly Vector2 _halfCell = new Vector2(CellSize / 2f, CellSize / 2f); - - public override Task PlaceRoom(Vector2 position, IRoom room) - { - if (MapGeneratorConfig == null) - { - return Task.FromResult(false); - } - - var node = room.RootNode; - MapGeneratorConfig.MapRoot.AddChild(node); - if (node is { } node2D) - { - //If the Node is not empty and is a 2D node. - //如果Node不是空的,且是2D节点。 - node2D.Position = position; - return Task.FromResult(true); - } - - return Task.FromResult(false); - } - - public override Task CalculatedPosition(IRoom mainRoom, IRoom newRoom, RoomSlot? mainRoomSlot, - RoomSlot? newRoomSlot, - RoomPlacerConfig roomPlacerConfig) - { - if (mainRoom.RootNode == null || mainRoom.TileMap == null || newRoom.TileMap == null || mainRoomSlot == null || - newRoomSlot == null) - { - return Task.FromResult(Vector2.Zero); - } - - //计算主插槽中点在世界中的位置。 - //mainRoom.RootNode.Position意为房间所在的世界位置 - //mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition)意为主插槽在房间中的位置 - var result = mainRoom.RootNode.Position + mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition); - if (roomPlacerConfig.RoomSlotOverlap) - { - //执行减法,从槽中点偏移到左上角 - result -= _halfCell; - } - else - { - //执行减法,从槽中点偏移到右下角 - result += _halfCell; - } - //我们不能将新房间的原点设置在主房间槽的左上角或右下角,这会导致插槽不对应。 - - //竖直槽,我们需要在同一水平上。 - if (mainRoomSlot.IsHorizontal) - { - result += newRoom.TileMap.MapToLocal(new Vector2I(newRoomSlot.EndPosition.X, 0)) - _halfCell; - } - else - { - result -= newRoom.TileMap.MapToLocal(new Vector2I(0, newRoomSlot.EndPosition.Y)) - _halfCell; - } - - return Task.FromResult(result); - } -} \ No newline at end of file diff --git a/scripts/map/roomPlacer/RoomPlacerTemplate.cs b/scripts/map/roomPlacer/RoomPlacerTemplate.cs deleted file mode 100644 index 99557a2..0000000 --- a/scripts/map/roomPlacer/RoomPlacerTemplate.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Threading.Tasks; -using ColdMint.scripts.map.dateBean; -using ColdMint.scripts.map.interfaces; -using Godot; - -namespace ColdMint.scripts.map.RoomPlacer; - -public abstract class RoomPlacerTemplate : IRoomPlacer -{ - public abstract Task PlaceRoom(Vector2 position, IRoom room); - - public abstract Task CalculatedPosition(IRoom mainRoom, IRoom newRoom, RoomSlot? mainRoomSlot, RoomSlot? newRoomSlot, - RoomPlacerConfig roomPlacerConfig); -} \ No newline at end of file