NOGDUS

Articles, Tutorials, and other things. => General Game Programming => Topic started by: Richard Marks on July 05, 2008, 10:03:30 AM



Title: RubySDL Introduction
Post by: Richard Marks on July 05, 2008, 10:03:30 AM
RubySDL Introduction

Okay since there is a total lack of documentation on this I figure that it would be nice for me to put this out there.  ;D

I assume only that you have gone through the Ruby Tutorials here (http://www.ruby-lang.org/en/documentation/quickstart/) and here (http://tryruby.hobix.com/) so that you are familiar with the Ruby syntax.

I also assume that you have Ruby installed on your computer and RubySDL properly installed already.
If not get with either Michael or I on IRC and we will explain the process to you. (Linux and Windows support only atm)

I use the text editor SciTE based on the Scintilla syntax-highlighting component for nearly all my programming projects.
I highly recommend it. Get it here (http://scintilla.sourceforge.net/SciTEDownload.html).

Let's get started. Create an "arby" file (a file with the extension .rb on the end) in your project directory.
I called mine rubysdl_helloworld.rb

The first thing you need is to include the SDL library in your program.
Code:
#!/usr/bin/env ruby
# rubysdl_helloworld.rb
# A RubySDL Hello World program
# by Richard Marks ccpsceo@gmail.com

require "sdl"

That was simple.

The require command simply includes the classes, constants and functions that are contained within the specified "arby" library. Do notice that you do not specify the .rb extension when requiring the library file.

Next we will write a small function for loading bitmaps that will make our code a little cleaner and easier to understand.
Code:
# LoadBitmap
# returns a bitmap suitable to be displayed with SDL
def LoadBitmap(fileName, useColorKey=false, colorKey=nil)
surface = SDL::Surface.loadBMP(fileName)
if useColorKey == true then
if colorKey.nil? then
# use the color at 0,0 in the image as the color key
surface.setColorKey(SDL::SRCCOLORKEY, surface[0, 0])
else
# use the color key specified
surface.setColorKey(SDL::SRCCOLORKEY, colorKey)
end # end if no color key specified
end # end if we are using a color key on this image
surface = surface.displayFormat
return surface
end # end function LoadBitmap

If any of this does not make sense, I'll try to explain it now.
If you already understand the code, then jump ahead past this section of text.

The function that we just made LoadBitmap takes from 1 to 3 parameters.
The last two parameters are optional since we specified a default value for them.
The first parameter is a string that specifies the filename and path of the bitmap to load.
The second parameter is a boolean that specifies if we want to bother with color-keying the bitmap or not.
Color-keying means to specify a transparent color in the image that will be ignored when you draw it on the screen (or another surface you created).
The third parameter is the color to use as your color-key. It is nil by default meaning we will use the color in the image at 0,0 (the upper-lefthand corner of the image) as the color key.
The last thing that we do is make sure the image has the same bit-depth as the screen and then return our surface.

You will see how to use the function later.

I like to place my program's main loop in a class called Demo just for kicks I guess.
This is just my particular taste, and you don't have to use this convention, though if you do, its easier for you and I to find bugs in your code.

We will have only two methods in our class for this simple program.
The initialize method is the class constructor that gets called when an instance of the class is created.
The Run method is where I place my main loop of my programs.

Note: I like my methods to be capitalized, but I cannot capitalize the constructor method as it is a built-in requirement of the Ruby language that it be lowercase.

SAVE your file if you haven't now.

Code:
class Demo
def initialize
end # end method initialize
def Run
end # end method Run
end # end class Demo

Now, After our class we will place the code to create an isntance of our Demo class, and the call the Run method.
This code only gets called if the file is being executed by Ruby directly (not being included by another "arby" file).
Code:
if __FILE__ == $0 then
# create an instance of our demo class (calls initialize automatically)
demo = Demo.new
# call the Run method of our class to get this sucker running!
demo.Run
end # end if this file is the running file (not just being required from another file)

That was easy.

Jump back up to our empty Demo class.
Let's fill in the details of the initialize method now.

What do we need to do?

1. initialize SDL
2. create a window to draw on
3. load the bitmaps that we will use
4. init any member variables that we need

Code:
# init SDL
SDL.init(SDL::INIT_VIDEO)

# init video mode (create a window 640x480 with 16 bpp)
@screen = SDL.setVideoMode(640, 480, 16, SDL::SWSURFACE)

# set the window manager window caption
# SDL::WM.setCaption(windowed_caption, icon_caption)
SDL::WM.setCaption("RubySDL Hello World!", "RubySDL Hello World!")

# load our bitmap
@helloWorldBitmap = LoadBitmap("rubysdlhw2.bmp")

# SDL event handler
@event = SDL::Event.new

SAVE your file if you haven't now. I cannot stress the importance of saving your code after each few lines enough. Nothing worse than your computer dying randomly while typing your code. >_<

All that code should be pretty much easy to understand.
I think that I named it all clear enough, but if not, then just ask me to elaborate on IRC or here.

We now need to handle a few things in our Run method.

1. begin the main loop
2. poll for events such as key presses, mouse actions, window events like resizing and closing etc.
3. handle the events we want to handle
4. update any objects we need to (Note: in this demo we don't have anything to update)
5. render (draw or blit) everything to the screen buffer
6. flip the screen buffer to the physical screen display so we can see it

Whew! How about we do that now?
Code:
# start the infinitely executing main loop
while true
# poll for events
if @event.poll != 0 then
# check for quit and keydown events
case @event.type
when SDL::Event::QUIT
break
when SDL::Event::KEYDOWN
# check for the ESC key
if @event.keySym == SDL::Key::ESCAPE then
break
end # end if ESC pressed
end # end case event.type
end # end event if events in event.poll

# fill the screen buffer with black
@screen.fillRect(0, 0, 640, 480, 0)

# draw bitmap centered
# 640 / 2 - 468 / 2, 480 / 2 - 60 / 2
@screen.put(@helloWorldBitmap, 86, 210)

# ensure garbage collection
ObjectSpace.garbage_collect

# flip screen buffer contents to visible screen
@screen.flip
end # end main loop
SAVE your file if you haven't now. I'd have saved at least 8 times by now.

Create a bmp file called rubysdlhw2.bmp 468x60 pixels in size in your project directory before running this.

If you're running SciTE, then press F5 and your program will run. Press ESC or close the window using the close-button.

That's it.
Here is the full source in one chunk so that you can see how it all fits together.
Make sure you don't blindly copy/paste this code to your file.
You will not learn that way!

Code:
#!/usr/bin/env ruby
# rubysdl_helloworld.rb
# A RubySDL Hello World program
# by Richard Marks ccpsceo@gmail.com

require "sdl"

# LoadBitmap
# returns a bitmap suitable to be displayed with SDL
def LoadBitmap(fileName, useColorKey=false, colorKey=nil)
surface = SDL::Surface.loadBMP(fileName)
if useColorKey == true then
if colorKey.nil? then
# use the color at 0,0 in the image as the color key
surface.setColorKey(SDL::SRCCOLORKEY, surface[0, 0])
else
# use the color key specified
surface.setColorKey(SDL::SRCCOLORKEY, colorKey)
end # end if no color key specified
end # end if we are using a color key on this image
surface = surface.displayFormat
return surface
end # end function LoadBitmap

class Demo
def initialize
# init SDL
SDL.init(SDL::INIT_VIDEO)

# init video mode (create a window 640x480 with 16 bpp)
@screen = SDL.setVideoMode(640, 480, 16, SDL::SWSURFACE)

# set the window manager window caption
# SDL::WM.setCaption(windowed_caption, icon_caption)
SDL::WM.setCaption("RubySDL Hello World!", "RubySDL Hello World!")

# load our bitmap
@helloWorldBitmap = LoadBitmap("rubysdlhw2.bmp")

# SDL event handler
@event = SDL::Event.new
end # end method initialize

def Run
# start the infinitely executing main loop
while true
# poll for events
if @event.poll != 0 then
# check for quit and keydown events
case @event.type
when SDL::Event::QUIT
break
when SDL::Event::KEYDOWN
# check for the ESC key
if @event.keySym == SDL::Key::ESCAPE then
break
end # end if ESC pressed
end # end case event.type
end # end event if events in event.poll

# fill the screen buffer with black
@screen.fillRect(0, 0, 640, 480, 0)

# draw bitmap centered
# 640 / 2 - 468 / 2, 480 / 2 - 60 / 2
@screen.put(@helloWorldBitmap, 86, 210)

# ensure garbage collection
ObjectSpace.garbage_collect

# flip screen buffer contents to visible screen
@screen.flip
end # end main loop
end # end method Run
end # end class Demo

if __FILE__ == $0 then
# create an instance of our demo class (calls initialize automatically)
demo = Demo.new
# call the Run method of our class to get this sucker running!
demo.Run
end # end if this file is the running file (not just being required from another file)

I hope this helped you out.
I'll post more as I figure it out!
I'd love to hear your feedback on this article/ tutorial.