I need to create a feeling of depth for my 2D game. What I got so far is this:
The tree sprite is partly transparent, if the player’s z position lies behind the tree, it looks like he’s standing behind the tree. The problem is to set the depth value correctly. For the trees that’s rather simple. I created this script:
// y coordinates go from -10 to 10
public float offset=0;
public float deltaZ=1;
public float size=1;
void Update () {
transform.position = new Vector3(
transform.position.x,
transform.position.y,
offset + deltaZ * (transform.position.y-size + 10) / 20);
}
The script increases the z position, if the object moves up. That means that objects with a higher y coordinate appear behind objects that are “lower”. The strange calculation of the z coordinate works like this:
-
The offset is used to manage different layers of the game. If something should be in the background, you can increase the offset. For example: Offset 1 = background, Offset 0 = middleground, Offset -1 = foreground.
-
deltaZ is the maximum increase in the z value. If the object is at the lowest possible y coordinate, it just gets the offset as its z position. If it’s at the very top of the scene, it’s got a z value of offset+deltaZ
-
size is half the size of the object. This is necessary because in unity3d the position of an object is its middle-point. So the position of a sprite of a normal person would be somewhere around its waist. I need to position the objects according to their feet. Therefore the size is substracted from the y coordinate.
-
Since y coordinates in my scene go from -10 to 10, the y position +10 is somewhere between 0 and 20. Divide this by 20 and you got the percentage of deltaZ that needs to be added.
The script actually works rather nice. I added it to all objects in the scene. But there’s a problem.
What do I do with objects that are rotated ? Here’s a wall with the above script.
The player needs to be drawn behind the wall if he approaches from the left but before the wall if he comes from the right. I could probably add another script that modifies the z coordinate based on the x coordinate. But it’s already very difficult to get the correct behaviour out of the script. There’s a lot of experimenting involved till you find the right value for the size. I fear this would be complicated. Moreover, even if I modified my ZBuffer script, what about walls that are turned in the other direction ? Then I would have to invert the sorting.
Right now I’m using polygon colliders as a dirty workaround. The player is prevented from standing in positions were the graphical errors could be seen. But that means that his movement is rather restricted.
Is there a way to work around this ? Do you know a solution ? Right now I’m thinking about something like raycasting. I would use the basic ZBuffering based on the y position for simple things like trees. For these walls i could create a script that casts a ray from the players feet up along the y axis each frame. If the ray hits something, it must be behind the player. Do you think this would be a performance issue ? Eventually there will be other characters in the game. A few small animals maybe. A raycast for each of them for each frame ? I wouldn’t like to start creating this script, which would surely take me hours, only to find out that the hardware can’t handle it.