Whether you go with the torus option or not, you will need to do some wrap around, which will be the root of all the problems you will need to solve. However, they’ll be easier to address on a torus.
The idea is that your world is a grid that repeats itself along both the X and Y axes.
Position wrap around
When an object’s X or Y position goes over 1.0f (or whatever the world size is), it wraps around to 0.0f. Where you generally do computations such as:
position += velocity * time;
You add wrap around logic:
position += velocity * time;
if (position.x >= 1.0f) position.x -= 1.0f;
else if (position.x < 0.0f) position.x += 1.0f;
if (position.y >= 1.0f) position.y -= 1.0f;
else if (position.y < 0.0f) position.y += 1.0f;
Or, avoiding tests and securely handling the large velocity cases:
position += velocity * time;
position.x -= floorf(position.x);
position.y -= floorf(position.y);
Having 1.0f
as the world size allows you to use floorf()
, roundf()
etc. immediately. Otherwise, you will need to use constructs such as WORLD_SIZE * floorf(value * (1.0f / WORLD_SIZE))
instead.
Distance computation
Computing distances changes, too. If you have two objects and one of them has position.x = 0.1f
and the other has position.y = 0.9f
then the distance is 0.2f
, not 0.8f
. So instead of the following distance function:
float distance(vec2 p1, vec2 p2)
{
vec2 d = p2 - p1;
return sqrtf(d.x * d.x + d.y * d.y);
}
You need to account for wrap around:
float distance(vec2 p1, vec2 p2)
{
vec2 d = p2 - p1;
d.x -= roundf(d.x);
d.y -= roundf(d.y);
return sqrtf(d.x * d.x + d.y * d.y);
}
Rendering
Rendering will be tricky, too. You have several possibilities:
- when the camera reaches
0.0f
or 1.0f
, render the necessary parts from the other side of the map translated by combinations of (1.0f, 0.0f)
or (0.0f, 1.0f)
.
- always leave the camera at
(0.5f, 0.5f)
and move the whole world instead of the camera at each frame
These are fundamentally the same, but the way you see it will dictate your data structures. The best strategy here will probably depend on the culling mechanism you have.
Edit: sorry, I didn’t realise this was XNA. You will need to replace roundf
and others with the equivalent Math.Round()
etc.