Solve the problem of room overlap.
解决房间重叠问题。
This commit is contained in:
parent
5ec6b3065b
commit
ace9ba5b65
|
@ -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="."]
|
||||||
|
|
|
@ -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="."]
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user