Solve the problem of room overlap.

解决房间重叠问题。
This commit is contained in:
Cold-Mint 2024-05-26 00:02:00 +08:00
parent 5ec6b3065b
commit ace9ba5b65
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
8 changed files with 192 additions and 23 deletions

View File

@ -3,7 +3,7 @@
[ext_resource type="TileSet" uid="uid://c4wpp12rr44hi" path="res://tileSets/dungeon.tres" id="1_rn2om"] [ext_resource type="TileSet" uid="uid://c4wpp12rr44hi" path="res://tileSets/dungeon.tres" id="1_rn2om"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"]
size = Vector2(511.5, 254) size = Vector2(508.75, 254)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_jxmys"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_jxmys"]
size = Vector2(18, 57.75) size = Vector2(18, 57.75)
@ -24,7 +24,7 @@ layer_2/tile_data = PackedInt32Array(0, 1, 3, 65536, 131073, 1, 131072, 131073,
[node name="RoomArea" type="Area2D" parent="."] [node name="RoomArea" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="RoomArea"] [node name="CollisionShape2D" type="CollisionShape2D" parent="RoomArea"]
position = Vector2(257, 129) position = Vector2(255.625, 128)
shape = SubResource("RectangleShape2D_kiih8") shape = SubResource("RectangleShape2D_kiih8")
[node name="RoomSlotList" type="Node2D" parent="."] [node name="RoomSlotList" type="Node2D" parent="."]

View File

@ -3,7 +3,7 @@
[ext_resource type="TileSet" uid="uid://c4wpp12rr44hi" path="res://tileSets/dungeon.tres" id="1_rn2om"] [ext_resource type="TileSet" uid="uid://c4wpp12rr44hi" path="res://tileSets/dungeon.tres" id="1_rn2om"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"]
size = Vector2(735.375, 512.5) size = Vector2(681, 453)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_o85u0"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_o85u0"]
size = Vector2(20, 48) size = Vector2(20, 48)
@ -31,7 +31,7 @@ layer_2/tile_data = PackedInt32Array(0, 1, 3, 65536, 131073, 1, 131072, 131073,
collision_mask = 0 collision_mask = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="RoomArea"] [node name="CollisionShape2D" type="CollisionShape2D" parent="RoomArea"]
position = Vector2(369.313, 253.75) position = Vector2(371.5, 254.5)
shape = SubResource("RectangleShape2D_kiih8") shape = SubResource("RectangleShape2D_kiih8")
[node name="RoomSlotList" type="Node2D" parent="."] [node name="RoomSlotList" type="Node2D" parent="."]

View File

@ -61,7 +61,8 @@ public partial class GameSceneLoader : SceneLoaderTemplate
{ {
//2757235769 房间边框重叠! //2757235769 房间边框重叠!
//4175259928 房间内容重叠! //4175259928 房间内容重叠!
MapGenerator.Seed = "4175259928"; //212782913 起始房间重叠!
MapGenerator.Seed = GuidUtils.GetGuid();
if (_seedLabel != null) if (_seedLabel != null)
{ {
//If you have a seedLabel, then set the seed to it. //If you have a seedLabel, then set the seed to it.

View File

@ -1,9 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using ColdMint.scripts.debug;
using ColdMint.scripts.levelGraphEditor; using ColdMint.scripts.levelGraphEditor;
using ColdMint.scripts.serialization;
namespace ColdMint.scripts.map.LayoutParsingStrategy; namespace ColdMint.scripts.map.LayoutParsingStrategy;

View File

@ -97,6 +97,11 @@ public static class MapGenerator
} }
NodeUtils.DeleteAllChild(_mapRoot); NodeUtils.DeleteAllChild(_mapRoot);
if (!await _roomPlacementStrategy.StartGeneration(_mapRoot))
{
return;
}
//Get the layout data //Get the layout data
//拿到布局图数据 //拿到布局图数据
var levelGraphEditorSaveData = await _layoutStrategy.GetLayout(); var levelGraphEditorSaveData = await _layoutStrategy.GetLayout();
@ -169,6 +174,7 @@ public static class MapGenerator
} }
//All rooms have been placed. //All rooms have been placed.
//所有房间已放置完毕。 //所有房间已放置完毕。
await _roomPlacementStrategy.GeneratedComplete(_mapRoot);
} }
/// <summary> /// <summary>

