Ruby Game Programming II

(2.1) Introduction to Gosu

Now to kick part II off I've decided to switch from Zelda to a more traditional RPG game. It's your decision to choose what tileset/sprites suite your game needs. The only reason I decided to switch was because there's so many independent Zelda games out there that there's no real point in re-inventing the wheel. We should do something unique and original with our GAMENAO game series.



If you reading this part it means:

  • Ruby is installed and working
  • You've written your first "Hello World" game

Now to get things started we need to setup a new game directory if you haven't already.

Download and extract the game directory http://www.gamenao.com/download/shiningforce.zip

C:/Game/controllers/
C:/Game/media/
C:/Game/models/
C:/Game/views/
C:/Game/main.rb

You directory root should look something like the above. Why is there a controllers, models, and views folder? We're going to use something called the MVC (Model Viewer Controller) Framework. Many of todays games use this framework to separate and modulate program logic. In todays example will create a player controller which will have functions for a players movement eg. (Left, Right, Up, Down). The model will have a base structure for our player which will include his/her stats and position on the screen. Finally the views folder will hold map data for our game. It's simple if you think of MVC as what I just decsribed above, we're just modulating our program instead of sticking it in one big file (which would get messy). To learn more about MVC read http://en.wikipedia.org/wiki/Model-view-controller

Now that we have our little directory setup it's time to start programming! If you open your "main.rb" you should see the following

ruby Code:
  1. begin # In case you use Gosu via RubyGems.
  2.   require 'rubygems'
  3. rescue LoadError
  4. end
  5.  
  6. require 'gosu'
  7.  
  8. class MyWindow < Gosu::Window
  9.      def initialize
  10.          super(640, 480, false, 20)
  11.          self.caption = 'Shining Force: Legend of Ruby'
  12.          @song = Gosu::Song.new(self, "media/music/castle01.mp3")
  13.          @song.play(true)
  14.      end
  15. end
  16.  
  17. w = MyWindow.new
  18. w.show

Now i've highlighted some lines that I want to bring your attention too. At the top we have our few lines that
include the Gosu game engine.

The first line:

Code:
class MyWindow < Gosu::Window

What you see here is a class defined with the name "MyWindow". Gosu has their own Window class which we will be extending onto using "< Gosu::Window"
Now for those who don't know what a Class is it's a simple structure for holding user-defined functions for example:

ruby Code:
  1. class MyClass
  2.  
  3.   def initialize(name, age)
  4.     @fullname = name
  5.     @age = age
  6.   end
  7.  
  8.   def printName
  9.     puts @fullname
  10.   end
  11.  
  12.   def printAge
  13.     puts @age
  14.   end
  15.  
  16. end

If you write the above to a file, let's call it example.rb and open up "irb" and type require 'example.rb' it should load the class into memory.
Now let's create the class object by typing

Code:
irb(main):011:0> myobject = MyClass.new("Richard", 21)
irb(main):011:0> myobject.printName
Richard

As you can see we create the class by using .new() and store the object it creates in myobject. To call the function we simple type myobject.printName

The second line:

Code:
super(640, 480, false, 20)

This one is a bit easier, super() modifies variables in the Gosu::Window class (Remember the class we were extending?). This class holds the width, height of our screen. the syntax you see here is

super([screen width], [screenheight], [fullscreen], [framerate])

The third line:

Code:
@song = Gosu::Song.new(self, "media/music/castle01.mp3")
@song.play(true)

It's also pretty straight-forward, as you see we're using Gosu's Song class Gosu::Song.new() what might be a little unclear is what we're passing it (self, [song]).
Now if you lookup the Song() class in Gosu's documentation http://code.google.com/p/gosu/wiki/RubyReference

class Gosu::Song

  • initialize(window, filename)
  • play(looping = false): Also used to resume paused songs.
  • pause
  • paused?
  • stop
  • playing?
  • volume, from 0..1.
  • volume=(vol), with vol from 0..1

As you can see we're passing the Song class the current window self and the MP3 we want to play

Lastly:
w = MyWindow.new
w.show


Obviously this creates our window object and starts up the window.

Moving on

(2.2) Creating the player model

That's right! It's time we start drawing stuff to the screen! The most exciting part you've all been waiting for
First we need to define the player objects structure inside the model directory. Go ahead and create an empty file for our
player model called "models/player.rb" inside this file we can workout the basic shell for our player.

NOTE: @y += 4 is a short form for @y = @y + 4

