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
#############################################################################
on 2008-07-11 08:01
on 2008-07-11 12:48
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.
on 2008-07-11 13:09
> 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/ Regards, André -- Lamentação sem gratidão é murmuração. (Howard Hendricks)
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.