Reputation: 25
I'm trying to make an online game where I want to simulate a world that is connected in all directions, just like "PAC-MAN" does. When the player crosses the boundaries of the map he would be in the other side of the grid.
So far so good, I managed to build a server that holds a 10x10 matrix, (I attach some images as a reference), and using some modular-arithmetics it calculates and sends to the client the corresponding tiles of the map given the player's position.
So assuming "view_distance = 2" for example, the server sends the corresponding tiles based on the player's position:
I think I made my point, now lets face my problem.
When the client gets the list of tiles to render from the server, it needs to calculate the distance to the player (unit-vector) for each tile so it can instance it in the right place. Every instanced tile has a script that recalculates the distance to the player every time he moves so it destroys itself when it is farther than the "view_distance".
So for example, if I the client is in the position (9,5) the unit-vector of the tile (7,7) would be (-2,2)
The client has the following information:
Globals.PlayerInfo.PlayerPosition
Globals.MAP_LENGHT
(in this case it's 10)Globals.DATA_DISTANCE
(in this case it's 2)How do i calculate the unit-vector? I made the following function but it doesn't seem to work. Am I missing something?
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;
}
Upvotes: 1
Views: 605
Reputation: 90724
You say it yourself, the grid is connected in all directions
. So since your grid is "infinite" every position exists an "infinite" amount of times. What you are looking for is not one distance between two points but actually the smallest one out of multiple possibilities.
No worries, though ;) It is fully enough to check once into each direction (up, down, left, right) and chose the smallest of the resulting distances in these direction since any other one will be further away anyways.
As only one example what I am talking about. Lets say
1,1
(red)8,2
(blue)so if we want to get the minimum distance on the X axis we simply check in both directions, to the left and to the right.
In this case finding the next position to the left is trivial: It is the actual player position x = 1
.
Now what do we to towards the right? → We simply virtually extend the grid (light-grey) and map the player position to where it would be in that extended grid → x = 11
(light-red).
Here is an image to visualize it better
In the code this might look like e.g.
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 };
}
Here is a little visualization of how it works now
As a side note: There is already Vector2Int
you might want to use instead of your custom Position
Upvotes: 1