Add sequential layout diagram parsing policies.
添加顺序的布局图解析策略。
This commit is contained in:
parent
b5b79eccc1
commit
dd2577cfd0
83
data/levelGraphs/test.json
Normal file
83
data/levelGraphs/test.json
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
{
|
||||||
|
"ConnectionDataList": [
|
||||||
|
{
|
||||||
|
"FromId": "c0255eb6-2c75-44f7-9058-0921fe8fb0d8",
|
||||||
|
"ToId": "4ae948ea-82b7-4b2d-bec2-19ed8a9d4c03",
|
||||||
|
"FromPort": 0,
|
||||||
|
"ToPort": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FromId": "4ae948ea-82b7-4b2d-bec2-19ed8a9d4c03",
|
||||||
|
"ToId": "c604e1ef-f3e7-4189-a6f7-ab2bd23d5130",
|
||||||
|
"FromPort": 0,
|
||||||
|
"ToPort": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FromId": "4ae948ea-82b7-4b2d-bec2-19ed8a9d4c03",
|
||||||
|
"ToId": "bb9da3f9-911f-465f-af2e-be1325f17d15",
|
||||||
|
"FromPort": 0,
|
||||||
|
"ToPort": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FromId": "c604e1ef-f3e7-4189-a6f7-ab2bd23d5130",
|
||||||
|
"ToId": "c9e860b9-e001-4b9b-9e6d-adf132beb64f",
|
||||||
|
"FromPort": 0,
|
||||||
|
"ToPort": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FromId": "bb9da3f9-911f-465f-af2e-be1325f17d15",
|
||||||
|
"ToId": "c9e860b9-e001-4b9b-9e6d-adf132beb64f",
|
||||||
|
"FromPort": 0,
|
||||||
|
"ToPort": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"RoomNodeDataList": [
|
||||||
|
{
|
||||||
|
"Id": "c0255eb6-2c75-44f7-9058-0921fe8fb0d8",
|
||||||
|
"Title": "起点房间",
|
||||||
|
"Description": "测试的起点房间。",
|
||||||
|
"RoomTemplateSet": [
|
||||||
|
"res://prefab/roomTemplates/dungeon/initialRoom.tscn"
|
||||||
|
],
|
||||||
|
"Tags": [
|
||||||
|
"StartingRoom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "4ae948ea-82b7-4b2d-bec2-19ed8a9d4c03",
|
||||||
|
"Title": "大厅",
|
||||||
|
"Description": "比普通房间要大一些的房间,有多个门,用于连接到其他房间。",
|
||||||
|
"RoomTemplateSet": [
|
||||||
|
"res://prefab/roomTemplates/dungeon/utilityRoom.tscn"
|
||||||
|
],
|
||||||
|
"Tags": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "c604e1ef-f3e7-4189-a6f7-ab2bd23d5130",
|
||||||
|
"Title": "普通房间1",
|
||||||
|
"Description": "测试使用。",
|
||||||
|
"RoomTemplateSet": [
|
||||||
|
"res://prefab/roomTemplates/dungeon"
|
||||||
|
],
|
||||||
|
"Tags": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "bb9da3f9-911f-465f-af2e-be1325f17d15",
|
||||||
|
"Title": "普通房间2",
|
||||||
|
"Description": "测试使用。",
|
||||||
|
"RoomTemplateSet": [
|
||||||
|
"res://prefab/roomTemplates/dungeon"
|
||||||
|
],
|
||||||
|
"Tags": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "c9e860b9-e001-4b9b-9e6d-adf132beb64f",
|
||||||
|
"Title": "Boos房间",
|
||||||
|
"Description": "关卡结束的地方。",
|
||||||
|
"RoomTemplateSet": [
|
||||||
|
"res://prefab/roomTemplates/dungeon"
|
||||||
|
],
|
||||||
|
"Tags": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ 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.LayoutParsingStrategy;
|
||||||
|
using ColdMint.scripts.map.layoutStrategy;
|
||||||
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;
|
||||||
|
@ -34,6 +36,7 @@ public partial class GameSceneLoader : SceneLoaderTemplate
|
||||||
|
|
||||||
public override async Task LoadScene()
|
public override async Task LoadScene()
|
||||||
{
|
{
|
||||||
|
MapGenerator.LayoutStrategy = new TestLayoutStrategy();
|
||||||
|
MapGenerator.LayoutParsingStrategy = new SequenceLayoutParsingStrategy();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ using Godot;
|
||||||
namespace ColdMint.scripts.loader.sceneLoader;
|
namespace ColdMint.scripts.loader.sceneLoader;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>场景加载器模板</para>
|
/// <para>The scene loader template</para>
|
||||||
/// <para>场景加载器模板</para>
|
/// <para>场景加载器模板</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class SceneLoaderTemplate : Node2D, ISceneLoaderContract
|
public partial class SceneLoaderTemplate : Node2D, ISceneLoaderContract
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ColdMint.scripts.levelGraphEditor;
|
using ColdMint.scripts.levelGraphEditor;
|
||||||
|
|
||||||
namespace ColdMint.scripts.map;
|
namespace ColdMint.scripts.map.LayoutParsingStrategy;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Layout parsing strategy</para>
|
/// <para>Layout parsing strategy</para>
|
|
@ -0,0 +1,215 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ColdMint.scripts.levelGraphEditor;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.map.LayoutParsingStrategy;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Sequential layout diagram parsing strategy</para>
|
||||||
|
/// <para>顺序的布局图解析策略</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
///<para>Traverse from the start element to the end element according to the ConnectionDataList. This policy considers the first element of the ConnectionDataList to be the fixed starting room information.</para>
|
||||||
|
///<para>按照ConnectionDataList从起始元素遍历到末项元素。本策略认为ConnectionDataList的首个元素为固定的起始房间信息。</para>
|
||||||
|
/// <para></para>
|
||||||
|
/// <para>This policy's Next() method does not return rooms that are not connected except for the start room</para>
|
||||||
|
/// <para>本策略Next()方法不会返回除了起始房间外,没有连接的房间</para>
|
||||||
|
/// </remarks>
|
||||||
|
public class SequenceLayoutParsingStrategy : ILayoutParsingStrategy
|
||||||
|
{
|
||||||
|
private LevelGraphEditorSaveData? _levelGraphEditorSaveData;
|
||||||
|
|
||||||
|
//Check whether data Settings are valid
|
||||||
|
//设置数据时,是否检查合法了
|
||||||
|
private bool _checkLegality;
|
||||||
|
|
||||||
|
//A special marker for the starting room.
|
||||||
|
//特殊标记,代表起始房间。
|
||||||
|
private const int StartingRoomIndex = -1;
|
||||||
|
|
||||||
|
//The connection index of the query
|
||||||
|
//查询的连接索引
|
||||||
|
private int _index = StartingRoomIndex;
|
||||||
|
private int _maxIndex;
|
||||||
|
private Dictionary<string, RoomNodeData> _roomNodeDataDictionary = new Dictionary<string, RoomNodeData>();
|
||||||
|
|
||||||
|
public void SetLevelGraph(LevelGraphEditorSaveData levelGraphEditorSaveData)
|
||||||
|
{
|
||||||
|
_index = StartingRoomIndex;
|
||||||
|
_levelGraphEditorSaveData = levelGraphEditorSaveData;
|
||||||
|
if (_levelGraphEditorSaveData.RoomNodeDataList == null || _levelGraphEditorSaveData.RoomNodeDataList.Count == 0)
|
||||||
|
{
|
||||||
|
//No room data, unable to parse.
|
||||||
|
//没有房间数据,无法解析。
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_levelGraphEditorSaveData.ConnectionDataList == null ||
|
||||||
|
_levelGraphEditorSaveData.ConnectionDataList.Count == 0)
|
||||||
|
{
|
||||||
|
_maxIndex = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_maxIndex = _levelGraphEditorSaveData.ConnectionDataList.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_roomNodeDataDictionary.Clear();
|
||||||
|
foreach (var roomNodeData in _levelGraphEditorSaveData.RoomNodeDataList)
|
||||||
|
{
|
||||||
|
if (roomNodeData.Id == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_roomNodeDataDictionary.Add(roomNodeData.Id, roomNodeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check that the first room is the starting room.
|
||||||
|
//检查首个房间是否为起始房间。
|
||||||
|
var firstRoom = GetFirstRoom(_levelGraphEditorSaveData);
|
||||||
|
if (firstRoom == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkLegality = firstRoom.HasTag(Config.RoomDataTag.StartingRoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Get the first room</para>
|
||||||
|
/// <para>获取第一个房间</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="levelGraphEditorSaveData"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private RoomNodeData? GetFirstRoom(LevelGraphEditorSaveData? levelGraphEditorSaveData)
|
||||||
|
{
|
||||||
|
if (levelGraphEditorSaveData == null || levelGraphEditorSaveData.RoomNodeDataList == null ||
|
||||||
|
levelGraphEditorSaveData.RoomNodeDataList.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomNodeData? firstRoom = null;
|
||||||
|
if (levelGraphEditorSaveData.ConnectionDataList == null ||
|
||||||
|
levelGraphEditorSaveData.ConnectionDataList.Count == 0)
|
||||||
|
{
|
||||||
|
//If there is no connection information, then fetch the first room in the RoomNodeDataList.
|
||||||
|
//如果没有连接信息,那么在RoomNodeDataList内取出第一个房间。
|
||||||
|
firstRoom = levelGraphEditorSaveData.RoomNodeDataList[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//If there is connection information, then fetch the first connected From room in the ConnectionDataList.
|
||||||
|
//如果有连接信息,那么在ConnectionDataList内取出第一个连接的From房间。
|
||||||
|
var firstConnection = levelGraphEditorSaveData.ConnectionDataList[0];
|
||||||
|
if (firstConnection.FromId == null)
|
||||||
|
{
|
||||||
|
return firstRoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_roomNodeDataDictionary.TryGetValue(firstConnection.FromId, out var value))
|
||||||
|
{
|
||||||
|
firstRoom = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstRoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<RoomNodeData?> Next()
|
||||||
|
{
|
||||||
|
if (_index == StartingRoomIndex)
|
||||||
|
{
|
||||||
|
return Task.FromResult(GetFirstRoom(_levelGraphEditorSaveData));
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectionData = GetIndexOfConnectionData(_index);
|
||||||
|
if (connectionData == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<RoomNodeData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectionData.ToId == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<RoomNodeData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_roomNodeDataDictionary.TryGetValue(connectionData.ToId, out var value))
|
||||||
|
{
|
||||||
|
return Task.FromResult<RoomNodeData?>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult<RoomNodeData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Gets connection information for the specified location</para>
|
||||||
|
/// <para>获取指定位置的连接信息</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private ConnectionData? GetIndexOfConnectionData(int index)
|
||||||
|
{
|
||||||
|
if (_levelGraphEditorSaveData == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_levelGraphEditorSaveData.ConnectionDataList == null ||
|
||||||
|
_levelGraphEditorSaveData.ConnectionDataList.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _levelGraphEditorSaveData.ConnectionDataList[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string?> GetNextParentNodeId()
|
||||||
|
{
|
||||||
|
if (_index == StartingRoomIndex)
|
||||||
|
{
|
||||||
|
//The start room will not have a parent node.
|
||||||
|
//起始房间不会有父节点。
|
||||||
|
return Task.FromResult<string?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectionData = GetIndexOfConnectionData(_index);
|
||||||
|
if (connectionData == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<string?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectionData.FromId == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<string?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_roomNodeDataDictionary.ContainsKey(connectionData.FromId))
|
||||||
|
{
|
||||||
|
return Task.FromResult<string?>(connectionData.FromId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult<string?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> HasNext()
|
||||||
|
{
|
||||||
|
if (!_checkLegality)
|
||||||
|
{
|
||||||
|
//If the check is not valid, then simply return false
|
||||||
|
//如果检查不合法,那么直接返回false
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_index == StartingRoomIndex)
|
||||||
|
{
|
||||||
|
//The start room is always considered to have the next room, in order to handle situations where levelGraphEditorSaveData has only room data and no connection data.
|
||||||
|
//起始房间始终被认为有下一个房间,这是为了处理levelGraphEditorSaveData仅有房间数据,没有连接数据的情况。
|
||||||
|
_index++;
|
||||||
|
return Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(_index < _maxIndex);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ColdMint.scripts.debug;
|
using ColdMint.scripts.debug;
|
||||||
using ColdMint.scripts.map.interfaces;
|
using ColdMint.scripts.map.interfaces;
|
||||||
|
using ColdMint.scripts.map.LayoutParsingStrategy;
|
||||||
|
using ColdMint.scripts.map.layoutStrategy;
|
||||||
|
|
||||||
namespace ColdMint.scripts.map;
|
namespace ColdMint.scripts.map;
|
||||||
|
|
||||||
|
@ -67,7 +69,8 @@ public static class MapGenerator
|
||||||
//Get the layout data
|
//Get the layout data
|
||||||
//拿到布局图数据
|
//拿到布局图数据
|
||||||
var levelGraphEditorSaveData = await _layoutStrategy.GetLayout();
|
var levelGraphEditorSaveData = await _layoutStrategy.GetLayout();
|
||||||
if (levelGraphEditorSaveData.RoomNodeDataList == null || levelGraphEditorSaveData.RoomNodeDataList.Count == 0)
|
if (levelGraphEditorSaveData == null || levelGraphEditorSaveData.RoomNodeDataList == null ||
|
||||||
|
levelGraphEditorSaveData.RoomNodeDataList.Count == 0)
|
||||||
{
|
{
|
||||||
LogCat.LogError("map_generator_attempts_to_parse_empty_layout_diagrams");
|
LogCat.LogError("map_generator_attempts_to_parse_empty_layout_diagrams");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ColdMint.scripts.levelGraphEditor;
|
using ColdMint.scripts.levelGraphEditor;
|
||||||
|
|
||||||
namespace ColdMint.scripts.map;
|
namespace ColdMint.scripts.map.layoutStrategy;
|
||||||
|
|
||||||
public interface ILayoutStrategy
|
public interface ILayoutStrategy
|
||||||
{
|
{
|
||||||
|
@ -10,5 +10,5 @@ public interface ILayoutStrategy
|
||||||
/// <para>获取布局图</para>
|
/// <para>获取布局图</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<LevelGraphEditorSaveData> GetLayout();
|
public Task<LevelGraphEditorSaveData?> GetLayout();
|
||||||
}
|
}
|
32
scripts/map/layoutStrategy/TestLayoutStrategy.cs
Normal file
32
scripts/map/layoutStrategy/TestLayoutStrategy.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ColdMint.scripts.levelGraphEditor;
|
||||||
|
using ColdMint.scripts.serialization;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.map.layoutStrategy;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Layout selection strategy to use at test time</para>
|
||||||
|
/// <para>测试时使用的布局选择策略</para>
|
||||||
|
/// </summary>
|
||||||
|
public class TestLayoutStrategy : ILayoutStrategy
|
||||||
|
{
|
||||||
|
private string _path = "res://data/levelGraphs/test.json";
|
||||||
|
|
||||||
|
public Task<LevelGraphEditorSaveData?> GetLayout()
|
||||||
|
{
|
||||||
|
var exists = FileAccess.FileExists(_path);
|
||||||
|
if (!exists)
|
||||||
|
{
|
||||||
|
return Task.FromResult<LevelGraphEditorSaveData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var json = FileAccess.GetFileAsString(_path);
|
||||||
|
if (json == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<LevelGraphEditorSaveData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(JsonSerialization.Deserialize<LevelGraphEditorSaveData>(json));
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,18 @@ public static class JsonSerialization
|
||||||
return JsonSerializer.Serialize(obj, _options);
|
return JsonSerializer.Serialize(obj, _options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Deserialize Json to an object</para>
|
||||||
|
/// <para>将Json反序列化为对象</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json"></param>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T? Deserialize<T>(string json)
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<T>(json, _options);
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<T?> ReadJsonFileToObj<T>(Stream openStream)
|
public static async Task<T?> ReadJsonFileToObj<T>(Stream openStream)
|
||||||
{
|
{
|
||||||
return await JsonSerializer.DeserializeAsync<T>(openStream, _options);
|
return await JsonSerializer.DeserializeAsync<T>(openStream, _options);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user