Introduction:
The term Z-Ordering can mean something different depending on context. In the realm of 3D graphics, I've seen it described as "...to derive closed-form relations for the difference between the node indices, which can be used to browse the tree in constant time." That's NOT the way we'll be using it in this article ;)
Since we'll be applying Z-Ordering to a 2D graphics plane, I'll define the term as "the drawing of graphical elements in order of their height in respect to graphics plane."
These are the planes of drawing. Anything that you draw on plane -1 will be "under" anything drawn on plane 0 or plane 1, as anything on plane 0 will be "under" anything drawn on plane 1.
Note that the only plane completely visible is plane 1.
Why Would I Want to Use Z-Ordering?
There are a ton of reasons you'll wanna use this concept. If you take the standard space game, for example, you would probably want your ship to look as if it's hovering over a planet. Or maybe you'll have a neat little code that let's you hide behind planets (in multiplayer maybe?). How are you going to visually do that? The only way is to control the order in which you draw the planet and the ship.
Let's say that you're doing a football game (which kinda sparked this tutorial in the first place...thanks to "msephton" on the BlitzBasic board for starting the discussion ;)). You'll need to have a way to show the ball if front of the players, or behind...heck, you'll need a way to show the players to the front or back of other players in or it'll look REALLY weird. Z-Ordering handles that.
Another example would be a side-scroller. Pretend you have this little character running along a grassy, er, tile set, and behind him is a line of trees. Up ahead is a water fall...but wait...it's flowing IN FRONT of the grassy tile set! Your character gets up to that point and nearly disappears through the waterfall... he's BEHIND the waterfall! In order to do this...we'd draw in this order:
- Draw the trees
- Draw the grass
- Draw the player
- Draw the waterfall
So the grass is on top of the trees, and the player is on top of the grass, and the waterfall is on top of the player. Since we can use transparency in our images, it gives us the illusion of depth!
Okay, Quit Teasing...How Do I Use This?
No idea. JUST KIDDING! It's actually quite simple. One way is define certain images ahead of time to have a certain plane. This works great in the case of the side-scroller. You define either an Array or Type (depending on your preference) that contains all of the Plane 0 elements. Then others that contains all the Plane -2, Plane -1, Plane 1, Plane 2, etc...(however many you want, really). Next you simply start at the lowest Plane and draw it, then move up to the next, draw it, and then continue that cycle until they're all drawn.
Sometimes you'll want to be more dynamic (as in the case of the football game). In this case, you'll need to have the ZOrder for each Image dynamic. This way, depending on comparisons in your game, you'll be able to change the value of ZOrder in your "Update" phase and watch that change take effect in your "Render" phase.
Here is a piece of code that simply grabs three images and moves them over each other based on ZOrder. With only 3 images, this is REALLY unnecessary, but it gets the point across of HOW to use this technique. The code with graphics and such can be downloaded here.
; setup our graphics mode Graphics 640,480 ; set the Backbuffer as the drawing surface ; for page flipping SetBuffer BackBuffer() ; load up our dummy images Wall_Image = LoadImage("graphics\walltile.bmp") Stoop_Image = LoadImage("graphics\stoop1.bmp") Knight_Image = LoadImage("graphics\knight.bmp") ; create a type that has which image to use, where ; to draw it, a direction to show the ZOrdering in ; action, and the ZOrder of the image Type Images Field ImageToUse Field X,Y Field iDir Field ZOrder End Type ; create an instance of the Images Object, starting it ; moving from right to left, and starting it ; as being "behind" the baseline plane. Make this ; one the "wall" (or big blue square) NewImage.Images = New Images NewImage\ImageToUse = 0 NewImage\X = 125 NewImage\Y = 100 NewImage\iDir = -1 NewImage\ZOrder = -1 ; create an instance of the Images Object, no movement, ; And starting it as being ON the baseline plane. ; Make this one the "Knight" image NewImage.Images = New Images NewImage\ImageToUse = 1 NewImage\X = 100 NewImage\Y = 100 NewImage\iDir = 0 NewImage\ZOrder = 0 ; create an instance of the Images Object, moving from ; left to right, and starting it as being "In Front of" ; the baseline plane. Make this one the the little rock ; image NewImage.Images = New Images NewImage\ImageToUse = 2 NewImage\X = 75 NewImage\Y = 100 NewImage\iDir = 1 NewImage\ZOrder = 1 ; quit only if the user hits ESC While Not KeyHit(1) ; clear the screen Cls ; Use this FOR...NEXT loop to cover each ZOrder plane of ; drawing. So, if we're at -1, that will be the bottom. ; 0 will be the middle (or baseline), and 1 will be the top. For Planes = -1 To 1 ; run through each of our images For NewImage.Images = Each Images ; see if the current image is on the Plane we're on If NewImage\ZOrder = Planes ; if so, see what image we need to draw Select NewImage\ImageToUse ; it's the wall image Case 0 DrawImage(Wall_Image,NewImage\X,NewImage\Y) ; this is just for looks, but it moves the ; wall back and forth Select NewImage\iDir Case 1 NewImage\X = NewImage\X + 1 If NewImage\X > 125 NewImage\iDir = -1 EndIf Case -1 NewImage\X = NewImage\X - 1 If NewImage\X < 75 NewImage\iDir = 1 EndIf End Select ; it's the Knight image Case 1 DrawImage(Knight_Image,NewImage\X,NewImage\Y) ; it's the rock image Case 2 DrawImage(Stoop_Image,NewImage\X,NewImage\Y) ; this is just for looks, but it moves the ; rock back and forth Select NewImage\iDir Case 1 NewImage\X = NewImage\X + 1 If NewImage\X > 125 NewImage\iDir = -1 EndIf Case -1 NewImage\X = NewImage\X - 1 If NewImage\X < 75 NewImage\iDir = 1 EndIf End Select End Select EndIf Next Next ; put up a little text telling the user how to change the ordering Text 0,300,"Press the spacebar to change the ZOrder" ; if the user hits the spacebar If KeyHit(57) ; run through the image list again For NewImage.Images = Each Images ; determine the ZOrder value and change it accordingly ; -1 will change to 1, 0 to -1, and 1 to 0...again, this ; is just so the user can see it in action Select NewImage\ZOrder Case -1 NewImage\ZOrder = 1 Case 0 NewImage\ZOrder = -1 Case 1 NewImage\ZOrder = 0 End Select Next EndIf ; flip the pages so the user will see the animation's effect Flip ; end of the While loop Wend ; end the program End |
For fun you could hook up a function that puts a bunch of these images up in Random x,y locations, with Random Z-Orders. Should be a pretty simple thing to do and it could help you get your hands dirty in this coding practice ;)
Conclusion
Hopefully this gave you a basic idea on how 2D Z-Ordering works, why it's useful, and how to use it.
Until next time...cya!
This tutorial is by Christian Coders>