Keeping it Small and Simple

2008.02.22

Rubygame tutorial #3: In control

Filed under: Ruby Programming, Rubygame Tutorial — Tags: , , , — Lorenzo E. Danielsson @ 07:37

Welcome back. Due to (somewhat) popular demand, I’m going to continue the rubygame tutorials. In this tutorial we will look at a keyboard event: KeyDownEvent.

Looking back for a second or two

Let us remind ourselves of the steps we need to take to create a very simple Rubygame program:

  1. Create a screen
  2. Create a event queue
  3. Create a clock
  4. Enter the main loop. The main loop does drawing and contains an event loop.
  5. The event loop should have some exit condition

That is really it. Armed with only this knowledge and a few drawing methods we can do a lot already.

A single pixel

Let’s start off with a program that plots a single pixel. The following program will just plot a single pixel at the center of the screen.


 1 #! /usr/bin/ruby
 2
 3 # A pixel.
 4
 5 require rubygame
 6 include Rubygame
 7
 8 screen = Screen.new([640, 400])
 9 events = EventQueue.new
10 clock = Clock.new
11 clock.target_framerate = 120
12 running = true
13
14 while running
15   events.each do |event|
16     case event
17     when QuitEvent
18       running = false
19     end
20   end
21
22   screen.fill([0, 0, 0])
23   screen.set_at([screen.w / 2, screen.h / 2], [255, 255, 255])
24   screen.update
25   clock.tick
26 end
27

Not too interesting I guess. I single pixel and it doesn’t even move! Let’s change that.

Exercises

1. Modify the program to display a blue pixel.

2. Modify the progam to plot the pixel at the position 100, 100.

3. Change the screen size to 500, 500.

4. Write a program that takes the pixel coordinates as command-line arguments. Provide the center as a default position if no arguments are passed. Give an error if the coordinates are beyond the size of the screen.

Preparing for motion

Let’s give our pixel a life of its own. We will create a pixel class. Here is a new version of the program.


 1 #! /usr/bin/ruby
 2
 3 # Another pixel.
 4
 5 require rubygame
 6 include Rubygame
 7
 8 class Pixel
 9   attr_reader ðŸ˜¡, :y
10
11   def initialize(x, y, surface)
12     @x, @y = x, y
13     @surface = surface
14   end
15
16   def plot
17     @surface.set_at [@x, @y], [255, 255, 255]
18   end
19 end
20
21 screen = Screen.new [640, 400]
22 events = EventQueue.new
23 clock = Clock.new
24 clock.target_framerate = 120
25 pix = Pixel.new(screen.w/2, screen.h/2, screen)
26 running = true
27
28 while running
29   events.each { |event|
30     case event
31     when QuitEvent
32       running = false
33     end
34   }
35
36   pix.plot
37   screen.update
38   clock.tick
39 end

We still only see a single pixel at the middle of the screen. Still no fun! 😦

On the other hand, we now have a pixel that knows its own position and is able to “draw itself” onto its target surface.

Exercises

1. Add a color attribute to the Pixel class. Set the color attribute to red before plotting the pixel.

2. Create five Pixel instances, each with different coordinates and plot each of them.

Now, move it!

So far we have used QuitEvent to determine if the user has closed the Rubygame screen. Now let’s look at another event: KeyDownEvent. This event is triggered any time a key is pressed down. We can find out which key via KeyDownEvent#key. Let’s use this to add the ability to move the pixel around.

We give our Pixel class some new methods: up, down, left, right and stop. Internally, it will also have two new fields: one to determine the horizontal direction and one to determine the vertical direction.


 1 #! /usr/bin/ruby
 2
 3 # Moving pixel.
 4
 5 require rubygame
 6 include Rubygame
 7
 8 class Pixel
 9   attr_reader ðŸ˜¡, :y
10
11   def initialize(x, y, surface)
12     @x, @y = x, y
13     @dx, @dy = 0, 0
14     @surface = surface
15   end
16
17   def up
18     @dx, @dy = 0, –1
19   end
20
21   def down 
22     @dx, @dy = 0, 1
23   end
24
25   def left
26     @dx, @dy = –1, 0
27   end
28
29   def right
30     @dx, @dy = 1, 0
31   end
32
33   def stop
34     @dx = @dy = 0
35   end
36
37   def move
38     tx, ty = @x + @dx, @y + @dy
39     return unless (0..@surface.w-1).include? tx
40     return unless (0..@surface.h-1).include? ty
41
42     @x, @y = tx, ty
43   end
44
45   def plot
46     @surface.set_at [@x, @y], [255, 255, 255]
47   end
48 end
49
50 screen = Screen.new [640, 400]
51 events = EventQueue.new
52 clock = Clock.new
53 clock.target_framerate = 120
54 pix = Pixel.new(screen.w/2, screen.h/2, screen)
55 running = true
56
57 while running
58   events.each { |event|
59     case event
60     when QuitEvent
61       running = false
62     when KeyDownEvent
63       case event.key
64       when K_UP: pix.up
65       when K_DOWN: pix.down
66       when K_LEFT: pix.left
67       when K_RIGHT: pix.right
68       when K_SPACE: pix.stop
69       end
70     end
71   }
72
73   screen.fill [0, 0, 0]
74   pix.move
75   pix.plot
76   screen.update
77   clock.tick
78 end

Exercises

1. Try to comment out the screen.fill line inside the drawing loop. What happens?

2. Currently, the pixel can move in four directions: up, down, left and right. How could you modify the program to allow the pixel to move diagonally. (There are several ways, experiment as much as you can.)

3. Modify the program to create three Pixels. Give each a different starting position. When one of the motion keys is pressed, all three should move.

4. What if you wanted to create three Pixels that each used a different set of keys to control its motion, how would you go about that? Would you make any changes to the Pixel class itself?

5. Rewrite the program to check the KeyUpEvent instead of KeyDown. How does this affect the program?

Conclusion

In this tutorial you have learned how to use the KeyDown event. We will continue with our moving pixel in the next tutorial (hey, I told you I was going to go real slow).

In the meantime, experiment with what you have learned so far. There are loads of things you can do to get extra practice. For instance you could modify the program so that the pixel only moves while a key is pressed down. Once the key is released it should stop (use both KeyDownEvent and KeyUpEvent). The more you practice the better you will become.

Advertisements

1 Comment »

  1. ARGH! Stupid smiley expansion! The 😡 is supposed to be : x (without a space between the colon and the x).

    Comment by Lorenzo E. Danielsson — 2008.02.22 @ 07:38


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: