1. Computing

Z-Ordering and Layering in Gosu

By

Z-Ordering and Layering in Gosu
Z-Ordering and Layering in Gosu

As soon as you start drawing more than one thing on the screen, you have to consider which will be rendered in front of the other. It makes no sense for the background (which typically covers the entire screen) to be rendered in front of the player and enemies, or for things to be rendered behind the background.

Gosu uses a 3D rendering interface to render 2D images. Because of this, it has easy access to Z-ordering, or putting images in front of or behind each other. In a 3D scene, this Z-ordering would determine how far "into" the screen objects are. It's the same in a 2D scene except there's no perspective, images rendered at a Z-layer far "into" the screen are the same size as images rendered at a "closer" Z-layer. Likewise, images rendered at a Z-layer far "into" the screen will be rendered as if they are "behind" images at a closer Z-layer.

We've seen Z-ordering in this article series before. When we created a window, we rendered the background at Z-layer 0. Later when we loaded an image, we rendered that image on Z-layer 1. If we rendered both at once, since the image has a higher Z-layer, it would be rendered in front of the background. The higher the Z-layer, the closer to the screen the image is. The lower the Z-layer, the farther away it is.

The following program will render two rectangles. These rectangles are overlapping and rendered at Z-layers 0 and 1. When the space bar is pressed (more on input in a later article), the Z-order will be reversed and the opposite rectangle will be displayed in front.


#!/usr/bin/env ruby
require 'rubygems'
require 'gosu'

class MyWindow < Gosu::Window
 def initialize
    super(640, 480, false)
   
    @order = [0, 1]
 end

 def draw
    c1 = Gosu::Color.new(255, 0, 0, 255)
    c2 = Gosu::Color.new(255, 255, 0, 0)
   
    draw_quad(
     100, 100, c1,
     200, 100, c1,
     100, 200, c1,
     200, 200, c1,
     @order[0]
    )
   
    draw_quad(
     150, 150, c2,
     250, 150, c2,
     150, 250, c2,
     250, 250, c2,
     @order[1]
    )
 end

 def button_down(id)
    @order.reverse!
 end
end

MyWindow.new.show

Magic Numbers are Bad

Up until now, we've been hard-coding Z-layer numbers into the program. This is not a good practice. What is "Z-layer 0?" It could be anything, it's best to have names for your Z-layers.

One very common idiom you see in Gosu programs is a Z-order module. In this module, there are a number of constants that represent the Z-layers used in the game. These are assigned to integers by assigning a range (converted to an array) to the list of constants. Those listed first in the module will be rendered behind those listed later in the module.

While it's generally a bad idea to have single-letter module names (especially in the global namespace), since the Z-ordering module will be referred to quite often, I've named it simply Z. If this is a problem, you can name it something like ZOrder.


module Z
 Background, Player = (1..100).to_a
end

Now, whenever you need to refer to one of these layers (when drawing an image, for example), you simply need to use the constants Z::Background or Z::Player.

This article is part of a series. Read more articles about Rapid Game Prototyping in Ruby

©2014 About.com. All rights reserved.