advertisement

Print

Creating Games in Ruby (Part 2)
Pages: 1, 2, 3, 4

For comparison's sake here are a couple of screenshots of a game packaged with the RUDL library that was covered in Part One. It is similar in that it also involves blasting holes in the landscape. It features tanks instead of toy soldiers. The little square boxes are the tanks. Its remove_dirt method makes it look like dirt was displaced by rendering a black circle where the projectile dropped. This only works with a black background. With an ImageMagick-based implementation, there are no such restrictions. RMagick integration opens up so many possibilities.

Demo game packaged with RUDL
Figure 2. Progressive screenshots of a demo game packaged with RUDL (written by Brian Palmer, Pocket Martion Software)

Below is the code from the Gosu demo that makes it look like craters with charred rims are left in the earth or the star. In the top code block, circle and fill create a black circle, and shadow creates a blurred version of the circle. The second code block shows how these shapes are used in conjunction with the RMagick composite! method to complete the effect. After each shot is fired, the application loops through the tiles that comprise the background (@rmagick_images) and determines which ones were near the blast. The sequence of calls in the second code block is made for each tile that was "hit." The shadow is placed on the background image by passing the Atop flag to composite!. Next the DstOutcompositeOp flag is passed to composite! to add the smaller smoother crater image. The DstOutcompositeOp flag indicates that a space the size and shape of the image should be erased.

if not @crater_image then
  @crater_image = Magick::Image.new(50, 50)
    {self.background_color = 'none'}
  gc = Magick::Draw.new
  gc.fill('black').circle(25, 25, 25, 0)
  gc.draw(@crater_image)
  @crater_shadow = @crater_image.shadow(0,0,5,1)   
end

Circle and its shadow
Figure 3. The circle and its shadow created with calls to circle() and shadow()

@rmagick_images[index].composite!(@crater_shadow,
  center_x - 35, center_y - 35,  
  Magick::AtopCompositeOp)

@rmagick_images[index].composite!(@crater_image,
  center_x - 25, center_y - 25, 
  Magick::DstOutCompositeOp)

A tile with a solid shadow and a tile with an
Figure 4. A tile with a solid shadow and a tile with an "erased" circle

The very latest release of Gosu features another variation on the standard Gosu tutorial. The new demo (Figure 5) incorporates a 3D background, courtesy of OpenGL. Gosu has long used OpenGL for rendering behind the scenes (recently for Windows, longer for other platforms), shielding developers from the OpenGL API. Now developers can access the OpenGL API selectively to add 3D effects to their 2D games.

 The standard Gosu tutorial with a 3D background
Figure 5. The standard Gosu tutorial with a 3D background

The first code fragment below shows that a block of OpenGL API calls can be passed to the new gl method. Most of the OpenGL API calls are encapsulated in the exec_gl method, which creates the mountain range effect by displaying the same texture over and over with a random height.

The bottom fragment is excerpted from the exec_gl code. The background is composed of multiple triangles, which have vertexes in common. Instead of making a separate set of glVertex3d calls for each surface, which would result in specifying the same vertex more than once, the GL_TRIANGLE_STRIP OpenGL API specifier is used. With GL_TRIANGLE STRIP you declare 3 or more vertexes and OpenGL takes care of connecting them all with triangular surfaces. This code listing shows just one of the 4 vertexes defined in the application. The scrolling background is composed of multiple GL_TRIANGLE_STRIPs.

def draw
  gl do
    glClearColor(0.0, 0.2, 0.5, 1.0)
    glClearDepth(0)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    @gl_background.exec_gl
  end   
  ... 
end
def exec_gl
  info = @image.gl_tex_info
  ...
    0.upto(POINTS_Y - 2) do |y|
      0.upto(POINTS_X - 2) do |x|
        glBegin(GL_TRIANGLE_STRIP)
          z = @height_map[y][x]
          glColor4d(1, 1, 1, z)
          glTexCoord2d(info.left, info.top)
          glVertex3d(-0.5 + (x - 0.0) / (POINTS_X-1),
            -0.5 + (y - offs_y - 0.0) / (POINTS_Y-2),
            z)
          ...
        glEnd
      end
    end
end

The OpenGL API method names in the Gosu code look different than the names used in the RUDL example in Part One because Gosu is integrated with the ruby-opengl library, while the RUDL sample uses an older Ruby/OpenGL library. The way the OpenGL API calls are structured, however, is identical in the RUDL example and the Gosu example.

Look for the ability to input text so high scores can be entered and socket support in future Gosu releases.

Ogre.rb
Creator and Lead Developer: Jason Roelofs

Shattered Ruby
Co-Creators and Co-Lead Developers: Martyn Garcia and Mikkel Garcia

Given what it takes to hand code 3D effects using OpenGL, I'm sure you can see why people use 3D modeling software for more complex characters and scenes. Now we're going to explore two Ruby projects that leverage full-blown 3D models: Ogre.rb, a 3D graphics rendering engine, and Shattered Ruby, a 3D game development framework that is built on top of Ogre.rb.

Ogre.rb is a Ruby wrapper around OGRE, which stands for Object-Oriented Graphics Rendering Engine. It is used for combining 3D models, textures, and other kinds of graphical content into a scene. There are ways to incorporate special effects including wind, rain, smoke, photo-realistic explosions, and sophisticated lighting techniques.

Ogre.rb comes with a testing helper that sets up a generic scene manager and leverages class variables so that a new window does not need to instantiated for each test.

Below is a video clip (click on the screenshot to view the video clip) from one of the sample scenes packaged with Ogre.rb. It's actually a Ruby port of one of the demos packaged with OGRE. The green ogre head is an example of a 3D model. Using arrow keys or the mouse, you can navigate around the screen and view the ogre head from the side or from the back. The front is not just a facade. It's fully rendered in fine detail 360 degrees around.

OGRE is written in C++, and Ogre.rb creator and lead developer Jason Roelofs initially used SWIG to help generate the C++ extensions for Ruby. Because SWIG does not provide support for wrapping nested classes, however, he found he could not move forward with Ogre.rb after he finished wrapping the main OGRE classes. After researching different binding strategies, he decided to put Ogre.rb development on hold to build a Ruby/C++ interoperability suite in the mold of luabind and Boost.Python. He plans to rebuild Ogre.rb from scratch using the new toolset. In the meanwhile, he will continue to support the most recent release of Ogre.rb.

Shattered Ruby is a 3D game development framework inspired by Ruby on Rails and built on top of Ogre.rb.

Somehow, the creators and lead developers of Shattered Ruby, Martyn and Mikkel Garcia, find ways to talk about every aspect of 3D game development in terms of Ruby on Rails. For example, there's a post in the Shattered Ruby forum in which Martyn manages to liken Shattered to Rails, even as he's pointing out a way in which Rails and Shattered are not only different, but diametrically opposed. He points out that the Model in Rails is more complex than the typical Shattered Model, while the View in Shattered, which is typically a 3D View, is way more complex than the View in a Rails app. He concludes that Rails gets a lot of mileage out of being able to make assumptions about the Model, while Shattered can do the same with its Views.

Pages: 1, 2, 3, 4

Next Pagearrow