View File

@ -12,6 +12,24 @@ namespace ColdMint.scripts.map.interfaces;
/// </summary> /// </summary>
public interface IRoomPlacementStrategy public interface IRoomPlacementStrategy
{ {
/// <summary>
/// <para>This method is called when the map generator starts generating the map</para>
/// <para>当地图生成器开始生成地图时调用此方法</para>
/// </summary>
/// <param name="mapRoot"></param>
/// <returns>
///<para>Returning false terminates the build</para>
///<para>返回false则终止生成</para>
/// </returns>
public Task<bool> StartGeneration(Node mapRoot);
/// <summary>
/// <para>Call this method after the build is complete</para>
/// <para>生成完成后调用此方法</para>
/// </summary>
/// <returns></returns>
public Task GeneratedComplete(Node mapRoot);
/// <summary> /// <summary>
/// <para>Place the room in the designated location</para> /// <para>Place the room in the designated location</para>
/// <para>在指定的位置放置房间</para> /// <para>在指定的位置放置房间</para>

View File

@ -20,6 +20,23 @@ public class Room
private Node2D? _rootNode; private Node2D? _rootNode;
private RoomSlot?[]? _roomSlots; private RoomSlot?[]? _roomSlots;
private TileMap? _tileMap; private TileMap? _tileMap;
private Area2D? _area2D;
private CollisionShape2D? _collisionShape2D;
/// <summary>
/// <para>The collision shape of the room</para>
/// <para>房间的碰撞形状</para>
/// </summary>
public CollisionShape2D? RoomCollisionShape2D
{
get => _collisionShape2D;
set => _collisionShape2D = value;
}
public Area2D? Area2D
{
get => _area2D;
set => _area2D = value;
}
public PackedScene? RoomScene public PackedScene? RoomScene
{ {
@ -50,7 +67,10 @@ public class Room
_rootNode = node2D; _rootNode = node2D;
_tileMap = node2D.GetNode<TileMap>("TileMap"); _tileMap = node2D.GetNode<TileMap>("TileMap");
_roomSlots = GetRoomSlots(_tileMap, node2D.GetNode<Area2D>("RoomArea"), _area2D = node2D.GetNode<Area2D>("RoomArea");
_area2D.Monitorable = true;
_collisionShape2D = _area2D.GetChild<CollisionShape2D>(0);
_roomSlots = GetRoomSlots(_tileMap, _area2D,
node2D.GetNode<Node2D>("RoomSlotList")); node2D.GetNode<Node2D>("RoomSlotList"));
} }
@ -90,6 +110,10 @@ public class Room
//Got the object in the room slot //Got the object in the room slot
//拿到了房间槽对象 //拿到了房间槽对象
var area2D = slotList.GetChild<Area2D>(i); var area2D = slotList.GetChild<Area2D>(i);
//Prevent other areas from detecting the room slot
//禁止其他区域检测到房间槽
area2D.Monitorable = false;
var collisionShape2D = area2D.GetChild<CollisionShape2D>(0); var collisionShape2D = area2D.GetChild<CollisionShape2D>(0);
var rect2 = collisionShape2D.Shape.GetRect(); var rect2 = collisionShape2D.Shape.GetRect();
//Round the size of the impactor to the tile size For example, the impactor size 44 is converted to the tile size 44/32=1.375 rounded to 1 //Round the size of the impactor to the tile size For example, the impactor size 44 is converted to the tile size 44/32=1.375 rounded to 1

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using ColdMint.scripts.debug; using ColdMint.scripts.debug;
using ColdMint.scripts.levelGraphEditor; using ColdMint.scripts.levelGraphEditor;
@ -20,6 +21,82 @@ namespace ColdMint.scripts.map.RoomPlacer;
/// </remarks> /// </remarks>
public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
{ {
/// <summary>
/// <para>We use a temporary area to measure whether the rooms overlap</para>
/// <para>我们使用一个临时区域进行测量房间是否重叠</para>
/// </summary>
private Area2D? _measuringArea2D;
private CollisionShape2D? _measuringCollisionShape2D;
private Area2D? _selfArea2D;
/// <summary>
/// <para>How many rooms overlap with the new rooms that will be placed</para>
/// <para>有多少个房间与将要放置的新房间重叠</para>
/// </summary>
private int _overlapQuantity;
public Task<bool> StartGeneration(Node mapRoot)
{
if (_measuringArea2D == null)
{
_measuringArea2D = new Area2D();
_measuringArea2D.Monitoring = true;
_measuringArea2D.AreaEntered += body =>
{
if (_selfArea2D != null && body == _selfArea2D)
{
return;
}
//Room overlap detected
//检测到房间重叠
_overlapQuantity++;
};
_measuringArea2D.AreaExited += body =>
{
if (_selfArea2D != null && body == _selfArea2D)
{
return;
}
//Rooms no longer overlap
//房间不再重叠
_overlapQuantity--;
};
mapRoot.AddChild(_measuringArea2D);
}
if (_measuringCollisionShape2D == null)
{
_measuringCollisionShape2D = new CollisionShape2D();
_measuringArea2D.AddChild(_measuringCollisionShape2D);
}
return Task.FromResult(true);
}
public Task GeneratedComplete(Node mapRoot)
{
if (_measuringCollisionShape2D != null)
{
_measuringCollisionShape2D?.QueueFree();
_measuringArea2D?.RemoveChild(_measuringCollisionShape2D);
_measuringCollisionShape2D = null;
}
if (_measuringArea2D != null)
{
_measuringArea2D?.QueueFree();
mapRoot.RemoveChild(_measuringArea2D);
_measuringArea2D = null;
}
return Task.CompletedTask;
}
public Task<bool> PlaceRoom(Node mapRoot, RoomPlacementData roomPlacementData) public Task<bool> PlaceRoom(Node mapRoot, RoomPlacementData roomPlacementData)
{ {
if (roomPlacementData.Room == null || roomPlacementData.Position == null) if (roomPlacementData.Room == null || roomPlacementData.Position == null)
@ -38,30 +115,30 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
return Task.FromResult(true); return Task.FromResult(true);
} }
public Task<RoomPlacementData?> CalculateNewRoomPlacementData(RandomNumberGenerator randomNumberGenerator, public async Task<RoomPlacementData?> CalculateNewRoomPlacementData(RandomNumberGenerator randomNumberGenerator,
Room? parentRoomNode, Room? parentRoomNode,
RoomNodeData newRoomNodeData) RoomNodeData newRoomNodeData)
{ {
if (newRoomNodeData.RoomTemplateSet == null || newRoomNodeData.RoomTemplateSet.Length == 0) if (newRoomNodeData.RoomTemplateSet == null || newRoomNodeData.RoomTemplateSet.Length == 0)
{ {
return Task.FromResult<RoomPlacementData?>(null); return null;
} }
if (parentRoomNode == null) if (parentRoomNode == null)
{ {
return Task.FromResult<RoomPlacementData?>(null); return null;
} }
var roomResArray = RoomFactory.RoomTemplateSetToRoomRes(newRoomNodeData.RoomTemplateSet); var roomResArray = RoomFactory.RoomTemplateSetToRoomRes(newRoomNodeData.RoomTemplateSet);
if (roomResArray.Length == 0) if (roomResArray.Length == 0)
{ {
return Task.FromResult<RoomPlacementData?>(null); return null;
} }
var roomSlots = parentRoomNode.RoomSlots; var roomSlots = parentRoomNode.RoomSlots;
if (roomSlots == null || roomSlots.Length == 0) if (roomSlots == null || roomSlots.Length == 0)
{ {
return Task.FromResult<RoomPlacementData?>(null); return null;
} }
//Saves all data in the room template that matches the parent room. //Saves all data in the room template that matches the parent room.
@ -87,8 +164,7 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
continue; continue;
} }
var position = CalculatedPosition(parentRoomNode, newRoom, mainRoomSlot, newRoomSlot, false) var position = await CalculatedPosition(parentRoomNode, newRoom, mainRoomSlot, newRoomSlot, false);
.Result;
if (position == null) continue; if (position == null) continue;
var roomPlacementData = new RoomPlacementData var roomPlacementData = new RoomPlacementData
{ {
@ -100,12 +176,12 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
if (useableRoomPlacementData.Count == 0) if (useableRoomPlacementData.Count == 0)
{ {
return Task.FromResult<RoomPlacementData?>(null); return null;
} }
else else
{ {
var index = randomNumberGenerator.Randi() % useableRoomPlacementData.Count; var index = randomNumberGenerator.Randi() % useableRoomPlacementData.Count;
return Task.FromResult<RoomPlacementData?>(useableRoomPlacementData[(int)index]); return useableRoomPlacementData[(int)index];
} }
} }
@ -210,7 +286,7 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
{ {
continue; continue;
} }
mainRoomSlot.Matched = true; mainRoomSlot.Matched = true;
newRoomSlot.Matched = true; newRoomSlot.Matched = true;
outMainRoomSlot = mainRoomSlot; outMainRoomSlot = mainRoomSlot;
@ -224,7 +300,32 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
return Task.FromResult(false); return Task.FromResult(false);
} }
private Task<Vector2?> CalculatedPosition(Room mainRoom, Room newRoom, RoomSlot? mainRoomSlot, /// <summary>
/// <para>Calculate room position</para>
/// <para>计算房间位置</para>
/// </summary>
/// <param name="mainRoom">
///<para>Main room</para>
///<para>主房间</para>
/// </param>
/// <param name="newRoom">
///<para>New room</para>
///<para>新房间</para>
/// </param>
/// <param name="mainRoomSlot">
///<para>Main room slot</para>
///<para>主房间插槽</para>
/// </param>
/// <param name="newRoomSlot">
///<para>New room slot</para>
///<para>新房间插槽</para>
/// </param>
/// <param name="roomSlotOverlap">
///<para>Whether room slots allow overlays</para>
///<para>房间插槽是否允许覆盖</para>
/// </param>
/// <returns></returns>
private async Task<Vector2?> CalculatedPosition(Room mainRoom, Room newRoom, RoomSlot? mainRoomSlot,
RoomSlot? newRoomSlot, bool roomSlotOverlap) RoomSlot? newRoomSlot, bool roomSlotOverlap)
{ {
if (mainRoom.RootNode == null || newRoom.RootNode == null || newRoom.TileMap == null || if (mainRoom.RootNode == null || newRoom.RootNode == null || newRoom.TileMap == null ||
@ -232,7 +333,7 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
newRoom.TileMap == null || mainRoomSlot == null || newRoom.TileMap == null || mainRoomSlot == null ||
newRoomSlot == null) newRoomSlot == null)
{ {
return Task.FromResult<Vector2?>(null); return null;
} }
//Main room slot location description //Main room slot location description
@ -245,7 +346,7 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
{ {
//If the room slot is described as null, null is returned //If the room slot is described as null, null is returned
//若房间槽描述为null那么返回null //若房间槽描述为null那么返回null
return Task.FromResult<Vector2?>(null); return null;
} }
var mainRoomSlotPosition = mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition); var mainRoomSlotPosition = mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition);
@ -285,6 +386,27 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
} }
} }
} }
return Task.FromResult<Vector2?>(result);
//Do calculations overlap with other rooms?
//计算结果是否与其他房间重叠?
if (newRoom.RoomCollisionShape2D != null && _measuringArea2D != null && _measuringCollisionShape2D != null)
{
//Ignore yourself when detecting room overlap
//检测房间重叠时应忽略自身
_selfArea2D = newRoom.Area2D;
_measuringArea2D.Position = result;
_measuringCollisionShape2D.Shape = newRoom.RoomCollisionShape2D.Shape;
//Calculate the offset of the shape.
//计算形状的偏移量。
_measuringCollisionShape2D.Position = newRoom.RoomCollisionShape2D.Shape.GetRect().Size / 2;
await Task.Delay(TimeSpan.FromMilliseconds(50));
if (_overlapQuantity > 0)
{
return null;
}
}
return result;
} }
} }