diff --git a/data/levelGraphs/test.json b/data/levelGraphs/test.json
index 556d872..4682698 100644
--- a/data/levelGraphs/test.json
+++ b/data/levelGraphs/test.json
@@ -5,30 +5,6 @@
"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": [
@@ -37,7 +13,7 @@
"Title": "起点房间",
"Description": "测试的起点房间。",
"RoomTemplateSet": [
- "res://prefab/roomTemplates/dungeon/initialRoom.tscn"
+ "res://prefab/roomTemplates/dungeon"
],
"Tags": [
"StartingRoom"
@@ -51,33 +27,6 @@
"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
}
]
}
\ No newline at end of file
diff --git a/locals/Error.csv b/locals/Error.csv
index add28cc..5fb7974 100644
--- a/locals/Error.csv
+++ b/locals/Error.csv
@@ -6,4 +6,5 @@ width_or_height_of_room_slot_must_be_1,房间槽的宽度或高度必须为1。,
connected_room_timeout,连接房间超时。,Connecting the room timed out.,接続部屋はタイムアウトです。
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
+map_generator_attempts_to_parse_empty_layout_diagrams,地图生成器尝试解析空的布局图。,Map generator attempts to parse empty layout diagrams.,マップジェネレータは空のレイアウト図を解析しようとしています。
+map_generator_has_no_starting_room_data,地图生成器没有起点房间数据。,Map generator has no starting room data.,マップ生成器に起点部屋データはありません。
\ No newline at end of file
diff --git a/locals/Error.en.translation b/locals/Error.en.translation
index 262938c..64b0440 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 50361d6..1192517 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 6e08a5e..b15f408 100644
Binary files a/locals/Error.zh.translation and b/locals/Error.zh.translation differ
diff --git a/scripts/loader/sceneLoader/GameSceneLoader.cs b/scripts/loader/sceneLoader/GameSceneLoader.cs
index 2e6e057..3d4969b 100644
--- a/scripts/loader/sceneLoader/GameSceneLoader.cs
+++ b/scripts/loader/sceneLoader/GameSceneLoader.cs
@@ -4,6 +4,7 @@ using ColdMint.scripts.map;
using ColdMint.scripts.map.LayoutParsingStrategy;
using ColdMint.scripts.map.layoutStrategy;
using ColdMint.scripts.map.RoomPlacer;
+using ColdMint.scripts.utils;
using Godot;
namespace ColdMint.scripts.loader.sceneLoader;
@@ -33,6 +34,7 @@ public partial class GameSceneLoader : SceneLoaderTemplate
MapGenerator.LayoutStrategy = new TestLayoutStrategy();
MapGenerator.LayoutParsingStrategy = new SequenceLayoutParsingStrategy();
MapGenerator.RoomPlacementStrategy = new PatchworkRoomPlacementStrategy();
+ MapGenerator.Seed = GuidUtils.GetGuid();
await MapGenerator.GenerateMap();
}
}
\ No newline at end of file
diff --git a/scripts/map/LayoutParsingStrategy/ILayoutParsingStrategy.cs b/scripts/map/LayoutParsingStrategy/ILayoutParsingStrategy.cs
index 78cee3f..483f7fe 100644
--- a/scripts/map/LayoutParsingStrategy/ILayoutParsingStrategy.cs
+++ b/scripts/map/LayoutParsingStrategy/ILayoutParsingStrategy.cs
@@ -15,7 +15,14 @@ public interface ILayoutParsingStrategy
///
///
public void SetLevelGraph(LevelGraphEditorSaveData levelGraphEditorSaveData);
-
+
+ ///
+ /// Gets data for the start room node
+ /// 获取起始房间节点的数据
+ ///
+ ///
+ public Task GetStartRoomNodeData();
+
///
/// Gets the next room to place
/// 获取下一个要放置的房间
@@ -29,7 +36,7 @@ public interface ILayoutParsingStrategy
///
///
public Task GetNextParentNodeId();
-
+
///
/// Is there another room that needs to be placed
/// 是否还有下一个需要放置的房间
diff --git a/scripts/map/LayoutParsingStrategy/SequenceLayoutParsingStrategy.cs b/scripts/map/LayoutParsingStrategy/SequenceLayoutParsingStrategy.cs
index 73b9a2e..0d8a6f5 100644
--- a/scripts/map/LayoutParsingStrategy/SequenceLayoutParsingStrategy.cs
+++ b/scripts/map/LayoutParsingStrategy/SequenceLayoutParsingStrategy.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using ColdMint.scripts.levelGraphEditor;
@@ -23,19 +24,17 @@ public class SequenceLayoutParsingStrategy : ILayoutParsingStrategy
//设置数据时,是否检查合法了
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 _index;
private int _maxIndex;
private Dictionary _roomNodeDataDictionary = new Dictionary();
public void SetLevelGraph(LevelGraphEditorSaveData levelGraphEditorSaveData)
{
- _index = StartingRoomIndex;
+ _checkLegality = false;
+ _index = -1;
_levelGraphEditorSaveData = levelGraphEditorSaveData;
if (_levelGraphEditorSaveData.RoomNodeDataList == null || _levelGraphEditorSaveData.RoomNodeDataList.Count == 0)
{
@@ -51,7 +50,7 @@ public class SequenceLayoutParsingStrategy : ILayoutParsingStrategy
}
else
{
- _maxIndex = _levelGraphEditorSaveData.ConnectionDataList.Count - 1;
+ _maxIndex = _levelGraphEditorSaveData.ConnectionDataList.Count;
}
_roomNodeDataDictionary.Clear();
@@ -64,66 +63,34 @@ public class SequenceLayoutParsingStrategy : ILayoutParsingStrategy
_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);
+ _checkLegality = true;
}
- ///
- /// Get the first room
- /// 获取第一个房间
- ///
- ///
- ///
- private RoomNodeData? GetFirstRoom(LevelGraphEditorSaveData? levelGraphEditorSaveData)
+ public Task GetStartRoomNodeData()
{
- if (levelGraphEditorSaveData == null || levelGraphEditorSaveData.RoomNodeDataList == null ||
- levelGraphEditorSaveData.RoomNodeDataList.Count == 0)
+ if (_levelGraphEditorSaveData == null)
{
- return null;
+ return Task.FromResult(null);
}
- RoomNodeData? firstRoom = null;
- if (levelGraphEditorSaveData.ConnectionDataList == null ||
- levelGraphEditorSaveData.ConnectionDataList.Count == 0)
+ if (_levelGraphEditorSaveData.RoomNodeDataList == null || _levelGraphEditorSaveData.RoomNodeDataList.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;
- }
+ //If there is no room data in the level map set.
+ //如果设置的关卡图内没有房间数据。
+ return Task.FromResult(null);
}
- return firstRoom;
+ foreach (var roomNodeData in _levelGraphEditorSaveData.RoomNodeDataList.Where(roomNodeData =>
+ roomNodeData.HasTag(Config.RoomDataTag.StartingRoom)))
+ {
+ return Task.FromResult(roomNodeData);
+ }
+
+ return Task.FromResult(null);
}
public Task Next()
{
- if (_index == StartingRoomIndex)
- {
- return Task.FromResult(GetFirstRoom(_levelGraphEditorSaveData));
- }
-
var connectionData = GetIndexOfConnectionData(_index);
if (connectionData == null)
{
@@ -167,13 +134,6 @@ public class SequenceLayoutParsingStrategy : ILayoutParsingStrategy
public Task GetNextParentNodeId()
{
- if (_index == StartingRoomIndex)
- {
- //The start room will not have a parent node.
- //起始房间不会有父节点。
- return Task.FromResult(null);
- }
-
var connectionData = GetIndexOfConnectionData(_index);
if (connectionData == null)
{
@@ -202,14 +162,7 @@ public class SequenceLayoutParsingStrategy : ILayoutParsingStrategy
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);
- }
-
+ _index++;
return Task.FromResult(_index < _maxIndex);
}
}
\ No newline at end of file
diff --git a/scripts/map/MapGenerator.cs b/scripts/map/MapGenerator.cs
index f78599b..54ec660 100644
--- a/scripts/map/MapGenerator.cs
+++ b/scripts/map/MapGenerator.cs
@@ -1,10 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ColdMint.scripts.debug;
+using ColdMint.scripts.levelGraphEditor;
+using ColdMint.scripts.map.dateBean;
using ColdMint.scripts.map.interfaces;
using ColdMint.scripts.map.LayoutParsingStrategy;
using ColdMint.scripts.map.layoutStrategy;
using ColdMint.scripts.map.room;
+using ColdMint.scripts.utils;
using Godot;
namespace ColdMint.scripts.map;
@@ -37,6 +40,19 @@ public static class MapGenerator
///
private static IRoomPlacementStrategy? _roomPlacementStrategy;
+ private static ulong _seed;
+
+ ///
+ /// Set seed
+ /// 设置种子
+ ///
+ public static string Seed
+ {
+ get => _seed.ToString();
+ //If the player inputs integers, we seed them directly with the input values. If it is not an integer, the hash value is taken.
+ //如果玩家输入的是整数,那么我们直接用输入值作为种子。如果不是整数,则取哈希值。
+ set => _seed = ulong.TryParse(value, out var result) ? result : HashCodeUtils.GetFixedHashCode(value);
+ }
///
/// Layout diagram parsing policy
@@ -95,12 +111,36 @@ public static class MapGenerator
//Save the dictionary, put the ID in the room data, corresponding to the successful placement of the room.
//保存字典,将房间数据内的ID,对应放置成功的房间。
var roomDictionary = new Dictionary();
+ var randomNumberGenerator = new RandomNumberGenerator();
+ randomNumberGenerator.Seed = _seed;
+ LogCat.Log("Seed:" + _seed);
+ var startRoomNodeData = await _layoutParsingStrategy.GetStartRoomNodeData();
+ if (startRoomNodeData == null || string.IsNullOrEmpty(startRoomNodeData.Id))
+ {
+ LogCat.LogError("map_generator_has_no_starting_room_data");
+ return;
+ }
+
+ var startingRoomPlacementData =
+ await _roomPlacementStrategy.CalculatePlacementDataForStartingRoom(randomNumberGenerator,
+ startRoomNodeData);
+ if (startingRoomPlacementData == null)
+ {
+ return;
+ }
+
+ var placeSuccess = await PlaceRoomAndAddRecord(startRoomNodeData.Id, startingRoomPlacementData, roomDictionary);
+ if (!placeSuccess)
+ {
+ return;
+ }
+
while (await _layoutParsingStrategy.HasNext())
{
//When a new room needs to be placed
//当有新的房间需要放置时
var roomNodeData = await _layoutParsingStrategy.Next();
- if (roomNodeData == null)
+ if (roomNodeData == null || string.IsNullOrEmpty(roomNodeData.Id))
{
continue;
}
@@ -118,23 +158,49 @@ public static class MapGenerator
}
var roomPlacementData =
- await _roomPlacementStrategy.CalculateNewRoomPlacementData(parentRoomNode, roomNodeData);
+ await _roomPlacementStrategy.CalculateNewRoomPlacementData(randomNumberGenerator, parentRoomNode,
+ roomNodeData);
if (roomPlacementData == null)
{
continue;
}
- if (!await _roomPlacementStrategy.PlaceRoom(_mapRoot, roomPlacementData))
- {
- continue;
- }
-
- if (!string.IsNullOrEmpty(roomNodeData.Id) && roomPlacementData.Room != null)
- {
- roomDictionary.Add(roomNodeData.Id, roomPlacementData.Room);
- }
+ await PlaceRoomAndAddRecord(roomNodeData.Id, roomPlacementData, roomDictionary);
}
//All rooms have been placed.
//所有房间已放置完毕。
}
+
+ ///
+ /// Place rooms and add mappings
+ /// 放置房间,并增加映射
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static async Task PlaceRoomAndAddRecord(string roomNodeDataId,
+ RoomPlacementData roomPlacementData, Dictionary dictionary)
+ {
+ //The input parameters are incomplete.
+ //输入参数不全。
+ if (_roomPlacementStrategy == null || _mapRoot == null || string.IsNullOrEmpty(roomNodeDataId) ||
+ roomPlacementData.Room == null)
+ {
+ return false;
+ }
+
+ if (dictionary.ContainsKey(roomNodeDataId))
+ {
+ return false;
+ }
+
+ if (!await _roomPlacementStrategy.PlaceRoom(_mapRoot, roomPlacementData))
+ {
+ return false;
+ }
+
+ dictionary.Add(roomNodeDataId, roomPlacementData.Room);
+ return true;
+ }
}
\ No newline at end of file
diff --git a/scripts/map/interfaces/IRoomPlacementStrategy.cs b/scripts/map/interfaces/IRoomPlacementStrategy.cs
index 4b48d53..c828611 100644
--- a/scripts/map/interfaces/IRoomPlacementStrategy.cs
+++ b/scripts/map/interfaces/IRoomPlacementStrategy.cs
@@ -40,5 +40,18 @@ public interface IRoomPlacementStrategy
///欲放置的新房间数据
///
///
- public Task CalculateNewRoomPlacementData(Room? parentRoomNode, RoomNodeData newRoomNodeData);
+ public Task CalculateNewRoomPlacementData(RandomNumberGenerator randomNumberGenerator,
+ Room? parentRoomNode,
+ RoomNodeData newRoomNodeData);
+
+
+ ///
+ /// Calculates the placement information for the starting room
+ /// 计算起始房间的放置信息
+ ///
+ ///
+ ///
+ ///
+ public Task CalculatePlacementDataForStartingRoom(
+ RandomNumberGenerator randomNumberGenerator, RoomNodeData startRoomNodeData);
}
\ No newline at end of file
diff --git a/scripts/map/room/RoomFactory.cs b/scripts/map/room/RoomFactory.cs
index 8a47653..3c9d6f3 100644
--- a/scripts/map/room/RoomFactory.cs
+++ b/scripts/map/room/RoomFactory.cs
@@ -1,5 +1,7 @@
using System.Collections.Generic;
+using System.IO;
using Godot;
+using FileAccess = Godot.FileAccess;
namespace ColdMint.scripts.map.room;
@@ -36,7 +38,7 @@ public static class RoomFactory
{
if (!dir.CurrentIsDir())
{
- resList.Add(fileName);
+ resList.Add(Path.Join(roomTemplate, fileName));
}
fileName = dir.GetNext();
diff --git a/scripts/map/roomPlacer/PatchworkRoomPlacementStrategy.cs b/scripts/map/roomPlacer/PatchworkRoomPlacementStrategy.cs
index 502beb6..9b6e846 100644
--- a/scripts/map/roomPlacer/PatchworkRoomPlacementStrategy.cs
+++ b/scripts/map/roomPlacer/PatchworkRoomPlacementStrategy.cs
@@ -32,40 +32,55 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
}
var rootNode = roomPlacementData.Room.RootNode;
- rootNode.Reparent(mapRoot);
+ mapRoot.AddChild(rootNode);
rootNode.Position = roomPlacementData.Position.Value;
return Task.FromResult(true);
}
- public Task CalculateNewRoomPlacementData(Room? parentRoomNode, RoomNodeData newRoomNodeData)
+ public Task CalculateNewRoomPlacementData(RandomNumberGenerator randomNumberGenerator,
+ Room? parentRoomNode,
+ RoomNodeData newRoomNodeData)
{
if (newRoomNodeData.RoomTemplateSet == null || newRoomNodeData.RoomTemplateSet.Length == 0)
{
return Task.FromResult(null);
}
- var roomResArray = RoomFactory.RoomTemplateSetToRoomRes(newRoomNodeData.RoomTemplateSet);
if (parentRoomNode == null)
{
- //No parent node is set, which we think is the starting room.
- //没有设置父节点,我们认为是起点房间。
- //TODO:在这里兼容世界种子。
- var roomPlacementData = new RoomPlacementData
- {
- Room = RoomFactory.CreateRoom(roomResArray[0]),
- Position = Vector2.Zero
- };
- return Task.FromResult(roomPlacementData);
- }
- else
- {
- //TODO:在这里实现房间的放置策略。
return Task.FromResult(null);
}
+ // var roomResArray = RoomFactory.RoomTemplateSetToRoomRes(newRoomNodeData.RoomTemplateSet);
+ //TODO:在这里实现房间的放置策略。
+ return Task.FromResult(null);
}
+ public Task CalculatePlacementDataForStartingRoom(RandomNumberGenerator randomNumberGenerator,
+ RoomNodeData startRoomNodeData)
+ {
+ if (startRoomNodeData.RoomTemplateSet == null || startRoomNodeData.RoomTemplateSet.Length == 0)
+ {
+ return Task.FromResult(null);
+ }
+
+ var roomResArray = RoomFactory.RoomTemplateSetToRoomRes(startRoomNodeData.RoomTemplateSet);
+ if (roomResArray.Length == 0)
+ {
+ return Task.FromResult(null);
+ }
+
+ var index = randomNumberGenerator.Randi() % roomResArray.Length;
+ var roomPlacementData = new RoomPlacementData
+ {
+ Room = RoomFactory.CreateRoom(roomResArray[index]),
+ Position = Vector2.Zero
+ };
+ return Task.FromResult(roomPlacementData);
+ }
+
+
private Task CalculatedPosition(Room mainRoom, Room newRoom, RoomSlot? mainRoomSlot,
- RoomSlot? newRoomSlot,bool roomSlotOverlap)
+ RoomSlot? newRoomSlot, bool roomSlotOverlap)
{
if (mainRoom.RootNode == null || mainRoom.TileMap == null || newRoom.TileMap == null || mainRoomSlot == null ||
newRoomSlot == null)
diff --git a/scripts/utils/HashCodeUtils.cs b/scripts/utils/HashCodeUtils.cs
new file mode 100644
index 0000000..db479f6
--- /dev/null
+++ b/scripts/utils/HashCodeUtils.cs
@@ -0,0 +1,23 @@
+using System.Linq;
+
+namespace ColdMint.scripts.utils;
+
+public class HashCodeUtils
+{
+ ///
+ /// Gets the hash code for a string
+ /// 获取字符串的哈希码
+ ///
+ ///
+ ///The input string returns a fixed hash code
+ ///输入的字符串,返回固定的哈希码
+ ///
+ ///
+ public static uint GetFixedHashCode(string str)
+ {
+ unchecked
+ {
+ return str.Aggregate(2166136261, (current, c) => (current ^ c) * 16777619);
+ }
+ }
+}
\ No newline at end of file