2d game depth?

Started by
4 comments, last by AgroTemp 12 years ago
I am currently creating a 2D game, and I need help with depth.

Basically I need to make sure images are where they are supposed to be. For example, a tree is in front of the player. Or the player is behind the tree.

The way I'm handling this right now is adding the Y of the image to the Y position of the first non-transparent pixel in the sprite, and then I compare it to the other objects. Then I place it where I need to.

I figured out this works up to a point, but after that it stops working. Can anybody explain a more efficient working way to do this?
Advertisement
assuming the game is a side scoller:

Well, if you're using OpenGL with orthographic projection, you can just directly use the z-values while translating the model view matrix. If not, you'll probably need to keep a 2 dimensional array.

Something like this:
Renderer *objects[mWindow::drawSprite(Renderer *r){
int layer = r->getLayer();
int numObjects = this->numObjects[layer];
this->objects[layer][numObjects] = r;
this->numObjects[layer]++;
}
axObjects][maxLayers];

and when you call draw() or something similar, you pass the z-value either as a parameter or as a member variable, and you just push the object in the correct slot. you'll also need to keep another set of integers to find out how many objects are present in a layer. something like
int numObjects[maxLayers];

Afterwards, you should have a dedicated function that loops through the 2 dimensional array and draws the objects - from the layer that's to the back to the layer that's at the front.

Hope that helps :)

a WIP 2d game engine: https://code.google.com/p/modulusengine/

English is not my first language, so do feel free to correct me :)

You haven't mentioned what graphics API you're using, but the principle is the same regardless: sort all your sprites by the order of their appearance before drawing them or draw each sprite into a separate graphics layer then draw all the layers in order onto to the main screen.
I second zoneweb's response: Draw back to front. If you're drawing 'on your own' (pixel by pixel into a bitmap), or you're using someone else's software renderer, it's the easiest way.

The downside of drawing back to front is you need to sort, which means you need to know all of what you're going to draw before you draw it. (Unless you have hardcoded stages like 1) draw background 2) draw player/enemies 3) draw foreground objects, but this is inflexible). To avoid a costly qsort with a large number of objects, bollµ had a good suggestion of using buckets for each layer. (Although I would probably use a vector for each layer, instead of a fixed size 2 dimensional array.) But if you don't have that many things to draw, qsort is pretty fast; how many sprites are you drawing at once?

If you're using hardware, it may seem temping to draw in any random order and use the z-buffer, but that only works if you are using alpha-testing for transparency. If you have nice smooth 'fuzzy' alpha values around your sprites, you'll need to draw back to front to keep things from looking weird around the edges.

There is also a front-to-back drawing algorithm that preserves alpha ( http://hacksoflife.blogspot.com/2010/02/alpha-blending-back-to-front-front-to.html ), but it's backwards of what you would normally do, and you have to sort anyway. If you're sorting, you might as well do it the 'normal' way.
What I do is I have vectors/arrays of sprites for each layer of drawing. I have four background layers with the first being static and non moving, like a blue sky. The next three are slow scrolling backgrounds with the next drawn moving faster than the previous to create an illusion of depth. So like I could have clouds, then mountains, and then trees. Next I draw all my sprites that are not animated that are behind the player, and then all sprites that are animated behind the player. Since I use tiles for my terrain I draw any terrain that is behind the player next, then the player and enemies, then any terrain in front of the player(ex. grass). Then nonanimated sprites in front of the player, then animated in front, then any foregrounds that are tied to a world position(ex. water), and then world foregrounds(like leaves flying through the air, fog etc.). It works for me and no real sorting is needed as long as I save the sprite locations in the level the same way I draw them, in groups.
I am using the SDL library. I figured out a new solution and I'm not sure it will last, but it suits my needs for now. Basically, I just check the last y-wise pixel and add it to the y location of that. Since all of my entities(trees, tiles, NPCs) are inside a list, I sort the list. The function I created puts in order based on the last Y pixel. After testing with it, it works really well. It even allows being hidden(or being behind a wall). Here is the code I can offer:

bool sort(Entity* e, Entity* f) {
if(e->getY() + e->getSprite()->getLastYPixelPosition() < f->getY() + f->getSprite()->getLastYPixelPosition()) {
return true;
}
return false;
}

This topic is closed to new replies.

Advertisement