ruby Code:
  1. class Player
  2.  
  3.    def initialize(window, x, y)
  4.          @x, @y = x, y
  5.  
  6.          @player  = Gosu::Image.load_tiles(window, "media/down.png", 47, 47, false)
  7.          @up       = @player [0..1]
  8.          @right   = @player [2..3]
  9.          @left      = @player [4..5]
  10.          @down   = @player [6..7]
  11.    
  12.          @cur_image = @down
  13.  
  14.      end
  15.  
  16.      def walk_up
  17.          @cur_image = @up
  18.          @y -= 4
  19.      end
  20.  
  21.      def walk_right
  22.          @cur_image = @right
  23.          @x += 4
  24.      end
  25.  
  26.      def walk_left
  27.          @cur_image = @left
  28.          @x -= 4
  29.      end
  30.  
  31.      def walk_down
  32.          @cur_image = @down    
  33.          @y += 4
  34.      end
  35.  
  36.      def draw(offset_x, offset_y)
  37.          img = @cur_image[Gosu::milliseconds / 500 % @cur_image.size]
  38.          img.draw(@x - offset_x, @y - offset_y, 0, 1.0, 1.0)
  39.      end
  40.  
  41. end

Let's jump into the complicated stuff!

@player = Gosu::Image.load_tiles(window, "media/down.png", 47, 47, false)
@up = @player[0..1]
@right = @player[2..3]
@left = @player[4..5]
@down = @player[6..7]

As you can see here your loading the picture media/down.png and slicing it up into 47x47 blocks when you do this
an array of 47x47 block pictures will be stored in @player


[0].......... [1]........ [2]...... [3] ......[4] .......[5] ......[6]....... [7]

As you can see,
@up corresponds to @player[0..1] (0 through 1)
@right corresponds to @player[2..3] (2 through 3)
. . .
etc.

Only one last thing to explain:

Code:
img = @cur_image[Gosu::milliseconds / 100 % @cur_image.size]

You're probably wondering what this line does? Simple, it's going to alternate through our two images every 100 milliseconds
@cur_image.size would be how many pictures were in the array for it to alternate between. I'll go over modolus for those who haven't taken
University mathematics courses yet in a later tutorial for now, just remember this is going to alternate between 0 and 1 every 100 milliseconds

Finally img.draw() draws our player to the screen, now before we can see this Player class in action we have to include it! Open up main.rb and
add the following lines:

ruby Code:
  1. begin # In case you use Gosu via RubyGems.
  2.   require 'rubygems'
  3. rescue LoadError
  4. end
  5.  
  6. require 'gosu'
  7. require 'model/player'
  8. class MyWindow < Gosu::Window
  9.   def initialize
  10.     super(640, 480, false, 20)
  11.     self.caption = 'Shining Force: Legend of Ruby'
  12.     @song = Gosu::Song.new(self, "media/music/castle01.mp3")
  13.     @song.play(true)
  14.    
  15.     @player = Player.new(self, 320, 240)  
  16.  
  17.   end
  18.  
  19.   def update
  20.     @player.draw(0,0)
  21. end
  22.  
  23. end


Now because this class extends Gosu::Window the function def update is visited every game tick. Which means its going to loop through drawing and re-drawing our character on the screen. This is how a video game works, it's a big continuous loop checking updates.

Execute and run your main.rb file and see if you get the character walk animation working ( If it doesn't work, try to find out where the error is, Ruby will give you a filename and line number). Now let's trace our steps, what exactly is Gosu doing to create this walk animation:



(2.3) Creating the player controller

Now it's time to make our player move! Will have to make a few changes to the main.rb file to
setup the controller for our character.

ruby Code:
  1. class MyWindow < Gosu::Window
  2.   def initialize
  3.     super(640, 480, false, 20)
  4.     self.caption = 'Shining Force: Legend of Ruby'
  5.     @player = Player.new(self, 50, 50)
  6.     @controller = Controller.new(self, @player)
  7.     @song = Gosu::Song.new(self, "media/music/castle01.mp3")
  8.     @song.play(true)
  9.   end
  10.  
  11.   def update
  12.     @player.draw(0,0)
  13.     @controller.update()
  14.   end
  15. end

After adding the controller class to main.rb we have to create it! Change the directory to controllers/ and create a file called player_controller.rb

ruby Code:
  1. class Controller
  2.   def initialize(window, player)
  3.         @window = window
  4.         @player = player
  5.   end
  6.  
  7.   def update
  8.         if @window.button_down? Gosu::Button::KbUp then
  9.                 @player.turn_up()
  10.         elsif @window.button_down? Gosu::Button::KbDown then
  11.                 @player.turn_down()
  12.         elsif @window.button_down? Gosu::Button::KbLeft then
  13.                 @player.turn_left()
  14.         elsif @window.button_down? Gosu::Button::KbRight then
  15.                 @player.turn_right()
  16.         end
  17.   end
  18. end


I hope this is pretty self-explanatory to you. You can see Gosu::Button::Kb refers to the current key you press down on your keyboard and the if/elsif/else structure just means

ruby Code:
  1. if something?
  2.      do something
  3. else if another thing?
  4.      do something
  5. else if another thing?
  6.      do something
  7. else nothing worked?
  8.      do something


Anyway that's it! Launch main.rb and you should have a walking character if you don't. Feel free to download this part from download location
http://www.gamenao.com/download/shiningforce_ii.zip

Any this concludes part II, the next episode i'll be covering how to create a map!

Go Back

Comment