diff --git a/README.md b/README.md index ee567a1..4a6a3e3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,68 @@ -## Star History +## Intro 简介 + +Mint's new game. + +薄荷的新作游戏。 + +A pixel cross-platform Roguelite game. + +一款像素的跨平台的Roguelite游戏。 + +## Recent Development progress 近期研发进度 + +| Task 任务 | status 状态 | +| ----------------------------------------------------------- | ------------------ | +| Randomly generated map 随机生成地图 | In progress 进行中 | +| loot 战利品 | await 等待 | +| Support still out of the knapsack system 支持仍出的背包系统 | await 等待 | + +## Run the project locally 在本地运行项目 + +#### Download engine 下载引擎 +1. Download [Godot Engine .Net](https://godotengine.org/). + + 下载[Godot Engine .Net](https://godotengine.org/)。 + + After downloading the engine, you will need to download an additional export template to export as an executable program. + + 下载引擎后,您需要额外下载导出模板才能导出为可执行程序。 + +2. Download [.NetSDK](https://dotnet.microsoft.com/download). + + 下载 [.NetSDK](https://dotnet.microsoft.com/download). + +#### Clone project 克隆项目 + +Enter the following command in your working directory: + +在您的工作目录输入以下指令: + +``` +git clone https://github.com/Cold-Mint/Traveller.git +``` + +## Participate in translation 参与翻译 + +The project is prepared for localization at the beginning of writing. You can edit the csv file in the locals directory. To modify and add new translations. + +此项目在编写之初就为本地化做好了准备。您可以编辑locals目录下的csv文件。来修改和添加新的翻译。 + +## License 许可证 + +[GPL-3.0 license](LICENSE) + +Chinese translation version:[GPL-3.0 license 简体中文](LICENSE_ZH) + +查看协议的中文翻译版本:[GPL-3.0 license 简体中文](LICENSE_ZH) + +Support commercial, anyone can modify, build, and sell or distribute for free. For all derivative versions of this project, under the GPL, you shall **retain the author copyright** and **publish the modified source code**. + +支持商用,任何人可修改,构建,并用于售卖或免费发布。对于此项目的所有衍生版本,根据GPL协议,您应当**保留作者版权**,以及**公开修改后的源代码**。 + +> Note: You have the right to sell the modified version, but not the original. +> +> 注意:您有权售卖修改后的版本,但不能售卖原版。 + +## Star History 点赞历史 [![Star History Chart](https://api.star-history.com/svg?repos=Cold-Mint/Traveller&type=Date)](https://star-history.com/#Cold-Mint/Traveller&Date) \ No newline at end of file diff --git a/locals/Error.csv b/locals/Error.csv index fca2966..90bdb00 100644 --- a/locals/Error.csv +++ b/locals/Error.csv @@ -4,6 +4,4 @@ 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.,射出体は設置されていません。 -map_generator_is_not_set_up,未设置地图生成器。,Map generator is not set up.,マップ生成器は設置されていません。 -map_generator_is_not_configured,地图生成器没有有效配置。,Map Generator is not configured.,地図生成器は機能していません。 \ No newline at end of file +projectiles_is_empty,未设置抛射体。,The projectile is not set.,射出体は設置されていません。 \ No newline at end of file diff --git a/locals/Error.en.translation b/locals/Error.en.translation index 9d1983d..6bd3e94 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 e938919..a8edd94 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 1a786bb..701d03f 100644 Binary files a/locals/Error.zh.translation and b/locals/Error.zh.translation differ diff --git a/scripts/Config.cs b/scripts/Config.cs index 70d77dc..1247775 100644 --- a/scripts/Config.cs +++ b/scripts/Config.cs @@ -333,6 +333,15 @@ public static class Config public const int Platform = 6; public const int Mob = 7; } + + public class RoomDataTag + { + /// + /// Mark the starting room + /// 起点房间的标记 + /// + public const string StartingRoom = "StartingRoom"; + } /// /// Specify the type of damage used in the game diff --git a/scripts/levelGraphEditor/RoomNodeData.cs b/scripts/levelGraphEditor/RoomNodeData.cs index bc647f4..4b5aa4d 100644 --- a/scripts/levelGraphEditor/RoomNodeData.cs +++ b/scripts/levelGraphEditor/RoomNodeData.cs @@ -1,4 +1,6 @@ -namespace ColdMint.scripts.levelGraphEditor; +using System.Linq; + +namespace ColdMint.scripts.levelGraphEditor; public class RoomNodeData { @@ -7,4 +9,18 @@ public class RoomNodeData public string? Description { get; set; } public string[]? RoomTemplateSet { get; set; } + + public string[]? Tags { get; set; } + + + /// + /// Whether a tag is held + /// 是否持有某个标签 + /// + /// + /// + public bool HasTag(string tag) + { + return Tags != null && Tags.Any(t => t == tag); + } } \ No newline at end of file diff --git a/scripts/loader/sceneLoader/GameSceneLoader.cs b/scripts/loader/sceneLoader/GameSceneLoader.cs index d48f4f3..549064e 100644 --- a/scripts/loader/sceneLoader/GameSceneLoader.cs +++ b/scripts/loader/sceneLoader/GameSceneLoader.cs @@ -3,7 +3,6 @@ using ColdMint.scripts.character; using ColdMint.scripts.debug; using ColdMint.scripts.inventory; using ColdMint.scripts.map; -using ColdMint.scripts.map.interfaces; using ColdMint.scripts.map.room; using ColdMint.scripts.map.roomHolder; using ColdMint.scripts.map.RoomPlacer; @@ -15,8 +14,6 @@ namespace ColdMint.scripts.loader.sceneLoader; public partial class GameSceneLoader : SceneLoaderTemplate { - private IMapGenerator? _mapGenerator; - private IMapGeneratorConfig? _mapGeneratorConfig; public override Task InitializeData() { @@ -32,77 +29,11 @@ public partial class GameSceneLoader : SceneLoaderTemplate //加载武器容器 var weaponContainer = GetNode("WeaponContainer"); GameSceneNodeHolder.WeaponContainer = weaponContainer; - - _mapGenerator = new MapGenerator(); - _mapGenerator.TimeOutPeriod = 15; - _mapGenerator.RoomHolder = new RoomHolder(); - _mapGenerator.RoomSlotsMatcher = new RoomSlotsMatcher(); - var roomProvider = new RoomProvider(); - //添加房间模板 - var initialRoom = new RoomTemplate("res://prefab/roomTemplates/dungeon/initialRoom.tscn"); - var utilityRoom = new RoomTemplate("res://prefab/roomTemplates/dungeon/utilityRoom.tscn"); - initialRoom.MaxNumber = 1; - var horizontalCorridorWithSewer = - new RoomTemplate("res://prefab/roomTemplates/dungeon/horizontalCorridorWithSewer.tscn"); - var horizontalCorridor = new RoomTemplate("res://prefab/roomTemplates/dungeon/horizontalCorridor.tscn"); - roomProvider.AddRoom(initialRoom); - roomProvider.AddRoom(horizontalCorridorWithSewer); - roomProvider.AddRoom(horizontalCorridor); - roomProvider.AddRoom(utilityRoom); - _mapGenerator.RoomProvider = roomProvider; - - var roomPlacer = new RoomPlacer(); - _mapGeneratorConfig = new MapGeneratorConfig(GetNode("MapRoot"), 1); - roomPlacer.MapGeneratorConfig = _mapGeneratorConfig; - _mapGenerator.RoomPlacer = roomPlacer; return Task.CompletedTask; } public override async Task LoadScene() { - if (_mapGenerator == null) - { - LogCat.LogError("map_generator_is_not_set_up"); - return; - } - - if (_mapGeneratorConfig == null) - { - LogCat.LogError("map_generator_is_not_configured"); - return; - } - - await _mapGenerator.Generate(_mapGeneratorConfig); - var packedScene = GD.Load("res://prefab/entitys/Character.tscn"); - //Register players in the holder - //在持有者内注册玩家 - var node2D = (Node2D)packedScene.Instantiate(); - if (node2D is Player player) - { - GameSceneNodeHolder.Player = player; - //Allow the player to pick up items. - //使玩家可以捡起物品。 - player.ItemContainer = GameSceneNodeHolder.HotBar; - } - - var gameRoot = GetNode("."); - gameRoot.AddChild(node2D); - node2D.Position = new Vector2(55, 70); - - var delivererOfDarkMagicPackedScene = GD.Load("res://prefab/entitys/DelivererOfDarkMagic.tscn"); - var delivererOfDarkMagicPackedSceneNode2D = (Node2D)delivererOfDarkMagicPackedScene.Instantiate(); - gameRoot.AddChild(delivererOfDarkMagicPackedSceneNode2D); - delivererOfDarkMagicPackedSceneNode2D.Position = new Vector2(70, 70); - - //Load a weapon - //加载武器 - var w = GD.Load("res://prefab/weapons/staffOfTheUndead.tscn"); - for (int i = 0; i < 3; i++) - { - var wn = (Node2D)w.Instantiate(); - wn.Position = new Vector2(55, 90); - var weaponContainer = GameSceneNodeHolder.WeaponContainer; - weaponContainer?.AddChild(wn); - } + } } \ No newline at end of file diff --git a/scripts/loader/uiLoader/LevelGraphEditorLoader.cs b/scripts/loader/uiLoader/LevelGraphEditorLoader.cs index a333382..edd842a 100644 --- a/scripts/loader/uiLoader/LevelGraphEditorLoader.cs +++ b/scripts/loader/uiLoader/LevelGraphEditorLoader.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.IO; -using ColdMint.scripts.debug; using ColdMint.scripts.levelGraphEditor; +using ColdMint.scripts.nodeBinding; using ColdMint.scripts.serialization; using ColdMint.scripts.utils; using Godot; @@ -17,41 +17,18 @@ namespace ColdMint.scripts.loader.uiLoader; /// public partial class LevelGraphEditorLoader : UiLoaderTemplate { - private GraphEdit? _graphEdit; - - /// - /// Button to display the room creation panel. - /// 用于展示房间创建面板的按钮。 - /// - private Button? _showCreateRoomPanelButton; - - private PackedScene? _roomNodeScene; - private Panel? _createOrEditorPanel; - private Button? _hideCreateRoomPanelButton; - private LineEdit? _roomNameLineEdit; - private LineEdit? _roomDescriptionLineEdit; - private Button? _createRoomButton; - private Button? _returnButton; private string? _defaultRoomName; + private readonly LevelGraphEditorBinding _nodeBinding = new LevelGraphEditorBinding(); + /// /// Index of the room /// 房间的索引 /// private int _roomIndex = 1; - private TextEdit? _roomTemplateCollectionTextEdit; - private Label? _roomTemplateTipsLabel; - private Button? _showSavePanelButton; - private Button? _openExportFolderButton; - private HBoxContainer? _hBoxContainer; - private Panel? _saveOrLoadPanel; - private Button? _cancelButton; - private Button? _actionButton; - private Label? _saveOrLoadPanelTitleLabel; - private LineEdit? _fileNameLineEdit; - private Button? _showLoadPanelButton; - private Button? _deleteSelectedNodeButton; + private PackedScene? _roomNodeScene; + private readonly List _selectedNodes = new List(); /// @@ -89,38 +66,18 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate public override void InitializeUi() { base.InitializeUi(); - _roomTemplateTipsLabel = GetNode private void HideCreateRoomPanel() { - if (_graphEdit != null) + if (_nodeBinding.GraphEdit != null) { - _graphEdit.Visible = true; + _nodeBinding.GraphEdit.Visible = true; } - if (_createOrEditorPanel != null) + if (_nodeBinding.CreateOrEditorPanel != null) { - _createOrEditorPanel.Visible = false; + _nodeBinding.CreateOrEditorPanel.Visible = false; } - if (_hBoxContainer != null) + if (_nodeBinding.HBoxContainer != null) { - _hBoxContainer.Visible = true; + _nodeBinding.HBoxContainer.Visible = true; } } } \ No newline at end of file diff --git a/scripts/map/ILayoutStrategy.cs b/scripts/map/ILayoutStrategy.cs new file mode 100644 index 0000000..0bbe1d7 --- /dev/null +++ b/scripts/map/ILayoutStrategy.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using ColdMint.scripts.levelGraphEditor; + +namespace ColdMint.scripts.map; + +public interface ILayoutStrategy +{ + /// + /// Get layout + /// 获取布局图 + /// + /// + public Task GetLayout(); +} \ No newline at end of file diff --git a/scripts/map/MapGenerator.cs b/scripts/map/MapGenerator.cs index 5994ee6..03daf44 100644 --- a/scripts/map/MapGenerator.cs +++ b/scripts/map/MapGenerator.cs @@ -1,110 +1,60 @@ -using System; -using System.Threading.Tasks; -using ColdMint.scripts.debug; -using ColdMint.scripts.map.interfaces; -using ColdMint.scripts.map.room; -using ColdMint.scripts.map.RoomPlacer; -using Godot; +using System.Threading.Tasks; +using ColdMint.scripts.levelGraphEditor; namespace ColdMint.scripts.map; -public class MapGenerator : IMapGenerator +/// +/// Map generator +/// 地图生成器 +/// +/// +///Responsible for the overall map generation process control +///负责地图的整体生成流程控制 +/// +public static class MapGenerator { - public int TimeOutPeriod { get; set; } - public IRoomSlotsMatcher? RoomSlotsMatcher { get; set; } - public IRoomHolder? RoomHolder { get; set; } + /// + /// Layout map selection strategy + /// 布局图选择策略 + /// + private static ILayoutStrategy? _layoutStrategy; - public IRoomPlacer? RoomPlacer { get; set; } - - public IRoomProvider? RoomProvider { get; set; } - - public async Task Generate(IMapGeneratorConfig mapGeneratorConfig) + public static ILayoutStrategy? LayoutStrategy { - if (RoomPlacer == null || RoomHolder == null || RoomProvider == null || RoomSlotsMatcher == null || - RoomProvider.InitialRoom == null) + get => _layoutStrategy; + set => _layoutStrategy = value; + } + + /// + /// Generating a map + /// 生成地图 + /// + public static async Task GenerateMap() + { + if (_layoutStrategy == null) { - PrintMissingParametersError(); return; } - try + //Get the layout data + //拿到布局图数据 + var levelGraphEditorSaveData = await _layoutStrategy.GetLayout(); + //Finding the starting room + //查找起点房间 + if (levelGraphEditorSaveData.RoomNodeDataList == null || levelGraphEditorSaveData.RoomNodeDataList.Count == 0) { - var roomPlacerConfig = new RoomPlacerConfig(); - //获取原点 - var origin = Vector2.Zero; - //在提供者哪里获取房间,并放置他(首次拿初始房间) - var originRoom = - RoomFactory.CreateRoom(RoomProvider.InitialRoom.RoomResPath); - await PlaceRoom(origin, originRoom); - var endTime = DateTime.Now + TimeSpan.FromSeconds(TimeOutPeriod); - while (RoomHolder.PlacedRoomNumber < mapGeneratorConfig.RoomCount) - { - if (DateTime.Now > endTime) - { - LogCat.LogError("connected_room_timeout"); - break; - } - - //我们会一直尝试放置房间,直到达到指定的数量 - var roomRes = RoomProvider.GetRoomRes(RoomHolder.PlacedRoomNumber, mapGeneratorConfig); - if (roomRes == null) - { - continue; - } - - var newRoom = - RoomFactory.CreateRoom(roomRes - .RoomResPath); - if (await RoomSlotsMatcher.IsMatch(RoomHolder.LastRoom, newRoom)) - { - // LogCat.Log("匹配成功" + RoomSlotsMatcher.LastMatchedMainSlot.DistanceToMidpointOfRoom[0] + " " + - // RoomSlotsMatcher.LastMatchedMainSlot.DistanceToMidpointOfRoom[1] + "到" + - // RoomSlotsMatcher.LastMatchedMinorSlot.DistanceToMidpointOfRoom[0] + " " + - // RoomSlotsMatcher.LastMatchedMinorSlot.DistanceToMidpointOfRoom[1]); - await PlaceRoom( - await RoomPlacer.CalculatedPosition(originRoom, newRoom, RoomSlotsMatcher.LastMatchedMainSlot, - RoomSlotsMatcher.LastMatchedMinorSlot, roomPlacerConfig), newRoom); - originRoom = newRoom; - } - } - } - catch (Exception e) - { - LogCat.WhenCaughtException(e); - } - } - - /// - /// PrintMissingParametersError - /// 打印缺少参数错误 - /// - private void PrintMissingParametersError() - { - LogCat.LogError("missing_parameters"); - } - - /// - /// PlaceRoom - /// 放置房间 - /// - /// - /// - /// - private async Task PlaceRoom(Vector2 position, IRoom room) - { - if (RoomPlacer == null || RoomHolder == null) - { - return false; + return; } - if (await RoomPlacer.PlaceRoom(position, room)) + var startRoomNodeData = levelGraphEditorSaveData.RoomNodeDataList.Find(roomNodeData => + roomNodeData.HasTag(Config.RoomDataTag.StartingRoom)); + if (startRoomNodeData == null) { - RoomHolder.AddRoom(room); - // LogCat.Log("我要放置房间,但是成功"); - return true; + //Can't find the starting room + //找不到起点房间 + return; } - - // LogCat.Log("我要放置房间,但是失败了"); - return false; + //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:将起点房间看作根节点,像树结构一样,从根节点到叶节点生成地图。 } } \ No newline at end of file diff --git a/scripts/map/interfaces/IMapGenerator.cs b/scripts/map/interfaces/IMapGenerator.cs deleted file mode 100644 index 0c0db87..0000000 --- a/scripts/map/interfaces/IMapGenerator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Threading.Tasks; - -namespace ColdMint.scripts.map.interfaces; - -public interface IMapGenerator -{ - /// - /// Setting the timeout period - /// 设置超时时间 - /// - /// - ///Causes the engine to terminate generation after a certain amount of time.(Unit: second) - ///使引擎超过一定时间后终止生成。(单位:秒) - /// - public int TimeOutPeriod { get; set; } - - public IRoomSlotsMatcher? RoomSlotsMatcher { get; set; } - public IRoomHolder? RoomHolder { get; set; } - public IRoomPlacer? RoomPlacer { get; set; } - - public IRoomProvider? RoomProvider { get; set; } - - Task Generate(IMapGeneratorConfig mapGeneratorConfig); -} \ No newline at end of file diff --git a/scripts/nodeBinding/INodeBinding.cs b/scripts/nodeBinding/INodeBinding.cs new file mode 100644 index 0000000..6bb93fb --- /dev/null +++ b/scripts/nodeBinding/INodeBinding.cs @@ -0,0 +1,12 @@ +using Godot; + +namespace ColdMint.scripts.nodeBinding; + +/// +/// Node binding +/// 节点绑定 +/// +public interface INodeBinding +{ + void Binding(Node root); +} \ No newline at end of file diff --git a/scripts/nodeBinding/LevelGraphEditorBinding.cs b/scripts/nodeBinding/LevelGraphEditorBinding.cs new file mode 100644 index 0000000..2af207b --- /dev/null +++ b/scripts/nodeBinding/LevelGraphEditorBinding.cs @@ -0,0 +1,56 @@ +using Godot; + +namespace ColdMint.scripts.nodeBinding; + +public class LevelGraphEditorBinding : INodeBinding +{ + public GraphEdit? GraphEdit; + + /// + /// Button to display the room creation panel. + /// 用于展示房间创建面板的按钮。 + /// + public Button? ShowCreateRoomPanelButton; + + public Panel? CreateOrEditorPanel; + public Button? HideCreateRoomPanelButton; + public LineEdit? RoomNameLineEdit; + public LineEdit? RoomDescriptionLineEdit; + public Button? CreateRoomButton; + public Button? ReturnButton; + public TextEdit? RoomTemplateCollectionTextEdit; + public Label? RoomTemplateTipsLabel; + public Button? ShowSavePanelButton; + public Button? OpenExportFolderButton; + public HBoxContainer? HBoxContainer; + public Panel? SaveOrLoadPanel; + public Button? CancelButton; + public Button? ActionButton; + public Label? SaveOrLoadPanelTitleLabel; + public LineEdit? FileNameLineEdit; + public Button? ShowLoadPanelButton; + public Button? DeleteSelectedNodeButton; + public void Binding(Node root) + { + RoomTemplateTipsLabel = root.GetNode