Refactoring map generator, updating readme.

重构地图生成器,更新readme。
This commit is contained in:
Cold-Mint 2024-05-18 23:35:12 +08:00
parent 2fe9353732
commit f07b073dc6
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
15 changed files with 325 additions and 342 deletions

View File

@ -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) [![Star History Chart](https://api.star-history.com/svg?repos=Cold-Mint/Traveller&type=Date)](https://star-history.com/#Cold-Mint/Traveller&Date)

View File

@ -4,6 +4,4 @@ missing_parameters,缺少参数。,Missing parameters.,パラメータが不足
room_root_node_must_be_node2d,房间根节点必须是 Node2D。,Room root node must be Node2D.,ルートードはNode2Dでなければなりません。 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でなければなりません。 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.,接続部屋はタイムアウトです。 connected_room_timeout,连接房间超时。,Connecting the room timed out.,接続部屋はタイムアウトです。
projectiles_is_empty,未设置抛射体。,The projectile is not set.,射出体は設置されていません。 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.,地図生成器は機能していません。
1 id zh en jp
4 room_root_node_must_be_node2d 房间根节点必须是 Node2D。 Room root node must be Node2D. ルートノードはNode2Dでなければなりません。
5 width_or_height_of_room_slot_must_be_1 房间槽的宽度或高度必须为1。 The width or height of the room slot must be 1. 部屋の溝の幅または高さは1でなければなりません。
6 connected_room_timeout 连接房间超时。 Connecting the room timed out. 接続部屋はタイムアウトです。
7 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. 地図生成器は機能していません。

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -333,6 +333,15 @@ public static class Config
public const int Platform = 6; public const int Platform = 6;
public const int Mob = 7; public const int Mob = 7;
} }
public class RoomDataTag
{
/// <summary>
/// <para>Mark the starting room</para>
/// <para>起点房间的标记</para>
/// </summary>
public const string StartingRoom = "StartingRoom";
}
/// <summary> /// <summary>
/// <para>Specify the type of damage used in the game</para> /// <para>Specify the type of damage used in the game</para>

View File

@ -1,4 +1,6 @@
namespace ColdMint.scripts.levelGraphEditor; using System.Linq;
namespace ColdMint.scripts.levelGraphEditor;
public class RoomNodeData public class RoomNodeData
{ {
@ -7,4 +9,18 @@ public class RoomNodeData
public string? Description { get; set; } public string? Description { get; set; }
public string[]? RoomTemplateSet { get; set; } public string[]? RoomTemplateSet { get; set; }
public string[]? Tags { get; set; }
/// <summary>
/// <para>Whether a tag is held</para>
/// <para>是否持有某个标签</para>
/// </summary>
/// <param name="tag"></param>
/// <returns></returns>
public bool HasTag(string tag)
{
return Tags != null && Tags.Any(t => t == tag);
}
} }

View File

@ -3,7 +3,6 @@ using ColdMint.scripts.character;
using ColdMint.scripts.debug; using ColdMint.scripts.debug;
using ColdMint.scripts.inventory; using ColdMint.scripts.inventory;
using ColdMint.scripts.map; using ColdMint.scripts.map;
using ColdMint.scripts.map.interfaces;
using ColdMint.scripts.map.room; using ColdMint.scripts.map.room;
using ColdMint.scripts.map.roomHolder; using ColdMint.scripts.map.roomHolder;
using ColdMint.scripts.map.RoomPlacer; using ColdMint.scripts.map.RoomPlacer;
@ -15,8 +14,6 @@ namespace ColdMint.scripts.loader.sceneLoader;
public partial class GameSceneLoader : SceneLoaderTemplate public partial class GameSceneLoader : SceneLoaderTemplate
{ {
private IMapGenerator? _mapGenerator;
private IMapGeneratorConfig? _mapGeneratorConfig;
public override Task InitializeData() public override Task InitializeData()
{ {
@ -32,77 +29,11 @@ public partial class GameSceneLoader : SceneLoaderTemplate
//加载武器容器 //加载武器容器
var weaponContainer = GetNode<Node2D>("WeaponContainer"); var weaponContainer = GetNode<Node2D>("WeaponContainer");
GameSceneNodeHolder.WeaponContainer = 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<Node2D>("MapRoot"), 1);
roomPlacer.MapGeneratorConfig = _mapGeneratorConfig;
_mapGenerator.RoomPlacer = roomPlacer;
return Task.CompletedTask; return Task.CompletedTask;
} }
public override async Task LoadScene() 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<PackedScene>("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<Node2D>(".");
gameRoot.AddChild(node2D);
node2D.Position = new Vector2(55, 70);
var delivererOfDarkMagicPackedScene = GD.Load<PackedScene>("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<PackedScene>("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);
}
} }
} }

