[英]Distance between two grid cells, with no diagonal
几天来我一直在做一个小项目,一切正常,直到我将“地图”实现更改为与我所基于的游戏(Dofus)中的相同(它是社区的小帮手) .
基本上,我有一个旋转 45° 的网格布局(见下图),从左上角到右下角构造。 每个单元格作为 xIndex 和 zIndex 来表示它在图像上的位置(xIndex ; zIndex),我只想获得两个单元格之间的距离,而不是沿对角线移动。
正如我试图在图片上解释的那样:
GetDistanceBetweenTiles(A, B) 应该是 3
GetDistanceBetweenTiles(A, C) 应该是 5
GetDistanceBetweenTiles(B, C) 应该是 2
我发现“曼哈顿距离”看起来像是我想要的,但它并没有给我上面的值。
这是代码:
private int GetDistanceBetweenTiles(MovableObject a, MovableObject b)
{
//int dist = Mathf.Abs(a.xIndex - b.xIndex) + Mathf.Abs(a.zIndex - b.zIndex);
int minX = a.xIndex < b.xIndex ? a.xIndex : b.xIndex;
int maxX = a.xIndex > b.xIndex ? a.xIndex : b.xIndex;
int minZ = a.zIndex < b.zIndex ? a.zIndex : b.zIndex;
int maxZ = a.zIndex > b.zIndex ? a.zIndex : b.zIndex;
int distX = (maxX - minX);
int distZ = (maxZ - minZ);
int dist = Mathf.Abs(maxX - minX) + Mathf.Abs(maxZ - minZ);
print($"Distance between {a.name} and {b.name} is {dist}");
return dist;
}
任何帮助将不胜感激。
如果它可以提供帮助,这里是使用我所做的第一个地图实现的项目(但尚未翻译)。
让我们用简单的公式在倾斜的行中创建新坐标:
row = z/2 - x ("/" for **integer division**)
col = z - row
现在我们可以计算曼哈顿距离为
abs(row2 - row1) + abs(col2 - col1)
对于你的例子
x z r c
4, 2 => -3, 5
1, 4 => 1, 4
distance = (1-(-3)) + (5-4) = 4 + 1 = 5
解释一下:你的网格旋转了 45 度:
0 1 2 3 4 5 6 7 8 \column
40|41 row -4
30|31|42|43 row -3
20|21|32|33|44|45 row -2
10|11|22|23|34|35|46|47 row -1
00|01|12|13|24|15|36|37|48 row 0
02|03|14|15|26|27|38 row 1
04|05|16|17|28 row 2
06|07|18 row 3
我可能有一个解决方法给你。 我是一个懒惰的人,数学很差......所以我通常让 Unity 在像你这样的情况下为我做数学;)
为此,您需要一个专用的 GameObject 以表示网格“旋转”的方式旋转,因此0,45,0
。
然后 - 由于您的瓷砖总是在旋转坐标系中以1
的步长移动 - 您可以使用基于索引的距离,而不是使用Transform.InverseTransformPoint
直接比较绝对位置,以获得相对于该旋转对象的位置。
InverseTransformPoint
在使用变换的局部空间中重新调整给定的世界位置,因此如果对象最初放置在例如x=1, z=1
在我们旋转的局部空间中,它将具有位置z=1.1414..., x=0
。
我只是将这个组件附加到我的旋转对象上..实际上我在Awake
中进行了确认,以确保 ;)
public class PositionsManager : MonoBehaviour
{
// I know .. singleton pattern .. buuu
// but that's the fastest way to prototype ;)
public static PositionsManager Singleton;
private void Awake()
{
// just for making sure this object is at world origin
transform.position = Vector3.zero;
// rotate the object liek you need it
// possible that in your case you rather wanted -45°
transform.eulerAngles = new Vector3(0, 45, 0);
// since InverseTransformPoint is affacted by scale
// just make sure this object has the default scale
transform.localScale = Vector3.one;
// set the singleton so we can easily access this reference
Singleton = this;
}
public Vector2Int GetDistance(Transform from, Transform to)
{
var localPosFrom = transform.InverseTransformPoint(from.position);
var localPosTo = transform.InverseTransformPoint(to.position);
// Now you can simply get the actual position distance and return
// them as vector2 so you can even still see the components
// seperately
var difference = localPosTo - localPosFrom;
// since you are using X-Z not X-Y you have to convert the vector "manually"
return new Vector2Int(Mathf.RoundToInt(difference.x), Mathf.RoundToInt(difference.z));
}
public int GetAbsoluteDistance(Transform from, Trasnform to)
{
var difference = GetDistance(from, to);
return Mathf.Abs(difference.x) + Mathf.Abs(difference.y);
}
}
现在,当您需要获得绝对距离时,您可以简单地做
var difference = PositionsManager.Singleton.GetDistance(objectA.transform, objectB.transform);
var absoluteDistance = PositionsManager.Singleton.GetAbsoluteDistance(objectA.transform, objectB.transform);
Little Demo(因为我有那个,所以用了一个棋盘抽屉^^)
它只是在写上面的解释时出现在我身上:
你已经知道你在瓷砖之间的步骤:总是Mathf.Sqrt(2)
!
因此,您再次可以简单地使用您世界中的绝对位置并将它们进行比较
private float Sqrt2;
private void Awake()
{
Sqrt2 = Mathf.Sqrt(2);
}
...
// devide the actual difference by Sqrt(2)
var difference = (objectA.position - objectB.position) / Mathf.Sqrt(2);
// again set the Vector2 manually since we use Z not Y
// This step is optional if you anyway aren't interrested in the Vector2
// distance .. jsut added it for completeness
// You might need the rounding part though
var fixedDifference = new Vector2Int(Mathf.RoundToInt(difference.x), Mathf.RoundToInt(difference.z));
// get the absolute difference
var absoluteDistance = Mathf.Abs(fixedDifference.x) + Mathf.Abs(fixedDifference.y);
...
仍然完全无需处理索引。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.