Understanding Z-Ordering

 

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:

 

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>