View File

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using ColdMint.scripts.debug;
using ColdMint.scripts.levelGraphEditor; using ColdMint.scripts.levelGraphEditor;
using ColdMint.scripts.nodeBinding;
using ColdMint.scripts.serialization; using ColdMint.scripts.serialization;
using ColdMint.scripts.utils; using ColdMint.scripts.utils;
using Godot; using Godot;
@ -17,41 +17,18 @@ namespace ColdMint.scripts.loader.uiLoader;
/// </summary> /// </summary>
public partial class LevelGraphEditorLoader : UiLoaderTemplate public partial class LevelGraphEditorLoader : UiLoaderTemplate
{ {
private GraphEdit? _graphEdit;
/// <summary>
/// <para>Button to display the room creation panel.</para>
/// <para>用于展示房间创建面板的按钮。</para>
/// </summary>
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 string? _defaultRoomName;
private readonly LevelGraphEditorBinding _nodeBinding = new LevelGraphEditorBinding();
/// <summary> /// <summary>
/// <para>Index of the room</para> /// <para>Index of the room</para>
/// <para>房间的索引</para> /// <para>房间的索引</para>
/// </summary> /// </summary>
private int _roomIndex = 1; private int _roomIndex = 1;
private TextEdit? _roomTemplateCollectionTextEdit; private PackedScene? _roomNodeScene;
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 readonly List<Node> _selectedNodes = new List<Node>(); private readonly List<Node> _selectedNodes = new List<Node>();
/// <summary> /// <summary>
@ -89,38 +66,18 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
public override void InitializeUi() public override void InitializeUi()
{ {
base.InitializeUi(); base.InitializeUi();
_roomTemplateTipsLabel = GetNode<Label>("CreateOrEditorPanel/RoomTemplateTipsLabel"); _nodeBinding.Binding(this);
if (_roomTemplateTipsLabel != null) if (_nodeBinding.OpenExportFolderButton != null)
{
_roomTemplateTipsLabel.Text = string.Empty;
}
_openExportFolderButton = GetNode<Button>("HBoxContainer/OpenExportFolderButton");
if (_openExportFolderButton != null)
{ {
//If open directories are supported, a button is displayed. //If open directories are supported, a button is displayed.
//若支持打开目录,那么显示按钮。 //若支持打开目录,那么显示按钮。
_openExportFolderButton.Visible = ExplorerUtils.SupportOpenDirectory(); _nodeBinding.OpenExportFolderButton.Visible = ExplorerUtils.SupportOpenDirectory();
} }
_showLoadPanelButton = GetNode<Button>("HBoxContainer/ShowLoadPanelButton"); if (_nodeBinding.RoomTemplateTipsLabel != null)
_saveOrLoadPanelTitleLabel = GetNode<Label>("SaveOrLoadPanel/SaveOrLoadPanelTitleLabel"); {
_saveOrLoadPanel = GetNode<Panel>("SaveOrLoadPanel"); _nodeBinding.RoomTemplateTipsLabel.Text = string.Empty;
_fileNameLineEdit = GetNode<LineEdit>("SaveOrLoadPanel/FileNameLineEdit"); }
_actionButton = GetNode<Button>("SaveOrLoadPanel/HBoxContainer/ActionButton");
_cancelButton = GetNode<Button>("SaveOrLoadPanel/HBoxContainer/CancelButton");
_hBoxContainer = GetNode<HBoxContainer>("HBoxContainer");
_showSavePanelButton = GetNode<Button>("HBoxContainer/ShowSavePanelButton");
_roomTemplateCollectionTextEdit = GetNode<TextEdit>("CreateOrEditorPanel/RoomTemplateCollectionTextEdit");
_graphEdit = GetNode<GraphEdit>("GraphEdit");
_deleteSelectedNodeButton = GetNode<Button>("HBoxContainer/DeleteSelectedNodeButton");
_showCreateRoomPanelButton = GetNode<Button>("HBoxContainer/ShowCreateRoomPanelButton");
_returnButton = GetNode<Button>("HBoxContainer/ReturnButton");
_createOrEditorPanel = GetNode<Panel>("CreateOrEditorPanel");
_hideCreateRoomPanelButton = GetNode<Button>("CreateOrEditorPanel/HideCreateRoomPanelButton");
_roomNameLineEdit = GetNode<LineEdit>("CreateOrEditorPanel/RoomNameLineEdit");
_roomDescriptionLineEdit = GetNode<LineEdit>("CreateOrEditorPanel/RoomDescriptionLineEdit");
_createRoomButton = GetNode<Button>("CreateOrEditorPanel/CreateRoomButton");
} }
/// <summary> /// <summary>
@ -131,7 +88,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
/// <returns></returns> /// <returns></returns>
private RoomNode? CreateRoomNode(RoomNodeData roomNodeData) private RoomNode? CreateRoomNode(RoomNodeData roomNodeData)
{ {
if (_roomNodeScene == null || _graphEdit == null) if (_roomNodeScene == null || _nodeBinding.GraphEdit == null)
{ {
return null; return null;
} }
@ -142,7 +99,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
return null; return null;
} }
_graphEdit?.AddChild(node); _nodeBinding.GraphEdit?.AddChild(node);
if (node is not RoomNode roomNode) if (node is not RoomNode roomNode)
{ {
return null; return null;
@ -160,22 +117,22 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
/// </summary> /// </summary>
private void DisplayInputPrompt() private void DisplayInputPrompt()
{ {
if (_roomTemplateTipsLabel == null || _roomTemplateCollectionTextEdit == null) if (_nodeBinding.RoomTemplateTipsLabel == null || _nodeBinding.RoomTemplateCollectionTextEdit == null)
{ {
return; return;
} }
var text = _roomTemplateCollectionTextEdit.Text; var text = _nodeBinding.RoomTemplateCollectionTextEdit.Text;
if (string.IsNullOrEmpty(text)) if (string.IsNullOrEmpty(text))
{ {
_roomTemplateTipsLabel.Text = string.Empty; _nodeBinding.RoomTemplateTipsLabel.Text = string.Empty;
return; return;
} }
var lastLine = StrUtils.GetLastLine(text); var lastLine = StrUtils.GetLastLine(text);
if (string.IsNullOrEmpty(lastLine)) if (string.IsNullOrEmpty(lastLine))
{ {
_roomTemplateTipsLabel.Text = string.Empty; _nodeBinding.RoomTemplateTipsLabel.Text = string.Empty;
return; return;
} }
@ -191,7 +148,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
return; return;
} }
_roomTemplateTipsLabel.Text = string.Format(lineError, lastLine); _nodeBinding.RoomTemplateTipsLabel.Text = string.Format(lineError, lastLine);
return; return;
} }
@ -205,11 +162,11 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
return; return;
} }
_roomTemplateTipsLabel.Text = string.Format(lineError, lastLine); _nodeBinding.RoomTemplateTipsLabel.Text = string.Format(lineError, lastLine);
return; return;
} }
_roomTemplateTipsLabel.Text = string.Empty; _nodeBinding.RoomTemplateTipsLabel.Text = string.Empty;
} }
} }
@ -228,45 +185,46 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
public override void LoadUiActions() public override void LoadUiActions()
{ {
base.LoadUiActions(); base.LoadUiActions();
if (_roomTemplateCollectionTextEdit != null) if (_nodeBinding.RoomTemplateCollectionTextEdit != null)
{ {
_roomTemplateCollectionTextEdit.TextChanged += () => _nodeBinding.RoomTemplateCollectionTextEdit.TextChanged += () =>
{ {
//Add anti-shake treatment. //Add anti-shake treatment.
//添加防抖处理。 //添加防抖处理。
//Higher frequency events are executed last time. //Higher frequency events are executed last time.
//频率较高的事件中,执行最后一次。 //频率较高的事件中,执行最后一次。
_displaysTheSuggestedInputTime = DateTime.Now.Add(TimeSpan.FromMilliseconds(Config.TextChangesBuffetingDuration)); _displaysTheSuggestedInputTime =
DateTime.Now.Add(TimeSpan.FromMilliseconds(Config.TextChangesBuffetingDuration));
}; };
} }
if (_graphEdit != null) if (_nodeBinding.GraphEdit != null)
{ {
_graphEdit.NodeSelected += node => { _selectedNodes.Add(node); }; _nodeBinding.GraphEdit.NodeSelected += node => { _selectedNodes.Add(node); };
_graphEdit.NodeDeselected += node => { _selectedNodes.Remove(node); }; _nodeBinding.GraphEdit.NodeDeselected += node => { _selectedNodes.Remove(node); };
_graphEdit.ConnectionRequest += (fromNode, fromPort, toNode, toPort) => _nodeBinding.GraphEdit.ConnectionRequest += (fromNode, fromPort, toNode, toPort) =>
{ {
_graphEdit.ConnectNode(fromNode, (int)fromPort, toNode, (int)toPort); _nodeBinding.GraphEdit.ConnectNode(fromNode, (int)fromPort, toNode, (int)toPort);
}; };
_graphEdit.DisconnectionRequest += (fromNode, fromPort, toNode, toPort) => _nodeBinding.GraphEdit.DisconnectionRequest += (fromNode, fromPort, toNode, toPort) =>
{ {
_graphEdit.DisconnectNode(fromNode, (int)fromPort, toNode, (int)toPort); _nodeBinding.GraphEdit.DisconnectNode(fromNode, (int)fromPort, toNode, (int)toPort);
}; };
} }
if (_openExportFolderButton != null) if (_nodeBinding.OpenExportFolderButton != null)
{ {
_openExportFolderButton.Pressed += () => _nodeBinding.OpenExportFolderButton.Pressed += () =>
{ {
ExplorerUtils.OpenFolder(Config.GetLevelGraphExportDirectory()); ExplorerUtils.OpenFolder(Config.GetLevelGraphExportDirectory());
}; };
} }
if (_deleteSelectedNodeButton != null) if (_nodeBinding.DeleteSelectedNodeButton != null)
{ {
_deleteSelectedNodeButton.Pressed += () => _nodeBinding.DeleteSelectedNodeButton.Pressed += () =>
{ {
if (_graphEdit == null) if (_nodeBinding.GraphEdit == null)
{ {
return; return;
} }
@ -284,63 +242,63 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
continue; continue;
} }
_graphEdit.RemoveChild(node); _nodeBinding.GraphEdit.RemoveChild(node);
roomNode.QueueFree(); roomNode.QueueFree();
_selectedNodes.Remove(node); _selectedNodes.Remove(node);
} }
}; };
} }
if (_showCreateRoomPanelButton != null) if (_nodeBinding.ShowCreateRoomPanelButton != null)
{ {
_showCreateRoomPanelButton.Pressed += () => _nodeBinding.ShowCreateRoomPanelButton.Pressed += () =>
{ {
if (_graphEdit != null) if (_nodeBinding.GraphEdit != null)
{ {
_graphEdit.Visible = false; _nodeBinding.GraphEdit.Visible = false;
} }
if (_createOrEditorPanel != null) if (_nodeBinding.CreateOrEditorPanel != null)
{ {
_createOrEditorPanel.Visible = true; _nodeBinding.CreateOrEditorPanel.Visible = true;
} }
if (_roomNameLineEdit != null && _defaultRoomName != null) if (_nodeBinding.RoomNameLineEdit != null && _defaultRoomName != null)
{ {
_roomNameLineEdit.Text = string.Format(_defaultRoomName, _roomIndex); _nodeBinding.RoomNameLineEdit.Text = string.Format(_defaultRoomName, _roomIndex);
} }
if (_hBoxContainer != null) if (_nodeBinding.HBoxContainer != null)
{ {
_hBoxContainer.Visible = false; _nodeBinding.HBoxContainer.Visible = false;
} }
}; };
} }
if (_returnButton != null) if (_nodeBinding.ReturnButton != null)
{ {
_returnButton.Pressed += () => _nodeBinding.ReturnButton.Pressed += () =>
{ {
GetTree().ChangeSceneToPacked((PackedScene)GD.Load("res://scenes/mainMenu.tscn")); GetTree().ChangeSceneToPacked((PackedScene)GD.Load("res://scenes/mainMenu.tscn"));
}; };
} }
if (_hideCreateRoomPanelButton != null) if (_nodeBinding.HideCreateRoomPanelButton != null)
{ {
_hideCreateRoomPanelButton.Pressed += HideCreateRoomPanel; _nodeBinding.HideCreateRoomPanelButton.Pressed += HideCreateRoomPanel;
} }
if (_createRoomButton != null) if (_nodeBinding.CreateRoomButton != null)
{ {
_createRoomButton.Pressed += () => _nodeBinding.CreateRoomButton.Pressed += () =>
{ {
if (_roomNameLineEdit == null || _roomDescriptionLineEdit == null || if (_nodeBinding.RoomNameLineEdit == null || _nodeBinding.RoomDescriptionLineEdit == null ||
_roomTemplateCollectionTextEdit == null) _nodeBinding.RoomTemplateCollectionTextEdit == null)
{ {
return; return;
} }
var roomTemplateData = _roomTemplateCollectionTextEdit.Text; var roomTemplateData = _nodeBinding.RoomTemplateCollectionTextEdit.Text;
if (string.IsNullOrEmpty(roomTemplateData)) if (string.IsNullOrEmpty(roomTemplateData))
{ {
return; return;
@ -355,8 +313,8 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
var roomNodeData = new RoomNodeData var roomNodeData = new RoomNodeData
{ {
Id = GuidUtils.GetGuid(), Id = GuidUtils.GetGuid(),
Title = _roomNameLineEdit.Text, Title = _nodeBinding.RoomNameLineEdit.Text,
Description = _roomDescriptionLineEdit.Text, Description = _nodeBinding.RoomDescriptionLineEdit.Text,
RoomTemplateSet = roomTemplateArray RoomTemplateSet = roomTemplateArray
}; };
var roomNode = CreateRoomNode(roomNodeData); var roomNode = CreateRoomNode(roomNodeData);
@ -367,94 +325,94 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
}; };
} }
if (_cancelButton != null) if (_nodeBinding.CancelButton != null)
{ {
_cancelButton.Pressed += () => _nodeBinding.CancelButton.Pressed += () =>
{ {
if (_saveOrLoadPanel != null) if (_nodeBinding.SaveOrLoadPanel != null)
{ {
_saveOrLoadPanel.Visible = false; _nodeBinding.SaveOrLoadPanel.Visible = false;
} }
}; };
} }
if (_actionButton != null) if (_nodeBinding.ActionButton != null)
{ {
_actionButton.Pressed += () => _nodeBinding.ActionButton.Pressed += () =>
{ {
if (_saveOrLoadPanel != null) if (_nodeBinding.SaveOrLoadPanel != null)
{ {
_saveOrLoadPanel.Visible = false; _nodeBinding.SaveOrLoadPanel.Visible = false;
} }
}; };
} }
if (_showLoadPanelButton != null) if (_nodeBinding.ShowLoadPanelButton != null)
{ {
_showLoadPanelButton.Pressed += () => _nodeBinding.ShowLoadPanelButton.Pressed += () =>
{ {
if (_saveOrLoadPanel != null) if (_nodeBinding.SaveOrLoadPanel != null)
{ {
_saveOrLoadPanel.Visible = true; _nodeBinding.SaveOrLoadPanel.Visible = true;
} }
if (_actionButton != null) if (_nodeBinding.ActionButton != null)
{ {
_actionButton.Text = TranslationServer.Translate("load"); _nodeBinding.ActionButton.Text = TranslationServer.Translate("load");
} }
if (_fileNameLineEdit != null) if (_nodeBinding.FileNameLineEdit != null)
{ {
_fileNameLineEdit.Text = string.Empty; _nodeBinding.FileNameLineEdit.Text = string.Empty;
} }
if (_saveOrLoadPanelTitleLabel != null) if (_nodeBinding.SaveOrLoadPanelTitleLabel != null)
{ {
_saveOrLoadPanelTitleLabel.Text = TranslationServer.Translate("load"); _nodeBinding.SaveOrLoadPanelTitleLabel.Text = TranslationServer.Translate("load");
} }
_saveMode = false; _saveMode = false;
}; };
} }
if (_showSavePanelButton != null) if (_nodeBinding.ShowSavePanelButton != null)
{ {
_showSavePanelButton.Pressed += () => _nodeBinding.ShowSavePanelButton.Pressed += () =>
{ {
if (_saveOrLoadPanel != null) if (_nodeBinding.SaveOrLoadPanel != null)
{ {
_saveOrLoadPanel.Visible = true; _nodeBinding.SaveOrLoadPanel.Visible = true;
} }
if (_actionButton != null) if (_nodeBinding.ActionButton != null)
{ {
_actionButton.Text = TranslationServer.Translate("save"); _nodeBinding.ActionButton.Text = TranslationServer.Translate("save");
} }
if (_fileNameLineEdit != null) if (_nodeBinding.FileNameLineEdit != null)
{ {
_fileNameLineEdit.Text = string.Empty; _nodeBinding.FileNameLineEdit.Text = string.Empty;
} }
if (_saveOrLoadPanelTitleLabel != null) if (_nodeBinding.SaveOrLoadPanelTitleLabel != null)
{ {
_saveOrLoadPanelTitleLabel.Text = TranslationServer.Translate("save"); _nodeBinding.SaveOrLoadPanelTitleLabel.Text = TranslationServer.Translate("save");
} }
_saveMode = true; _saveMode = true;
}; };
} }
if (_actionButton != null) if (_nodeBinding.ActionButton != null)
{ {
_actionButton.Pressed += () => _nodeBinding.ActionButton.Pressed += () =>
{ {
if (_fileNameLineEdit == null) if (_nodeBinding.FileNameLineEdit == null)
{ {
return; return;
} }
var fileName = _fileNameLineEdit.Text; var fileName = _nodeBinding.FileNameLineEdit.Text;
if (string.IsNullOrEmpty(fileName)) if (string.IsNullOrEmpty(fileName))
{ {
return; return;
@ -484,7 +442,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
/// </param> /// </param>
private async void SaveFile(string fileName) private async void SaveFile(string fileName)
{ {
if (_graphEdit == null) if (_nodeBinding.GraphEdit == null)
{ {
return; return;
} }
@ -492,7 +450,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
var levelGraphEditorSaveData = new LevelGraphEditorSaveData(); var levelGraphEditorSaveData = new LevelGraphEditorSaveData();
//Serialize room node information //Serialize room node information
//序列化房间节点信息 //序列化房间节点信息
var length = _graphEdit.GetChildCount(); var length = _nodeBinding.GraphEdit.GetChildCount();
if (length <= 0) if (length <= 0)
{ {
//no room //no room
@ -504,7 +462,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
levelGraphEditorSaveData.RoomNodeDataList = roomNodeDataList; levelGraphEditorSaveData.RoomNodeDataList = roomNodeDataList;
for (var i = 0; i < length; i++) for (var i = 0; i < length; i++)
{ {
var node = _graphEdit.GetChild(i); var node = _nodeBinding.GraphEdit.GetChild(i);
if (node is not RoomNode roomNode) continue; if (node is not RoomNode roomNode) continue;
var data = roomNode.RoomNodeData; var data = roomNode.RoomNodeData;
if (data == null) if (data == null)
@ -517,7 +475,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
//Serialized connection information //Serialized connection information
//序列化连接信息 //序列化连接信息
Array<Dictionary> connectionList = _graphEdit.GetConnectionList(); Array<Dictionary> connectionList = _nodeBinding.GraphEdit.GetConnectionList();
var connectionDataList = new List<ConnectionData>(); var connectionDataList = new List<ConnectionData>();
levelGraphEditorSaveData.ConnectionDataList = connectionDataList; levelGraphEditorSaveData.ConnectionDataList = connectionDataList;
if (connectionList.Count > 0) if (connectionList.Count > 0)
@ -603,7 +561,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
private async void LoadFile(string fileName) private async void LoadFile(string fileName)
{ {
if (_graphEdit == null) if (_nodeBinding.GraphEdit == null)
{ {
return; return;
} }
@ -627,7 +585,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
//Do not call DeleteAllChildAsync; this will raise "ERROR: Caller thread can't call this function in this node." //Do not call DeleteAllChildAsync; this will raise "ERROR: Caller thread can't call this function in this node."
//不要调用DeleteAllChildAsync方法这会引发“ERROR: Caller thread can't call this function in this node”。 //不要调用DeleteAllChildAsync方法这会引发“ERROR: Caller thread can't call this function in this node”。
NodeUtils.DeleteAllChild(_graphEdit); NodeUtils.DeleteAllChild(_nodeBinding.GraphEdit);
_roomIndex = 1; _roomIndex = 1;
var roomNodeDataList = levelGraphEditorSaveData.RoomNodeDataList; var roomNodeDataList = levelGraphEditorSaveData.RoomNodeDataList;
if (roomNodeDataList != null) if (roomNodeDataList != null)
@ -666,7 +624,7 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
//Connecting rooms //Connecting rooms
//连接房间 //连接房间
_graphEdit.ConnectNode(connectionData.FromId, connectionData.FromPort, connectionData.ToId, _nodeBinding.GraphEdit?.ConnectNode(connectionData.FromId, connectionData.FromPort, connectionData.ToId,
connectionData.ToPort); connectionData.ToPort);
} }
} }
@ -683,12 +641,12 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
/// <returns></returns> /// <returns></returns>
private RoomNodeData? GetRoomNodeData(string name) private RoomNodeData? GetRoomNodeData(string name)
{ {
if (_graphEdit == null) if (_nodeBinding.GraphEdit == null)
{ {
return null; return null;
} }
var roomNode = _graphEdit.GetNodeOrNull<RoomNode>(name); var roomNode = _nodeBinding.GraphEdit.GetNodeOrNull<RoomNode>(name);
if (roomNode == null) if (roomNode == null)
{ {
return null; return null;
@ -704,19 +662,19 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate
/// </summary> /// </summary>
private void HideCreateRoomPanel() 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;
} }
} }
} }

View File

@ -0,0 +1,14 @@
using System.Threading.Tasks;
using ColdMint.scripts.levelGraphEditor;
namespace ColdMint.scripts.map;
public interface ILayoutStrategy
{
/// <summary>
/// <para>Get layout</para>
/// <para>获取布局图</para>
/// </summary>
/// <returns></returns>
public Task<LevelGraphEditorSaveData> GetLayout();
}

View File

@ -1,110 +1,60 @@
using System; using System.Threading.Tasks;
using System.Threading.Tasks; using ColdMint.scripts.levelGraphEditor;
using ColdMint.scripts.debug;
using ColdMint.scripts.map.interfaces;
using ColdMint.scripts.map.room;
using ColdMint.scripts.map.RoomPlacer;
using Godot;
namespace ColdMint.scripts.map; namespace ColdMint.scripts.map;
public class MapGenerator : IMapGenerator /// <summary>
/// <para>Map generator</para>
/// <para>地图生成器</para>
/// </summary>
/// <remarks>
///<para>Responsible for the overall map generation process control</para>
///<para>负责地图的整体生成流程控制</para>
/// </remarks>
public static class MapGenerator
{ {
public int TimeOutPeriod { get; set; } /// <summary>
public IRoomSlotsMatcher? RoomSlotsMatcher { get; set; } /// <para>Layout map selection strategy</para>
public IRoomHolder? RoomHolder { get; set; } /// <para>布局图选择策略</para>
/// </summary>
private static ILayoutStrategy? _layoutStrategy;
public IRoomPlacer? RoomPlacer { get; set; } public static ILayoutStrategy? LayoutStrategy
public IRoomProvider? RoomProvider { get; set; }
public async Task Generate(IMapGeneratorConfig mapGeneratorConfig)
{ {
if (RoomPlacer == null || RoomHolder == null || RoomProvider == null || RoomSlotsMatcher == null || get => _layoutStrategy;
RoomProvider.InitialRoom == null) set => _layoutStrategy = value;
}
/// <summary>
/// <para>Generating a map</para>
/// <para>生成地图</para>
/// </summary>
public static async Task GenerateMap()
{
if (_layoutStrategy == null)
{ {
PrintMissingParametersError();
return; 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(); return;
//获取原点
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);
}
}
/// <summary>
/// <para>PrintMissingParametersError</para>
/// <para>打印缺少参数错误</para>
/// </summary>
private void PrintMissingParametersError()
{
LogCat.LogError("missing_parameters");
}
/// <summary>
/// <para>PlaceRoom</para>
/// <para>放置房间</para>
/// </summary>
/// <param name="position"></param>
/// <param name="room"></param>
/// <returns></returns>
private async Task<bool> PlaceRoom(Vector2 position, IRoom room)
{
if (RoomPlacer == null || RoomHolder == null)
{
return false;
} }
if (await RoomPlacer.PlaceRoom(position, room)) var startRoomNodeData = levelGraphEditorSaveData.RoomNodeDataList.Find(roomNodeData =>
roomNodeData.HasTag(Config.RoomDataTag.StartingRoom));
if (startRoomNodeData == null)
{ {
RoomHolder.AddRoom(room); //Can't find the starting room
// LogCat.Log("我要放置房间,但是成功"); //找不到起点房间
return true; return;
} }
//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.
// LogCat.Log("我要放置房间,但是失败了"); //TODO:将起点房间看作根节点,像树结构一样,从根节点到叶节点生成地图。
return false;
} }
} }

View File

@ -1,24 +0,0 @@
using System.Threading.Tasks;
namespace ColdMint.scripts.map.interfaces;
public interface IMapGenerator
{
/// <summary>
/// <para>Setting the timeout period</para>
/// <para>设置超时时间</para>
/// </summary>
/// <remarks>
///<para>Causes the engine to terminate generation after a certain amount of time.(Unit: second)</para>
///<para>使引擎超过一定时间后终止生成。(单位:秒)</para>
/// </remarks>
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);
}

View File

@ -0,0 +1,12 @@
using Godot;
namespace ColdMint.scripts.nodeBinding;
/// <summary>
/// <para>Node binding</para>
/// <para>节点绑定</para>
/// </summary>
public interface INodeBinding
{
void Binding(Node root);
}

View File

@ -0,0 +1,56 @@
using Godot;
namespace ColdMint.scripts.nodeBinding;
public class LevelGraphEditorBinding : INodeBinding
{
public GraphEdit? GraphEdit;
/// <summary>
/// <para>Button to display the room creation panel.</para>
/// <para>用于展示房间创建面板的按钮。</para>
/// </summary>
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<Label>("CreateOrEditorPanel/RoomTemplateTipsLabel");
OpenExportFolderButton = root.GetNode<Button>("HBoxContainer/OpenExportFolderButton");
ShowLoadPanelButton = root.GetNode<Button>("HBoxContainer/ShowLoadPanelButton");
SaveOrLoadPanelTitleLabel = root.GetNode<Label>("SaveOrLoadPanel/SaveOrLoadPanelTitleLabel");
SaveOrLoadPanel = root.GetNode<Panel>("SaveOrLoadPanel");
FileNameLineEdit = root.GetNode<LineEdit>("SaveOrLoadPanel/FileNameLineEdit");
ActionButton = root.GetNode<Button>("SaveOrLoadPanel/HBoxContainer/ActionButton");
CancelButton = root.GetNode<Button>("SaveOrLoadPanel/HBoxContainer/CancelButton");
HBoxContainer = root.GetNode<HBoxContainer>("HBoxContainer");
ShowSavePanelButton = root.GetNode<Button>("HBoxContainer/ShowSavePanelButton");
RoomTemplateCollectionTextEdit = root.GetNode<TextEdit>("CreateOrEditorPanel/RoomTemplateCollectionTextEdit");
GraphEdit = root.GetNode<GraphEdit>("GraphEdit");
DeleteSelectedNodeButton = root.GetNode<Button>("HBoxContainer/DeleteSelectedNodeButton");
ShowCreateRoomPanelButton = root.GetNode<Button>("HBoxContainer/ShowCreateRoomPanelButton");
ReturnButton = root.GetNode<Button>("HBoxContainer/ReturnButton");
CreateOrEditorPanel = root.GetNode<Panel>("CreateOrEditorPanel");
HideCreateRoomPanelButton = root.GetNode<Button>("CreateOrEditorPanel/HideCreateRoomPanelButton");
RoomNameLineEdit = root.GetNode<LineEdit>("CreateOrEditorPanel/RoomNameLineEdit");
RoomDescriptionLineEdit = root.GetNode<LineEdit>("CreateOrEditorPanel/RoomDescriptionLineEdit");
CreateRoomButton = root.GetNode<Button>("CreateOrEditorPanel/CreateRoomButton");
}
}

View File

@ -54,8 +54,6 @@ public class ExplorerUtils
}; };
Process.Start(startInfoAndroid); Process.Start(startInfoAndroid);
break; break;
default:
throw new NotImplementedException($"No implementation for OS: {osEnum}");
} }
} }