# Writing a game in Ruby

**URL:** <https://www.ruby-forum.com/t/writing-a-game-in-ruby/142768>\
**Category:** Ruby-Gnome 2\
**Created:** [July 11, 2008, 8:01am UTC](https://www.ruby-forum.com/t/writing-a-game-in-ruby/142768 "2008-07-11T08:01:40Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![jwigal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/6a8cbe/32.png) [@jwigal](https://www.ruby-forum.com/u/jwigal)\
**Post date:** [July 11, 2008, 8:01am UTC](https://www.ruby-forum.com/t/writing-a-game-in-ruby/142768/1 "2008-07-11T08:01:40Z")

</div>

Hi there,

I’m in the process of writing what will eventually be a card game using  
ruby. However, first things first I’m trying to set up the graphics  
functions. Currently I’m using a Gtk window with a sigle widget, a  
DrawingArea inside which I use cairo to draw the graphics.

However I’ve run into a few problems. First of all, if I don’t manually  
call the garbage collector frequently, the program grinds to a halt –  
it seems like when i grab a new Cairo context, the old one isn’t deleted  
and hangs around in memory? Am I doing something wrong?

Secondly, even after adding the garbage collector, the frame rate is  
depressingly low. With no background and drawing a minimal number of  
objects per frame, it only gets ~20 FPS.

I feel like I must be doing something wrong.

My question is twofold:

1. Is there a better way to do this (other than cairo/GTK) that I don’t  
know about?
2. If not, is there any way to speed up cairo’s drawing?

I’ve included a stripped-down version of my code below.

Thanks so much!

P.S. I’m somewhat new to this forum, so if this post is in the wrong  
place, please tell me.  
###############################################################################

require ‘gtk2’  
require ‘cairo’

def min(x, y)  
if x\<y  
return x  
else  
return y  
end  
end

def max(x, y)  
if x\>y  
return x  
else  
return y  
end  
end

class Entity  
attr\_accessor :image, :x, :y, :scale

```
    def initialize(img, x, y)
            @x, @y = x, y
            @image = Gdk::Pixbuf.new(img)
            @scale = 0
    end

    def draw(cr, scale)
            cr.save
            if scale != @scale
                    @pixbuf = @image.scale(@image.width*scale,

```

@image.height_scale)  
 @scale = scale  
end  
cr.set\_source\_pixbuf(@pixbuf, @x_scale, @y_scale)  
cr.rectangle(@x_scale, @y\*scale, @pixbuf.width,  
@pixbuf.height)  
cr.clip  
cr.paint  
cr.restore  
end  
end

class Field  
attr\_accessor :entities, :scale, :height, :width

```
    def initialize(w, h)
            @width, @height = w, h
            @entities = []
    end

    def draw(cr, x, y, scale)
            return nil if scale <= 0
            cr.save
            cr.rectangle(x, y, scale*@width, scale*@height)
            cr.clip
            cr.translate(x, y)
            cr.scale(scale, scale)
            entities.each do |e|
                    e.draw(cr, 1)
                    e.x += rand()*10-5
                    e.y += rand()*10-5
            end
            cr.restore
    end

```

end

class JCanvas \< Gtk::DrawingArea  
attr\_accessor :myfield, :yourfield, :frames, :sc

```
    def initialize(w, h)
            @myfield = Field.new(1280, 800)
            @yourfield = Field.new(1280, 800)
            @frames = 0
            @sc = 0.5
            super()
    end

    def get_cr()
            #puts "Getting new CR"
            cr = window.create_cairo_context()
    end

    def redraw
            cr = get_cr
            cr.push_group()

            black = [0.0,0.0,0.0]
            cr.set_source_rgb(black)
            cr.paint

            sc = @sc

            myfield.draw(cr, 640-640*min(sc,1), 0, min(sc, 1))
            yourfield.draw(cr, 640-640*max(1-sc, 0), 800*sc,

```

max(1-sc, 0))

```
            cr.pop_group_to_source()
            cr.paint

            @frames += 1
            return 1
    end

```

end

def main

```
    win = Gtk::Window.new;
    win.set_title("Magickz!");

    win.fullscreen
    w, h = win.default_size()
    canvas = JCanvas.new(w, h);
    10.times { canvas.myfield.entities.push(Entity.new("test.jpg",

```

