Algorithms for adjusting room placement.
调整房间放置的算法。
This commit is contained in:
parent
544c5303f3
commit
16a2a1d551
|
@ -72,3 +72,6 @@ script = ExtResource("5_dis4v")
|
||||||
[node name="DamageNumberContainer" type="Node2D" parent="."]
|
[node name="DamageNumberContainer" type="Node2D" parent="."]
|
||||||
|
|
||||||
[node name="WeaponContainer" type="Node2D" parent="."]
|
[node name="WeaponContainer" type="Node2D" parent="."]
|
||||||
|
|
||||||
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
|
zoom = Vector2(0.5, 0.5)
|
||||||
|
|
|
@ -34,7 +34,10 @@ public partial class GameSceneLoader : SceneLoaderTemplate
|
||||||
MapGenerator.LayoutStrategy = new TestLayoutStrategy();
|
MapGenerator.LayoutStrategy = new TestLayoutStrategy();
|
||||||
MapGenerator.LayoutParsingStrategy = new SequenceLayoutParsingStrategy();
|
MapGenerator.LayoutParsingStrategy = new SequenceLayoutParsingStrategy();
|
||||||
MapGenerator.RoomPlacementStrategy = new PatchworkRoomPlacementStrategy();
|
MapGenerator.RoomPlacementStrategy = new PatchworkRoomPlacementStrategy();
|
||||||
MapGenerator.Seed = GuidUtils.GetGuid();
|
//Test the seeds used
|
||||||
|
//2531276826 Right-Down和Left-Down匹配成功
|
||||||
|
//4208831693 Left-Down和Right-Up匹配成功
|
||||||
|
MapGenerator.Seed = "2531276826";
|
||||||
await MapGenerator.GenerateMap();
|
await MapGenerator.GenerateMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ColdMint.scripts.map.dateBean;
|
|
||||||
using ColdMint.scripts.map.room;
|
|
||||||
|
|
||||||
namespace ColdMint.scripts.map.interfaces;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>IRoomSlotsMatcher</para>
|
|
||||||
/// <para>房间插槽匹配器</para>
|
|
||||||
/// </summary>
|
|
||||||
public interface IRoomSlotsMatcher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Whether the slots of the two rooms can be matched</para>
|
|
||||||
/// <para>两个房间的插槽是否可匹配</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mainRoom"></param>
|
|
||||||
/// <param name="newRoom"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<bool> IsMatch(Room? mainRoom, Room newRoom);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>LastMatchedMainSlot</para>
|
|
||||||
/// <para>最后匹配的主要插槽</para>
|
|
||||||
/// </summary>
|
|
||||||
RoomSlot? LastMatchedMainSlot { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>LastMatchedMinorSlot</para>
|
|
||||||
/// <para>最后匹配的次要插槽</para>
|
|
||||||
/// </summary>
|
|
||||||
RoomSlot? LastMatchedMinorSlot { get; }
|
|
||||||
}
|
|
|
@ -85,7 +85,7 @@ public class Room
|
||||||
var midpoint = roomAreaCollisionShape2D.Position + roomAreaRect2.Position + roomAreaRect2.Size / 2;
|
var midpoint = roomAreaCollisionShape2D.Position + roomAreaRect2.Position + roomAreaRect2.Size / 2;
|
||||||
//endregion
|
//endregion
|
||||||
var roomSlots = new List<RoomSlot>();
|
var roomSlots = new List<RoomSlot>();
|
||||||
for (int i = 0; i < slotCount; i++)
|
for (var i = 0; i < slotCount; i++)
|
||||||
{
|
{
|
||||||
//拿到了房间卡槽对象
|
//拿到了房间卡槽对象
|
||||||
var area2D = slotList.GetChild<Area2D>(i);
|
var area2D = slotList.GetChild<Area2D>(i);
|
||||||
|
@ -107,11 +107,13 @@ public class Room
|
||||||
//转为瓦片地图的坐标(中点)
|
//转为瓦片地图的坐标(中点)
|
||||||
var tileMapStartPosition = tileMap.LocalToMap(startPosition);
|
var tileMapStartPosition = tileMap.LocalToMap(startPosition);
|
||||||
var tileMapEndPosition = tileMap.LocalToMap(endPosition);
|
var tileMapEndPosition = tileMap.LocalToMap(endPosition);
|
||||||
var roomSlot = new RoomSlot();
|
var roomSlot = new RoomSlot
|
||||||
roomSlot.EndPosition = tileMapEndPosition;
|
{
|
||||||
roomSlot.StartPosition = tileMapStartPosition;
|
EndPosition = tileMapEndPosition,
|
||||||
|
StartPosition = tileMapStartPosition,
|
||||||
//计算槽位的方向(房间中点为原点,指向槽位中点的向量)
|
//计算槽位的方向(房间中点为原点,指向槽位中点的向量)
|
||||||
roomSlot.DistanceToMidpointOfRoom = CoordinateUtils.VectorToOrientationArray(midpoint, midpointOfRoomSlots);
|
DistanceToMidpointOfRoom = CoordinateUtils.VectorToOrientationArray(midpoint, midpointOfRoomSlots)
|
||||||
|
};
|
||||||
roomSlots.Add(roomSlot);
|
roomSlots.Add(roomSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ColdMint.scripts.debug;
|
||||||
using ColdMint.scripts.levelGraphEditor;
|
using ColdMint.scripts.levelGraphEditor;
|
||||||
using ColdMint.scripts.map.dateBean;
|
using ColdMint.scripts.map.dateBean;
|
||||||
using ColdMint.scripts.map.interfaces;
|
using ColdMint.scripts.map.interfaces;
|
||||||
using ColdMint.scripts.map.room;
|
using ColdMint.scripts.map.room;
|
||||||
|
using ColdMint.scripts.utils;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace ColdMint.scripts.map.RoomPlacer;
|
namespace ColdMint.scripts.map.RoomPlacer;
|
||||||
|
@ -50,8 +52,48 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
|
||||||
{
|
{
|
||||||
return Task.FromResult<RoomPlacementData?>(null);
|
return Task.FromResult<RoomPlacementData?>(null);
|
||||||
}
|
}
|
||||||
// var roomResArray = RoomFactory.RoomTemplateSetToRoomRes(newRoomNodeData.RoomTemplateSet);
|
|
||||||
//TODO:在这里实现房间的放置策略。
|
var roomResArray = RoomFactory.RoomTemplateSetToRoomRes(newRoomNodeData.RoomTemplateSet);
|
||||||
|
if (roomResArray.Length == 0)
|
||||||
|
{
|
||||||
|
return Task.FromResult<RoomPlacementData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var roomSlots = parentRoomNode.RoomSlots;
|
||||||
|
if (roomSlots == null || roomSlots.Length == 0)
|
||||||
|
{
|
||||||
|
return Task.FromResult<RoomPlacementData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Matches unmatched slots.
|
||||||
|
//对未匹配的插槽进行匹配。
|
||||||
|
foreach (var roomRes in roomResArray)
|
||||||
|
{
|
||||||
|
var newRoom = RoomFactory.CreateRoom(roomRes);
|
||||||
|
if (newRoom == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a room, try to use the room slot to match the existing room slot.
|
||||||
|
//创建了一个房间,尝试使用房间的槽与现有的房间槽匹配。
|
||||||
|
if (!IsMatch(parentRoomNode, newRoom, out var mainRoomSlot, out var newRoomSlot).Result) continue;
|
||||||
|
if (mainRoomSlot == null || newRoomSlot == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = CalculatedPosition(parentRoomNode, newRoom, mainRoomSlot, newRoomSlot, true)
|
||||||
|
.Result;
|
||||||
|
if (position == null) continue;
|
||||||
|
var roomPlacementData = new RoomPlacementData
|
||||||
|
{
|
||||||
|
Room = newRoom,
|
||||||
|
Position = position
|
||||||
|
};
|
||||||
|
return Task.FromResult<RoomPlacementData?>(roomPlacementData);
|
||||||
|
}
|
||||||
|
|
||||||
return Task.FromResult<RoomPlacementData?>(null);
|
return Task.FromResult<RoomPlacementData?>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,32 +121,152 @@ public class PatchworkRoomPlacementStrategy : IRoomPlacementStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>if it matches</para>
|
||||||
|
/// <para>是否匹配</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mainRoom"></param>
|
||||||
|
/// <param name="newRoom"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<bool> IsMatch(Room? mainRoom, Room newRoom, out RoomSlot? outMainRoomSlot, out RoomSlot? outNewRoomSlot)
|
||||||
|
{
|
||||||
|
if (mainRoom == null)
|
||||||
|
{
|
||||||
|
outNewRoomSlot = null;
|
||||||
|
outMainRoomSlot = null;
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var roomSlots = mainRoom.RoomSlots;
|
||||||
|
if (roomSlots == null)
|
||||||
|
{
|
||||||
|
outNewRoomSlot = null;
|
||||||
|
outMainRoomSlot = null;
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newRoomSlots = newRoom.RoomSlots;
|
||||||
|
if (newRoomSlots == null)
|
||||||
|
{
|
||||||
|
outNewRoomSlot = null;
|
||||||
|
outMainRoomSlot = null;
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var mainRoomSlot in roomSlots)
|
||||||
|
{
|
||||||
|
if (mainRoomSlot == null || mainRoomSlot.Matched)
|
||||||
|
{
|
||||||
|
//如果已经匹配过了,就不再匹配
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var newRoomSlot in newRoomSlots)
|
||||||
|
{
|
||||||
|
if (newRoomSlot == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newRoomSlot.Matched)
|
||||||
|
{
|
||||||
|
//如果已经匹配过了,就不再匹配
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainRoomSlot.IsHorizontal != newRoomSlot.IsHorizontal)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainRoomSlot.Length != newRoomSlot.Length)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var distanceToMidpointOfRoom = mainRoomSlot.DistanceToMidpointOfRoom;
|
||||||
|
var newDistanceToMidpointOfRoom = newRoomSlot.DistanceToMidpointOfRoom;
|
||||||
|
if (distanceToMidpointOfRoom == null || newDistanceToMidpointOfRoom == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceToMidpointOfRoom[0] == newDistanceToMidpointOfRoom[0] &&
|
||||||
|
distanceToMidpointOfRoom[1] == newDistanceToMidpointOfRoom[1])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogCat.Log(distanceToMidpointOfRoom[0] + "-" + distanceToMidpointOfRoom[1] + "和" +
|
||||||
|
newDistanceToMidpointOfRoom[0] + "-" + newDistanceToMidpointOfRoom[1] + "匹配成功");
|
||||||
|
mainRoomSlot.Matched = true;
|
||||||
|
newRoomSlot.Matched = true;
|
||||||
|
outMainRoomSlot = mainRoomSlot;
|
||||||
|
outNewRoomSlot = newRoomSlot;
|
||||||
|
return Task.FromResult(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outNewRoomSlot = null;
|
||||||
|
outMainRoomSlot = null;
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
private Task<Vector2?> CalculatedPosition(Room mainRoom, Room newRoom, RoomSlot? mainRoomSlot,
|
private Task<Vector2?> 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 ||
|
if (mainRoom.RootNode == null || newRoom.RootNode == null || newRoom.TileMap == null ||
|
||||||
|
mainRoom.TileMap == null ||
|
||||||
|
newRoom.TileMap == null || mainRoomSlot == null ||
|
||||||
newRoomSlot == null)
|
newRoomSlot == null)
|
||||||
{
|
{
|
||||||
return Task.FromResult<Vector2?>(null);
|
return Task.FromResult<Vector2?>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//计算主插槽中点在世界中的位置。
|
//Main room slot location description
|
||||||
//mainRoom.RootNode.Position意为房间所在的世界位置
|
//主房间槽位置描述
|
||||||
//mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition)意为主插槽在房间中的位置
|
var mainOrientationDescribe = mainRoomSlot.DistanceToMidpointOfRoom;
|
||||||
var result = mainRoom.RootNode.Position + mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition);
|
//New room slot location description
|
||||||
if (roomSlotOverlap)
|
//新房间槽位置描述
|
||||||
|
var newOrientationDescribe = newRoomSlot.DistanceToMidpointOfRoom;
|
||||||
|
if (mainOrientationDescribe == null || newOrientationDescribe == null)
|
||||||
{
|
{
|
||||||
//执行减法,从槽中点偏移到左上角
|
//If the room slot is described as null, null is returned
|
||||||
result -= _halfCell;
|
//若房间槽描述为null,那么返回null
|
||||||
|
return Task.FromResult<Vector2?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 result;
|
||||||
|
if (mainOrientationDescribe[0] == CoordinateUtils.OrientationDescribe.Left &&
|
||||||
|
newOrientationDescribe[0] == CoordinateUtils.OrientationDescribe.Right)
|
||||||
|
{
|
||||||
|
//Move left to new room.
|
||||||
|
//左移新房间。
|
||||||
|
var mainSlotPosition = mainRoom.RootNode.Position + mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition);
|
||||||
|
var newSlotPosition = newRoom.RootNode.Position + newRoom.TileMap.MapToLocal(newRoomSlot.StartPosition);
|
||||||
|
result = mainSlotPosition +
|
||||||
|
newRoom.TileMap.Position - newRoom.TileMap.MapToLocal(newRoomSlot.StartPosition);
|
||||||
|
//Modified y height
|
||||||
|
//修正y高度
|
||||||
|
result.Y -= newSlotPosition.Y - mainSlotPosition.Y;
|
||||||
|
//If the room slots don't overlap
|
||||||
|
//如果房间槽不能重叠
|
||||||
|
if (!roomSlotOverlap)
|
||||||
|
{
|
||||||
|
result.X -= Config.CellSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//执行减法,从槽中点偏移到右下角
|
var mainSlotPosition = mainRoom.RootNode.Position + mainRoom.TileMap.MapToLocal(mainRoomSlot.StartPosition);
|
||||||
result += _halfCell;
|
var newSlotPosition = newRoom.RootNode.Position + newRoom.TileMap.MapToLocal(newRoomSlot.StartPosition);
|
||||||
|
result = mainSlotPosition;
|
||||||
|
// result.Y += newSlotPosition.Y - mainSlotPosition.Y;
|
||||||
}
|
}
|
||||||
//我们不能将新房间的原点设置在主房间槽的左上角或右下角,这会导致插槽不对应。
|
|
||||||
|
|
||||||
//竖直槽,我们需要在同一水平上。
|
|
||||||
|
//We need to be on the same level.
|
||||||
|
//我们需要在同一水平上。
|
||||||
if (mainRoomSlot.IsHorizontal)
|
if (mainRoomSlot.IsHorizontal)
|
||||||
{
|
{
|
||||||
result += newRoom.TileMap.MapToLocal(new Vector2I(newRoomSlot.EndPosition.X, 0)) - _halfCell;
|
result += newRoom.TileMap.MapToLocal(new Vector2I(newRoomSlot.EndPosition.X, 0)) - _halfCell;
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ColdMint.scripts.map.dateBean;
|
|
||||||
using ColdMint.scripts.map.interfaces;
|
|
||||||
using ColdMint.scripts.map.room;
|
|
||||||
|
|
||||||
namespace ColdMint.scripts.map.slotsMatcher;
|
|
||||||
|
|
||||||
public class RoomSlotsMatcher : IRoomSlotsMatcher
|
|
||||||
{
|
|
||||||
private RoomSlot? _lastMatchedMainSlot;
|
|
||||||
private RoomSlot? _lastMatchedMinorSlot;
|
|
||||||
|
|
||||||
public Task<bool> IsMatch(Room? mainRoom, Room newRoom)
|
|
||||||
{
|
|
||||||
if (mainRoom == null)
|
|
||||||
{
|
|
||||||
return Task.FromResult(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var roomSlots = mainRoom.RoomSlots;
|
|
||||||
if (roomSlots == null)
|
|
||||||
{
|
|
||||||
return Task.FromResult(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var newRoomSlots = newRoom.RoomSlots;
|
|
||||||
if (newRoomSlots == null)
|
|
||||||
{
|
|
||||||
return Task.FromResult(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var mainRoomSlot in roomSlots)
|
|
||||||
{
|
|
||||||
if (mainRoomSlot == null || mainRoomSlot.Matched)
|
|
||||||
{
|
|
||||||
//如果已经匹配过了,就不再匹配
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var newRoomSlot in newRoomSlots)
|
|
||||||
{
|
|
||||||
if (newRoomSlot == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newRoomSlot.Matched)
|
|
||||||
{
|
|
||||||
//如果已经匹配过了,就不再匹配
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainRoomSlot.IsHorizontal != newRoomSlot.IsHorizontal)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainRoomSlot.Length != newRoomSlot.Length)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var distanceToMidpointOfRoom = mainRoomSlot.DistanceToMidpointOfRoom;
|
|
||||||
var newDistanceToMidpointOfRoom = newRoomSlot.DistanceToMidpointOfRoom;
|
|
||||||
if (distanceToMidpointOfRoom == null || newDistanceToMidpointOfRoom == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (distanceToMidpointOfRoom[0] == newDistanceToMidpointOfRoom[0] &&
|
|
||||||
distanceToMidpointOfRoom[1] == newDistanceToMidpointOfRoom[1])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mainRoomSlot.Matched = true;
|
|
||||||
newRoomSlot.Matched = true;
|
|
||||||
_lastMatchedMainSlot = mainRoomSlot;
|
|
||||||
_lastMatchedMinorSlot = newRoomSlot;
|
|
||||||
return Task.FromResult(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.FromResult(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RoomSlot? LastMatchedMainSlot => _lastMatchedMainSlot;
|
|
||||||
public RoomSlot? LastMatchedMinorSlot => _lastMatchedMinorSlot;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user