计算矩阵中各个方向连接的点之间的距离

问题描述

我正在尝试制作一个在线游戏,我想在其中模拟一个四面八方连接的世界,就像“吃豆人”一样。当玩家越过地图边界时,他将位于网格的另一侧。

到目前为止一切顺利,我设法构建了一个包含 10x10 矩阵的服务器(我附上了一些 images 作为参考),并使用一些模块化算法计算并向客户端发送相应的图块给定玩家位置的地图。

因此假设以“view_distance = 2”为例,服务器根据玩家的位置发送相应的图块:

Player position (4,4)

Player position (9,5)

Player position (0,0)

我想我说得对,现在让我们面对我的问题。

当客户端从服务器获取要渲染的图块列表时,它需要计算每个图块到玩家的距离(单位向量),以便它可以在正确的位置实例化。每个实例化图块都有一个脚本,该脚本会在玩家每次移动时重新计算与玩家的距离,因此当它比“view_distance”更远时它会自行销毁。

例如,如果我的客户端在位置 (9,5),则图块 (7,7) 的单位向量将为 (-2,2)

客户端有以下信息:

  • 他所站的瓷砖:Globals.PlayerInfo.PlayerPosition
  • 地图的长度:Globals.MAP_LENGHT(在本例中为 10)
  • 视距:Globals.DATA_disTANCE(在本例中为 2)

如何计算单位向量?我做了以下功能,但它似乎不起作用。我错过了什么吗?

public static Position GetPlayerdistance(Position position)
    {
        var unitVector = new Position() { X = position.X,Y = position.Y };
        if (position.Y > Math.Truncate(Globals.PlayerInfo.PlayerPosition.Y) + Globals.DATA_disTANCE)
        {
            unitVector.Y = position.Y - Globals.MAP_LENGHT;
        }

        if (position.X > Math.Truncate(Globals.PlayerInfo.PlayerPosition.X) + Globals.DATA_disTANCE)
        {
            unitVector.X = position.X - Globals.MAP_LENGHT;
        }
        unitVector.X -= (float)Math.Truncate(Globals.PlayerInfo.PlayerPosition.X);
        unitVector.Y -= (float)Math.Truncate(Globals.PlayerInfo.PlayerPosition.Y);

        return unitVector;
    }

解决方法

你自己说吧,网格是connected in all directions。因此,由于您的网格是“无限的”,因此每个位置都存在“无限”的次数。您要寻找的不是两点之间的距离,而是多种可能性中最小的距离。

不过不用担心;) 对每个方向(上、下、左、右)进行一次检查并选择这些方向上产生的最小距离就足够了,因为无论如何其他任何距离都会更远。

我所说的只是一个例子。 说吧

  • 玩家在1,1(红色)
  • 敌人在8,2(蓝色)

所以如果我们想获得 X 轴上的最小距离,我们只需检查两个方向,向左和向右。

在这种情况下,找到左边的下一个位置是微不足道的:它是实际的玩家位置 x = 1

现在我们向右走怎么办? → 我们只是虚拟地扩展网格(浅灰色)并将玩家位置映射到它在扩展网格中的位置 → x = 11(浅红色)。

这是一张图片,可以更好地可视化

enter image description here

在代码中,这可能看起来像例如

public static Position GetPlayerDistance(Position position)
{
    // Get values local to not go through the accessors all the time
    Position playerPos = Globals.PlayerInfo.PlayerPosition;
    int playerX = (int)playerPos.X;
    int playerY = (int)playerPos.Y;

    int ownX = (int)position.X;
    int ownY = (int)position.Y;

    // On the X axis gather the next actual or virtual player position
    // where virtual means as if the grid was extended

    // Per default assume the positions are equal  
    var nextXLeft = ownX;
    var nextXRight = ownX;

    // Is the player actually left of us?
    if(playerX < ownX)
    {
        // Then trivial: the next left position is the actual one
        nextXLeft = playerX;
        // The next right position is a virtual one so we pretend
        // to extend the grid by the length and "copy" the player there
        nextXRight = Globals.MAP_LENGHT + playerX;
    } 
    // Or is the player actually right of us?
    else if (playerX > ownX)
    {
        // Just the other way round
        // this time the next position to the left is virtual
        nextXLeft = -Globals.MAP_LENGHT + playerX;
        // The next right position is the actual one
        nextXRight = playerX;
    }

    // Now we calculate the directed distances in both directions
    var distanceLeft = nextXLeft - ownX;
    var distanceRight = nextXRight - ownX;

    // use the Absolute only for comparing which is shorter
    var distanceX = Mathf.Abs(distanceRight) < Mathf.Abs(distanceLeft) ? distanceRight : distanceLeft;

    // And finally we want the smallest of both possible distances
    var distanceX = Mathf.Min(distanceLeft,distanceRight);

    // Repeat the same for the Y axis
    var nextYDown = ownY;
    var nextYUp = ownY;
    if(playerY < ownY)
    {
        nextYDown = playerY;
        nextYUp = Globals.MAP_LENGHT + playerY;
    } 
    else if (playerY > ownY)
    {
        nextYDown = -Globals.MAP_LENGHT + playerY;
        nextYUp = playerY;
    }

    var distanceDown = nextYDown - ownY;
    var distanceUp = nextYUp - ownY;

    var distanceY = Mathf.Abs(distanceUp) < Mathf.Abs(distanceDown) ? distanceUp : distanceDown;

    // Now you have a directed distance vector for both axis with the 
    // minimal absolute distance from the player
    return new Position(){ X = distanceX,Y = distanceY };
}

这是它现在如何工作的一些可视化

enter image description here


附带说明:您可能想要使用 Vector2Int 代替自定义的 Position