I apologize if the question has already been asked, but I can’t seem to find any answer whatsoever.
I’m trying to achieve a map that, much like in the Civilization series, wraps around itself horizzontaly, so that when the player scrolls through one side he appears on the other side.
Now, many 2D tile games implement something like this, but they usually has a fixed screen, while my map is too big to be displayed all at once (around 16km^2).
How can I achieve this effect? I thought initially to keep the player still and move the map, but there’re also plants and animals on it that should move together with the map. What would be the best course of action?
If need be i could always generate a falloff map and create bounds around the world, so that there’s no wrapping, but that is kind of a meh solution.
How about if you set bounds to the map with a buffer and set origins method,
cache both ends of the map (vector 3) and in update if the user reaches either cached point plus or minus the buffer then call the set origins method, i just wrote something along the lines of this.
For a map that large, it’s pretty important that you keep the player near the origin anyway. So, your world will be broken into tiles, only the tiles on/near the screen are actually loaded or drawn, and as the player moves, you move the map and everything on it (including plants, animals, etc. — let the scene hierarchy make this simple).
You can either move the whole world on every step of the player, or only move it (in large increments) when the player gets a certain distance from the origin.
As of right now, the method i use to load the map is exactly that. First, the map loader class checks if the player has moved more than X units and, if so, unloads the chunks out of visible range and loads the new ones. Coordinates are clamped using a simple % operation, so when the player exceeds the boundaries of the map the chunks on the other side are loaded. It works, but if I keep going in one direction, sooner or later i’ll get to a point where coordinates get fuzzy and potentially break up the game.
I thought initially about keeping the player still and move the world, but wouldn’t that be a problem with the physics? Wouldn’t the animals be affected by the movement in some way?
I’m not sure I understood your suggestion, so please, correct me if I’m wrong. What you suggest is, basically, to reset the position of the player the moment it crosses the boundaries of the map, correct? That was one of the ideas initially, but what I fear is that the player wouldn’t be able to see on the other side of the map and the feeling of a circular world would be broken. Is there any direction in which you could point me to find a solution to this?
Thanks to both of you for your answers nonetheless.
Ugh, you’re using physics? I recommend eliminating that if possible; it’s nearly always more trouble than it’s worth unless you’re making the next roll-a-ball or Angry Birds game. For simple things (running/jumping/etc.) it is easier and better to just code it yourself.
If you really can’t eliminate use of Unity’s physics, then yeah, you’ll need to be more careful. I wouldn’t move everything on every frame, but if you reset everything only when the player gets a certain distance from the origin, and move everything at once, I think it will be OK.
Why would they? Do they include scripts that depend in some way on their position? Those scripts should continue to reference map positions, which are different from actual Unity world coordinates. You will of course need functions to convert back and forth between the two coordinate systems, but I don’t see why that should be a big problem.
I’m actually quite noobish when it comes with colliders and gravity, so the reason I’m using the built-in physics is just for that, to avoid having floating items (or rather, to make the animals and plants correctly interact with the terrain).
Both plants and animals already reference map positions aniway, it’s just the idea behind moving them all around following the map (since they’re not anchored to the map but rather laid upon it) that I’m afraid might not work.
This being said, I kept looking for some ideas and someone suggested using two cameras, one following the player and the other on the opposite side of the map, changing the viewport so that when on the border, part of the scene is rendered from one camera and the other part from the second one. Then it’d be only a matter of teleporting the player (and, of course, every object which has a path that crosses the border) on the other side of the map.
You’re still quite likely to run into floating-point issues when you have wandered kilometers away from the origin. All positions (and speeds etc.) in Unity are represented with floats, which have only 32 bits of precision. That’s just not enough to work with meter-sized (or smaller) objects and positions, km away from zero.
Also, using physics just to keep things on the terrain is silly. Drop a ray down, see where it intersects the terrain, and set your transform.position accordingly.
I wish you luck with your project, but I see you have (twice now) chosen the Way of Pain.
If I understand correctly, this means that, say, going 4kms away from the origin will cause problems with floats? I’m not skeptical, I just don’t know enough about this subject and am curious.
My idea is that, when the player reaches the [1999;-20] coordinate and goes east, he will be teleported at the [-2000;20] coordinate. The rendering of the other side of the map could be done with a strategically placed extra camera and a change of the viewport so that both are used in the right percentage. This would work, if there wasn’t any problem with floating point vars, but now I’m not sure it’ll work anymore.
I agree with you that it’s silly, but again, I’m quite noobish when it comes to keeping things on ground without anchoring it. I’m going to look for guides on how to do this with raycasts asap, if it’s faster and frees me from having troubles with the terrain then that’s a very good thing to study
Thanks I sure hope I can get out of this mess that I oh so lovingly put myself into!
sorry to jump on this, what I’ve never workout, if for example you have a top down hack and clash game with monsters running around, could this system still work I’ve done it in pure .net winforms as an example no monsters just a circle moving around, but if you unload the tiles effectively how do you track if a monster bumps into a wall etc if it’s not there?
although all my maps are small 33 x 33, it would be nice to know for the future.
generally you don’t. For unloaded tiles if you want to continue to simulate what is going on there it’s usually in a more abstract fashion (50% chance of new monster spawning, 10% chance a new loot item appears etc.), but it’s done within the game logic/data not within the scene.
If a tree falls down and no one is around to see it… just spawn a fallen log next time they go by
This page is a pretty good explanation of how floats work, though they fail to go into precision problems. Basically you have 23 bits to represent the number, plus a sign and an exponent. So that means, if your numbers are generally less than 10, you can represent things with a precision of about 10/2^23. That’s really good — if our units are meters, then this is a precision of about 0.001 millimeter.
But if you’re, say, 10 km away from the origin, then the best precision you can get is 10000/2^23, which is a little over a millimeter. That means you can’t move something less than a millimeter. Worse, it may even mean that vertices of a mesh can’t be positioned more precisely than within a millimeter or so of where things are supposed to be. And when you’re trying to do physics calculations, and can’t do better than a millimeter precision, weird stuff can start happening, where things don’t collide that should, or slow-moving objects stop entirely, etc.
Actually it’s not all that bad at this point, but when you start getting hundreds or thousands of km away from the origin, then it really becomes problematic.
In your case, going no more than 2000 units from the origin, you might be fine. It’d make me nervous, but you might get away with it nonetheless.
It’s definitely an important technique to have in your toolkit! The Physics.RayCast reference has some decent sample code. The most relevant one in this case is this one:
using UnityEngine;
public class RaycastExample : MonoBehaviour
{
public Missile missile;
void FixedUpdate()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 100.0f))
print("Found an object - distance: " + hit.distance);
}
}
…which casts a ray down from the object’s position. If you want to be sure to hit the terrain, you could instead start at a high altitude (higher than any point in the terrain), and leave out the maxDistance parameter so the ray keeps going until it hits something.
There’s also a layer mask available that will allow your ray to ignore everything except the terrain. So then you know where the terrain is below the object, and you just set its Y position to that.
That was a really good explanation, thank you! It’s definitively something I have to sink my teeth into so I’ll be more aware when using floating point vars from now on.
Also, thanks for the tip on Raycast, this sparked more curiosity about that part of Unity! I’m going to study the argument asap.