rand()\*500, rand()\*500)) }  
10.times {  
canvas.yourfield.entities.push(Entity.new(“skull.jpg”, rand()\*500,  
rand()\*500)) }

```
    canvas.add_events(Gdk::Event::BUTTON_PRESS_MASK)
    canvas.signal_connect("button_press_event") { puts "got MOUSE!!"

```

}

```
    canvas.add_events(Gdk::Event::KEY_PRESS_MASK)
    canvas.signal_connect("key_press_event") { |ev, k| puts "got

```

KYBD (#{k.keyval})"; if k.keyval==113; exit(); end; if k.keyval==65362;  
canvas.sc +=0.05; else; canvas.sc -= 0  
.05; end }

```
    canvas.set_flags(Gtk::Widget::CAN_FOCUS)

    win.add(canvas);
    canvas.show();
    win.show()

    Thread.new("gameloop") {
            while true
                    canvas.redraw
                    sleep(0.0100)
            end
            true
    }
    Gtk.timeout_add(2000) {puts "starting GC"; GC.start; true}
    Gtk.timeout_add(1000) {puts "FPS = #{canvas.frames}";

```

canvas.frames = 0; true}

```
    Gtk.main

    return 0;

```

end

main  
#############################################################################

---

<div class="post-metadata">

**Author:** ![jwigal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/6a8cbe/32.png) [@jwigal](https://www.ruby-forum.com/u/jwigal)\
**Post date:** [July 11, 2008, 12:48pm UTC](https://www.ruby-forum.com/t/writing-a-game-in-ruby/142768/2 "2008-07-11T12:48:54Z")

</div>

Hi Jeff,

> I’m in the process of writing what will eventually be a card game using  
> ruby. However, first things first I’m trying to set up the graphics  
> functions. Currently I’m using a Gtk window with a sigle widget, a  
> DrawingArea inside which I use cairo to draw the graphics.

I looked at your code but i’m not sure what you plan to to exactly. I  
created a picture test.jpg and commented out the skull.jpg thingy. I  
just see a window, nothing more. Maybe you can attach the full code &  
pictures.

> However I’ve run into a few problems. First of all, if I don’t manually  
> call the garbage collector frequently, the program grinds to a halt –  
> it seems like when i grab a new Cairo context, the old one isn’t deleted  
> and hangs around in memory? Am I doing something wrong?

Ok, first be sure to use the newest ruby-gnome version.  
Second, the GC is automatically started. With GC.start you trigger a  
run, but you never stop it.  
What you can do is avoid destroying/recreating/reloading stuff you can  
still use. For example your images. Load them into a pixbuf once at  
start and use whenever you need them. Other example is what you display.  
Do you need to update everything or just one area?

> Secondly, even after adding the garbage collector, the frame rate is  
> depressingly low. With no background and drawing a minimal number of  
> objects per frame, it only gets ~20 FPS.

Well despite GTK is not a game engine, have a look at your “game main  
loop”. I guess canvas.redraw redraws everything - and you call this 100  
times a second. Plus, this operation may be blocked by other operations  
of the GTK main loop which want to do something at the same time. You  
may consider putting this “game main loop” into the GTK main loop.

oh and:

> def min(x, y) …  
> def max(x, y) …

You could just use [1,2].min or [1,2].max in ruby.

---

<div class="post-metadata">

**Author:** ![jwigal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/6a8cbe/32.png) [@jwigal](https://www.ruby-forum.com/u/jwigal)\
**Post date:** [July 11, 2008, 1:09pm UTC](https://www.ruby-forum.com/t/writing-a-game-in-ruby/142768/3 "2008-07-11T13:09:48Z")

</div>

> Secondly, even after adding the garbage collector, the frame rate is  
> depressingly low. With no background and drawing a minimal number of  
> objects per frame, it only gets ~20 FPS.

Hello Jeff,

not to be saying anything against Gtk, but have you ever heard of gosu?  
It’s a very nice new game library for ruby.

[http://code.google.com/p/gosu/](http://code.google.com/p/gosu/)

Regards,

André

–  
Lamentação sem gratidão é murmuração. (Howard Hendricks)
