What's new? | Help | Directory | Sign in
Google
gosu
Cross-platform 2D game development library
  
  
  
  
    
Search
for
Updated Apr 30, 2008 by julianraschke
Labels: Featured
GosuExchange  
Post questions and other comments, see collected answers.

Gosu Exchange

User jordan.applewhite suggested that there should be a place to exchange experiences that is not as real time as IRC. Also, I would like to collect some answers to emails here in the future. And maybe some users come up with their own best practices. So feel free to post anything that doesn't fit somewhere else as a comment to this page!

Note: This is getting a bit messy here, but it was good to see what kind of things people are interested in. I will take that as a base to decide what to use for future Gosu discussion. -Julian


Comment by psadda, Dec 13, 2007

Is there any way I can get the handle to a Gosu window so that I can use it with wxWidgets, GTK, etc?

Comment by psadda, Dec 13, 2007

I found the following code in Window.hpp:

00075 #ifdef GOSU_IS_WIN 00076 HWND handle() const; 00077 virtual LRESULT handleMessage(UINT message, WPARAM wparam, 00078 LPARAM lparam); 00079 #endif

It says that this is only for Windows, however, where can I find the MacOS and Linux handles?

Comment by julianraschke, Dec 13, 2007

If you can tell me what kind of handles you need for wxWidgets/GTK integration, I will happily provide them :) I'm especially clueless about the X11 port, which was mostly written by Jan Lücker.

Comment by habamax, Dec 14, 2007

Is it possible to turn on standard mouse cursor. Or should I render it using sprites? (I use Ruby/Gosu)

Comment by psadda, Dec 14, 2007

It's easy to implement a cursor class. Here is mine:

  class Cursor
    attr_reader :img, :visible, :imgObj
    def initialize(window,img,visible)
      @img=img
      @visible=visible
      @imgObj=Gosu::Image.new(window,img,true)
      @forced=false
    end
    def toggleVisible
      if not @forced
        @visible=!visible
      end
    end
    def forceVisible
      @forced=true
      @visible=true
    end
    def unforceVisible
      @forced=false
    end
    def visible?
      return visible
    end
    def draw
      if @visible
        @imgObj.draw(window.mouse_x,window.mouse_y,ZOrder::Cursor)
      end
    end
  end
Comment by habamax, Dec 14, 2007

psadda, thanks. I know it is easy to render your own mouse cursor. I just thought there was standard one.

Comment by julianraschke, Dec 15, 2007

No, depending on the operating system, the standard one can even make the game run slower. On Windows 2000, the frame rate used to drop quite a bit when there as a cursor over the window, due to the mouse shadow.

Comment by ladybenko, Dec 15, 2007

Hi, I'm having problems with the button_down? method, since it seems Enter key can be detected...

I tried this code, it should close the window when the user press Enter, but it doesn't work. I don't know if this is a bug or I'm doing something wrong. Any help would be appreciated :)

require 'gosu'

class GameWindow < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "KbEnter Bug?"
  end

  def update
	  if button_down?(Gosu::Button::KbEnter)
	    close
    end
  end

end

window = GameWindow.new
window.show
Comment by habamax, Dec 15, 2007

ladybenko, I tried your code - KbEnter? doesn't work. I tried KbReturn? instead and it does! So it seems that documentation has some issues to correct. :)

Comment by julianraschke, Dec 15, 2007

I rather suspect there is a bit of confusion about the key names ;) Return is that is in the center of the keyboard, Enter is in the lower right corner — and it works as intended on my Intel Mini, USB Keyboard. If it really doesn't on a MacBook?, please let me know. I'll add this as a comment to the RubyReference though.

Comment by julianraschke, Dec 15, 2007

I added the comments, and realized that they only seem to be distinct keys in Macintosh terminology: http://en.wikipedia.org/wiki/Enter_key Should probably be called KbNumpadEnter? then.

Comment by ladybenko, Dec 15, 2007

My fault, I should have notice the presence of KbReturn? and tried that one :( It works now, thanks a lot!

Comment by christoffer.lerno, Dec 17, 2007

If I use Gosu::Image.from_text - how can I control the colour of the text? Is there a way?

Comment by julianraschke, Dec 17, 2007

It's always white, giving you the opportunity to color it any way you like by passing a modulation color to the drawing functions. It's a bit annoying to pass the factor_x, factor_y args all the time, but Ruby will learn named arguments sooner or later, and this way, you can dynamically change the color every time you draw the text.

Comment by christoffer.lerno, Dec 20, 2007

Thanks a lot. Almost done with creating a scrollbox. There's just one problem: I need some sort of clipping. Is there some way of simulating clipping, say on an image I created with Gosu::Image.from_text?

Comment by julianraschke, Dec 20, 2007

Not really, except drawing a cutout over it ;) Clipping is scheduled for 0.8.x, and the basic problem is how to fit it into the interface. Setting a rect on Image or Window before those specific calls would be rather error-prone (I think - I don't like having too much state). Having it as even more draw parameters would be totally confusing. This needs some thought :(

Comment by christoffer.lerno, Dec 21, 2007

You actually both would like to have an image to act as the clipping mask, as well as being able to specify the rect itself. In addition, are we supposing that the clipping mask rotates with the image or not? That would make quite a difference.

I was thinking of being able to create a clip, either through Clip.new(image) or Clip.new(x, y, width, height)

Then you draw by passing it through the mask method, like this:

image.draw(x, y, ...) becomes:

clip.draw_clipped(image, x, y, ...)

When creating a clip, you probably want to be able to create the inverted version of it as well.

This code could draw characters that let the background shine through:

text_image = Image.from_text(window, "some text", ...)
clip = Clip.new(text_image).inverse (or Clip.new(text_image, :inverse)
clip.draw_clipped(Image.new(window, "background.png"), x, y, 0)

Another way to display it would be to use chaining, basically you could chain the clipping after the draw method.

image.draw(x, y, ...) with clipping would be:

image.draw(x, y, ...).clip(x, y, width, height)

Or the example above with the image

text_image = Image.from_text(window, "some text", ...)
background = Image.new(window, "background.png")
background.draw(x, y, 0).clip(text_image, x, y, :inverse)

Depending on the way the drawing method is written, the reverse semantic might be more appropriate i.e.:

text_image = Image.from_text(window, "some text", ...)
background = Image.new(window, "background.png")
background.clip(text_image, x, y, :inverse).draw(x, y, 0)

Any of these would be fine with me.

Comment by psadda, Dec 26, 2007

I've finaly found out how to use wxWidgets:

Wx In Non-Wx Applications From WxWiki? Jump to: navigation, search You can initialise wxWidgets from non-wxWidgets applications. You should look at the headers and not the docs for these functions, they are mostly internal and so far we have not decided yet what the best API would be for them so they are not documented.

In short you should use wxInitialize and wxUninitialize with a message loop in between, instead of just calling wxEntry. Indeed wxEntry basically calls wxEntryStart, then runs the MainLoop? and calls wxEntryCleanup when the loop exits. wxInitialize and wxUninitialize will respectively call wxEntryStart and wxEntryCleanup.
Note that wxEntry has some tweaks with wxMSW. You should look at init.cpp to have an idea of what to do in addition to wxInitialize.
If you want to combine wxWidgets and SDL, look at http://code.technoplaza.net/wx-sdl/

Comment by julianraschke, Dec 26, 2007

christoffer, as for Images acting as clipping masks, I would have to double-check that OpenGL supports this :) But generally I see that it would be a good addition to Gosu. I actually thought a lot about chaining, not just for clipping, but also for rotations, stretching etc. to get rid of all those unnamed arguments, ideally arriving at:

image.rot(90).stretch_x(5).clip(0, 0, 100, 100).draw

This would also eliminate the question whether the clipping mask rotates with the object or not, and whether the stretching is applied before or after the rotation etc. It would be possible to implement this in C++, but I don't really trust this to work efficiently enough in Ruby, as each call would create a new, GC'ed, object. I wonder if one could just make all this build up a sequence in Image itself and clear that in Image#draw, so it wouldn't create new objects. But if there's something I am afraid of, then it's giving objects too much state. The problem with the current API is that for adding clip(), I would need to duplicate all the draw... methods in one way or another. It is on the ToDo, but I will have to get my hands on tying up all the plans for Gosu::Input until 0.8.0. After that, I will focus on graphics again.

Comment by julianraschke, Dec 26, 2007

psadda, note that Gosu::Window has no real equivalent in the SDL. Basically, Gosu's components are designed so they can be used in isolation (as far as this is possible), and Window just combines them. If you have a wxWidgets application with a ready-to-use OpenGL context, you can create your own Gosu::Graphics object just like Gosu::Window does, and then call begin()/your drawing code/end() on it. The whole graphics system of Gosu does not need anything but an OpenGL context that is ready to use.

Audio is a tiny bit more complicated, as you need to supply its constructor OS dependent parameters (which would have to come from wxWidgets, not Gosu). Same for Input, except that you have to supply it with windowing API-specific Event structs, which will always be hard with anything but Cocoa ir X11 on OS X or Linux, respectively.

But generally, this is all possible with Gosu, similar to what the wx-sdl tutorial does. What you were first asking about—have a Gosu::Window in parallel to other windows, coming from wxWidgets or something else—is more complicated unfortunately. But that is why the components are separated, and with the rather independent Graphics subsystem, this should be enough to build a level editor (which doesn't need Gosu's Audio and Input) with any toolkit.

Hope that makes sense and that this route works for you. The other way around (using Gosu::Window in wxWidgets) gets you into a bit of a mess, as you can probably guess from the documentation :)

Comment by kaerigan, Dec 30, 2007

Is it possible to use some other color than 0xff00ff as the "transparent colour" when loading images? Also, is it possible for PNGs to have transparent backgrounds? Even if I do use 0xff00ff as the PNG's background, it won't work.

Comment by julianraschke, Dec 30, 2007

Only BMP files are loaded with color keying (because they have no built-in transparency). So if you want to use 0xff00ff as a color in your graphics, you have to use PNG files. Conversely, if you want PNG files with transparency, you have to use real PNG transparency (alpha channel).

Comment by kintovision, Jan 01, 2008

julian i just want to thank you for Gosu and for not quitting!

Comment by jmlacroix, Jan 05, 2008

I just discovered this library and I must say I'm really impressed!

I want to code a small RPG game with it, but I need some tools to create tiles, sprites and all the other stuff. I'd like to code these tools with Gosu in Ruby (for reusing code in the game), but is there a way to save "surfaces" to a file? Are such functions planned?

Comment by julianraschke, Jan 06, 2008

jmlacroix: Thanks! There is no Image#save, there is no way to manipulate images in the first place, so saving them wouldn't help :) I think you would have to use RMagick for that.

Comment by popo...@popolon.org, Jan 14, 2008

png can be replaced by jpg

to launch at the end of the window.draw() function

require 'gl'   # for gl functions
require 'gtk2' # for gdk-pixbuf functions
[...]
  def get_screenshot
    gl{}
    data = glReadPixels( 0, 0, WIDTH - 1, HEIGHT - 1, GL_RGB, GL_UNSIGNED_BYTE)
    screenbuffer = Gdk::Pixbuf.new(data, Gdk::Pixbuf::COLORSPACE_RGB, false, 8, WIDTH - 1, HEIGHT - 1, (WIDTH - 1)* 3)
    screenbuffer.flip(false).save("#{$screenshot_path}/scrinshaute_gosu.png", 'png')
  end
[...]
Comment by dgam3z, Jan 14, 2008

Same as above but instead of using gtk, it uses rmagick. (note about popolon's code: the data = getReadPixels([...]) should be inside the gl block)

require 'gl'   # for gl functions
require 'rmagick' # for rmagick functions
[...]
  def get_screenshot
        gl { data = glReadPixels( 0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_SHORT) }
                
        screenbuffer = Magick::Image.new(WIDTH, HEIGHT);
        screenbuffer.import_pixels(0, 0, WIDTH, HEIGHT, "RGB", data, Magick::ShortPixel).flip!
        screenbuffer.write("screenshot_gosu.png");
    end
  end
[...]
Comment by masonhale, Jan 28, 2008

First -- kudos to julian! I found gosu yesterday and have spent the last several hours building games with my kids ages 6 to 13. It has been terrific fun. Gosu makes it so easy and efficient. Every bit of code goes into making the game better. Gosu is a remarkably elegant piece of work. Thank you for making it.

Thinking about this suggested bit of code (from above):

image.rot(90).stretch_x(5).clip(0, 0, 100, 100).draw

I really like this approach and syntax. Although I prefer full method names to abbreviations for the sake of clarity (e.g. 'rotate' instead of 'rot'). You mentioned not wanting objects to carry too much state, and also not wanting to generate an object to be GC'd after each method.

Perhaps it would help to introduce an ImageTransform class? Such that the series of calls above builds a chain of transforms, which retain the order of the transformation operations, but defers applying those transforms until the draw method, and at that point all the transforms are applied in one operation.

I'm thinking that Image#scale(x, y) would return an ImageTransform object instead of an image. Something like:

class ImageTransform
  attr_accessor :transforms
  
  def initialize
    @transorms = []
  end
  
  def scale(x_factor, y_factor, hard_borders = false)
    @transforms << [:scale, x_factor, y_factor, hard_borders]
    self
  end
  
  def rotate(angle, x_center = 0.5, y_center = 0.5)
    @transforms << [:rotate, angle, x_center, y_center]
    self
  end
  
  def clip(x1, y1, x2, y2)
    @transforms << [:clip, x1, y1, x2, x2]
    self
  end
  
  def color(a_color)
    @transforms << [:color, a_color]
    self
  end
end

class SingleImageTransform < ImageTransform
  attr_accessor :image
  
  def initialize(image)
    @image = image
  end
  
  def apply
    @image.apply(self)
  end
  
  def draw(x, y, z = 0)
    self.apply
    @image.draw(x, y, z)
  end
end

class Image

  ...
  
  def scale(x_factor, y_factor, hard_borders = false)
    SingleImageTransform.new(self).scale(x_factor, y_factor, hard_borders)
  end
  
  def rotate(angle, x_center = 0.5, y_center = 0.5)
    SingleImageTransform.new(self).rotate(angle, x_center, y_center)
  end
  
  def clip(x1, y1, x2, y2)
    SingleImageTransform.new(self).clip(x1, y1, x2, y2)
  end
  
  def color(a_color)
    SingleImageTransform.new(self).color(a_color)
  end
  
  def apply(transform)
    # apply transforms passed in
  end
  
  def draw(x, y, z = 0)
    # normal draw
  end

end

# simple syntax
# developer doesn't need to be aware of ImageTranform
img = Image.new('path/file.png')
img.scale(2.0, 2.0).rotate(-90.0).draw(200, 300)

# advanced syntax
# developer can build a transform and apply to multiple images
transform = ImageTransform.new
transform.scale(0.5, 0.5)
transform.rotate(45.0)

img1 = Image.new('path/file1.png')
img2 = Image.new('path/file2.png')

img1.apply(transform)
img1.draw(200, 300)
img2.apply(transform)
img2.draw(150, 450, 1)

The other advantage I can see to this approach is that if you wanted to apply the same series of transformations to more than one image, you could create the ImageTransform object independently, and apply the same transform (really a series of transforms) to each image. The SingleImageTransform simply provides some syntactic sugar to make the simple syntax possible, concealing from the developer the complexity of the ImageTransform class.

One thing I didn't add is support for height and width. I'd suggest those values don't get adjusted in Image until after 'apply' has been called. And SingleImageTransform could calculate those easy enough before the tranform is applied, if necessary.

Comment by julianraschke, Jan 28, 2008

Thanks a lot!! Cool to hear you enjoyed using Gosu. As always, if you have any minigames coming from this, feel free to post them :)

I'm still not happy with img.apply(transform), but for the rest, I'll give it a try when 0.8.0 is out! (Currently busy with 0.7.9 and work, and it seems Gosu's Linux version will start to linger behind again :()

Comment by masonhale, Jan 28, 2008
Thanks a lot!! Cool to hear you enjoyed using Gosu. As always, if you have any minigames coming from this, feel free to post them :)

I will once something is closer to 'done'. We've made a game from the media assets used in Tutorial.rb that is closer to something like Galaga -- with a fixed angle on the spaceship and some firepower.

I'm still not happy with img.apply(transform), but for the rest, I'll give it a try when 0.8.0 is out! (Currently busy with 0.7.9 and work, and it seems Gosu's Linux version will start to linger behind again :()

Another possibility may be to pass the ImageTransform? object as an optional parameter to the Image#draw method.

transform = ImageTransform.new
transform.scale(0.5, 0.5)
transform.rotate(45.0)

img1 = Image.new('path/file1.png')
img2 = Image.new('path/file2.png')

img1.draw(200, 300, 0, transform)
img2.draw(150, 450, 1, transform)

I guess it depends on whether or not in the underlying code transformation and drawing happen separately or simultaneously.

Comment by jptarqu, Feb 09, 2008

How can I detect if the user clicked on an image object, i.e. the use pointer was over the bitmap of the image. Do I have to use the get_distance and check if the user clicked within a radius from the image's position? Or is there a more precise method of checking if the bitmap was clicked?

Comment by psadda, Feb 11, 2008

Use a Rect style class to store the coordinates of the top left and bottom right corners of the bitmap, then use mouse_x and mouse_y to see if the click was inside the bitmap. I've made a Button class, if you'd like to see it.

Comment by dapatil, Feb 12, 2008

Why is ClearType? not enabled for the Windows version of Gosu ? The following will turn on cleartype in Windows.

--- Graphics/TextWin.cpp	(revision 436)
+++ Graphics/TextWin.cpp	(working copy)
@@ -109,7 +109,7 @@
                     fontFlags & ffItalic ? TRUE : FALSE,
                     fontFlags & ffUnderline ? TRUE : FALSE,
                     FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
-                    CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
+                    CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,
                     DEFAULT_PITCH | FF_DONTCARE };
 
                 // IMPR: This truncates. Is this reasonable? Should we rather
Comment by julianraschke, Feb 12, 2008

jptarqu, the easiest way would be if there were a get_pixel method in Gosu::Image. Then you'd only have to calculate all your drawing transformations (stretch, rotation) backwards and it'd work. But that method doesn't exist right now and even though it's really hard to deploy RMagick apps at the moment, using RMagick would be the quickest workaround: just create all images both in Gosu and RMagick and use RMagick's get_pixel there, or whatever it's called. If you have a finished project that just depends on get_pixel being added to Gosu::Image, and RMagick deployment hasn't gotten easier until then, I will just throw it into Gosu :)

Comment by julianraschke, Feb 12, 2008

dapatil: Because ClearType? would make matters much complicated. ClearType? looks horribly wrong the moment it isn't perfectly aligned at the right pixel borders, i.e. as soon as you stretch or rotate something. I don't think it's worth the arguably clearer text. I actually suspect that the current AA code is a bit broken anyway, because it makes text look really bold; I will look into that first, hopefully it will make all text a lot crisper without ClearType? :)

Comment by hdaempfle, Feb 22, 2008

I want to create an osx-style osd (on screen display) which transparently lays over the whole screen (think apples volume control osd) - so my question is: Is there a way to use gosu in fullscreen mode with full transparency (apart from the few elements I want to draw)?

Comment by julianraschke, Feb 25, 2008

No, Gosu was not intended for building this kind of GUI. Sorry! :)

Comment by jklemail, Mar 10, 2008

Hi, it seems that I can't install gosu in 1.9.0 (Seg fault). It did install fine when I use 1.8.6. Can you please verify? If it really doesn't work, can you please fix it?

Comment by julianraschke, Mar 10, 2008

Gosu doesn't support Ruby 1.9 (though I haven't personally tested it yet). I'm currently focusing on completeness and stability for Gosu 0.7.9. Gosu 0.8.0 will be a cleanup with new features, e.g. Ruby 1.9 support. Of course, if you have an idea how to fix it, you can send in a patch for 0.7.9—but I don't want 0.7.9 to be even later than it currently is (sigh) :(

Comment by biot023, Mar 11, 2008

Hi -- I'm just starting w/ Gosu, and it looks fantastic, thankyou! One thing I'm struggling with is the physics side -- I want to handle moving ball collisions, and ball & wall collisions. Are there any Ruby/Gosu tuts or code that deal with this that may help? Bearing in mind I've been staring at tutorials on this all day & not getting very far! Cheers,

Doug.

Comment by erestar, Mar 11, 2008

Hi!

Fun little library you have here :)

I'm trying to implement a Zelda-like tile system. The project is here, with the images and maps and everything you need to run it: http://www.erestar.net/werfarlyn.tar

However, once things starts scrolling you can very visibly see the page redrawing, and if you watch it enough you start to develop a twitch in your left eye and severe pain in your temples.

Would anyone mind taking a look and pointing out what I'm doing wrong? You should be able to see the effect yourself. I've implemented some clipping, but that didn't help. Also, please keep in mind this is my first Ruby project, so I'm still not sure what I'm doing.

Any help or advice would be appreciated!!

Comment by julianraschke, Mar 11, 2008

biot023, testing for collisions between geometric primitives is outside of the scope of Gosu's documentaton. Testing for a collision between circles is easy to do with Gosu though: Gosu::distance(x1, y1, x2, y2) must be ≤ r1 + r2. For the second collision, if your wall is rectangular, you could check whether any of the corners of the rectangle are inside the circle (distance ≤ radius) or if the top/bottom/left/right edge of the circle is inside of the rectangle. From a quick look at it I'd say that exactly in these cases the circle and the rectangle do collide. phew ;)

Comment by julianraschke, Mar 11, 2008

erestar, what platform are you on? On OS X, it's easy to tell OpenGL to sync vertically with the screen. On Windows and Linux, I haven't found a solution that works everywhere. I do check for the wglSwapIntervalEXT function on Windows, but it isn't implemented in Apple's GMA950 drivers either. It's probably a matter of even more googling and experimenting. It's on the ToDo, and I fear it should be part of 0.7.9 if I want to call that release polished&solid ;)

Comment by erestar, Mar 11, 2008

julianraschke: I'm running this on Ubuntu Linux. Do you have a solution that works some places that I could try (please remember to use the smallest words possible)?

Otherwise, is it safe to assume that this is something I won't have to worry about in future versions and it's ok to deal with it now and continue on?

Thanks!

Ere

Comment by Qronicle, Mar 12, 2008

Hello,

I am working on a topdown race simulator, and I would like to make tings a bit better looking with tire marks (generated through the race). I tried to use a Bitmap to store the generated marks-image, and converting it each frame to an Image. This method however is extremely slow, has anybody another idea in order to do this?

Qronicle

Comment by di3go.bernardes, Mar 13, 2008

Hi

Can anyone help me make a better animation? Above is the code of gosu ruby tutorial

def draw

img = @animation[Gosu::milliseconds / 100 % @animation.size] img.draw(@x - img.width / 2.0, @y - img.height / 2.0,ZOrder::Stars, 1, 1, @color, :additive)

end

my sprites have dif delay to render, like this:

1 2 3 4.... 100ms 80ms 120ms .....

Can anyone help me to make this?

Thx alot :)

Comment by erestar, Mar 14, 2008

Regarding my earlier post about tearing with a large number of tiles on the screen...

I was able to fix this by telling Open GL to 'Sync to VBlank' Everything renders smoothly now.

Details: OS: Ubuntu GG Card: nvidia Setting change: in nvidia-settings > open GL > check Sync to Vblank

Comment by julianraschke, Mar 16, 2008

di3go.bernardes: As always, one level of indirection solves everything ;)

def draw
  indices = [0] * 5 + [1] * 4 + [2] * 6 + ...
  index = indices[Gosu::milliseconds / 20 % indices.size]
  img = @animation[index] img.draw(@x - img.width / 2.0, @y - img.height / 2.0,ZOrder::Stars, 1, 1, @color, :additive)
end
Comment by julianraschke, Mar 16, 2008

Qronicle: So you are using the C++ version of Gosu? Recreating from a Bitmap can work if you split the map into really small Images, as in the RMagickIntegration example, but will become way too slow if you change the map in multiple places. A better solution would be to draw the last 100 or so tracks using Image::draw and then recreate parts of the map in a background thread every once in a while. That is covered by experimental Async features, which are currently rather limited, experimental & untested outside of OS X. :(

I think the easier way to go is still to create marks that are just drawn using Image::draw for the last 100 ticks or so and then letting them fade away, or partitioning them in a 2D grid and setting limits for the amount of marks per square.

Comment by Qronicle, Mar 17, 2008

Thanks for the response. For the moment I am using the first method (splitting the bitmap). I made them 100x100px, each frame all the marks are added to the bitmaps, but only one image gets "refreshed" (per frame another car, the image were the center of the car is). Only the visible images are drawn. This gives fairly good results as the game now runs smoothly at 60fps (with 10 AI cars battling each other).

Comment by psadda, Mar 24, 2008

Is there any way to force a window to draw itself?

I'm trying to make a loadscreen for when my game loads a level. On big levels which take a while to load, it works fine, but on small levels, there is a pause where the screen goes blank, and then the map displays wtihout a loadscreen in between. I want a more uniform loadscreen, so I tried drawing the loadimage manually, but to no avail. I also tried messing around with threads, but I also couldn't get that to work.

Comment by kwilley1, Mar 25, 2008

I want to check for keyboard presses without having to set up a window context.

I'm writing a ruby extension for google sketchup and just need to check whether a key is pressed at the time I'm clicking on a toolbar icon.

Any ideas?

Comment by julianraschke, Mar 29, 2008

psadda, This is not directly possible. In my current project I used a flag that is set to true once draw() has been called, which will draw a one-time loading screen then. The next update will then perform the loading work.

Comment by julianraschke, Mar 29, 2008

kwilley, unfortunately this is not possible with the current Ruby bindings. It would be hackish even in the C++ version, because some of the underlying OS APIs require a window context for capturing input.

On Win32, you could use the Win32API module (or what it's called) to call the GetAsyncKeyState? function. I don't know off-hand if such functions also exist for OS X, or even Linux.

Comment by rabbitblue, Mar 31, 2008
indices = [0] * 5 + [1] * 4 + [2] * 6 + ...
index = indices[Gosu::milliseconds / 20 % indices.size]

That is brilliant.

Interesting, too, because I was looking at this bit:

Gosu::milliseconds / 100 % @animation.size

And I don't understand how it works. I see that it does work, but I don't understand how. (I remember looking at it a while ago thinking the animation would be out of order; obviously I was wrong.)

Can anyone clue me in?

Comment by rabbitblue, Apr 05, 2008

To begin answering my own question:

When issued to objects of class Fixnum, modulus answers with the remainder of division problem.

50 / 50 = 1 with a remainder of 0

Therefore, 50 % 5 = 0

50 % 51 = 1 because 50 goes into 51 once with 1 remaining.

This basic premise works infinitely.

50 % 51 = 1 50 % 75 = 25 50 % 99 = 49 50 % 100 = 0 50 % 101 = 1

See the pattern? It's possible to infinitely iterate through an array. Very slick. I have a new question: did you come up with this technique on your own Julian? If so, what inspired the idea?

I wrote a few methods to extend Array that take advantage of this technique.

class Array

  def next_element
    @count.nil? ? @count = size : @count += 1
    self[@count % size]
  end
  
  def previous_element
    @count.nil? ? @count = size : @count -= 1
    self[@count % size]
  end

  def roll
    loop { yield(next_element) }
  end

end

And to test it...

a = [ 'a', 'b', 'c' ]
a.roll { |e| puts e; sleep 1 }

One caveat to all this is that you must modulus by a number equal to or greater than the size of your collection. (This is handled by the method, but in case you were trying it on your own, now you know.)

Comment by rabbitblue, Apr 05, 2008

Oops, the formatting didn't display as I expected. Here's a clearer version:

  • 50 % 51 = 1
  • 50 % 75 = 25
  • 50 % 99 = 49
  • 50 % 100 = 0
  • 50 % 101 = 1

Mods feel free to correct my original comment and delete this one. :)

Comment by julianraschke, Apr 07, 2008

I can't edit messages, I'll just let it stay that way for now. I don't know why I'm %'ing so much, but it's a nice way of cycling through everything, and it works even with floats (as in Tutorial.rb). I guess it could need some more explanation right in the tutorial. I'll get back to this when I have the Windows and Linux version of 0.7.9 out.

Comment by rabbitblue, Apr 07, 2008

I like your use of %. Very clever and succinct, once you understand it.

With regards to my implementation of roll, it can also be written as:

class Array

  def roll
    loop { each { |e| yield(e) } }
  end

end
Comment by di3go.bernardes, Apr 08, 2008

me again ^^ hehe i have one question now about the collision detection, i know isnt the scope of gosu, but how can i do a better pixel collision? i was thinkin in this, when i make a map i make a collision mask too and i use rmagick to create a array with the x,y where can collide and everytime i move i verify the whole array to see if collides, this can work i think but its quite slow when have lots of monsters and moves, dont?

anyone have any sugestion? chipmunk can do collisions too right?

thx

and thx again julian for the help :) great job with gosu ^^

Comment by julianraschke, Apr 08, 2008

I don't know how fast RMagick's get_pixel is, but using a Ruby Array of booleans should be as fast as it gets without resorting to C extensions … just pretty wasteful too ;) But I'd start by keeping the number of vertices per object low and trying to get rid of objects quickly, or not updating off-screen enemies at all, or something like that.

Also, Chipmunk can't do pixel-level collisions, you have to define polygons and spheres, which is a bit more work. I don't know how it performs in conjunction with Ruby, but the Gosu/Chipmunk demo from Andrea O. K. Wright's article on Ruby gamedev looked really smooth :)

Comment by psadda, Apr 09, 2008

di3go.bernardes, I had the same problem. I ported a C++ image library, EasyBMP, to Ruby using SWIG. EasyBMP is lightweight and much faster than RMagick. Maybe you would find it useful.

Comment by snowcamera, Apr 11, 2008

Julian et.al.,

Just wanted to express my deepest thanks for GOSU. I've wanted to do some kind of game programming for years, made some lame attempts using FXRuby's canvas. That was sort of painful, and the results were 'meh'. With GOSU making it so easy, it is way fun writing games! Especially since I get to use my favorite language -- Ruby.

I so appreciate your efforts in GOSU. You should set up a donation link as other OpenSource? projects do. I know I would contribute as my finances would allow, which wouldn't be much considering the ton of work you've put into it.

Anyway, thanks again, I agree with your path, more documentation on what you already have will go a long way to making this the most popular 2D game programming environment around.

Thanks again!

DZ

Comment by julianraschke, Apr 14, 2008

Hi, I won't starve for a while, so I'd rather keep the bureaucratic overhead as little as possible for this project because I'm always short on time, but thanks a LOT for the kind feedback :) I will definitely try to push for more publicity, also on the C++ front, as Gosu becomes more stable. Julian

Comment by tmcdowell, Apr 30, 2008

Hey, I am just going through the first ruby tutorial thing, and adding onto it as I go, so I've made a separate class called 'PopUp?' which inherits from the normal Gosu::Window class. I'll explain the problem after this bit of code:

`class PopUp? < Gosu::Window

def initialize
super(240, 240, false) @font = Gosu::Font.new(self, Gosu::default_font_name, 10)
end
def update
if button_down? Gosu::Button::Kb then
close
end
end
def draw
@font.draw("You have opened up the WIP menu!", 10, 10, 0xffffff00)
end
end

pu = PopUp?.new w = GameWindow?.new(pu) w.show`

Thats the PopUp? bit, and the window bit:

`class GameWindow? < Gosu::Window

def initialize(popup)
@pu = popup super(640, 480, false) self.caption = "Gosu Tutorial Game"
@background_image = Gosu::Image.new(self, "/Users/kidz/Desktop/dynamite.png", true)
@player = Player.new(self) @player.warp(320, 240)

end

def update
if button_down? Gosu::Button::KbLeft? then
@player.turn_left
end if button_down? Gosu::Button::KbRight? then
@player.turn_right
end if button_down? Gosu::Button::KbUp? then
@player.accelerate
end if button_down? Gosu::Button::KbDown? then
@player.reversebackup
end if button_down? Gosu::Button::KbSpace? then
@pu.show
end @player.move
end
def draw
@player.draw @background_image.draw(0, 0, 0)
end
def button_down(id)
if id == Gosu::Button::KbEscape?
close
end
end
end`

The problem is this: I hit space in the program to open the popup, and the entire thing just closes down... any ideas? Also, can I get a little example on how to use 'visible'?

Comment by tmcdowell, Apr 30, 2008

Hrm, in the popup class I changed it to KbReturn? to close it, and now when I hit space it freezes up, and there is a weird, crazy screwed up window BEHIND the main, but I still can close it via the close button in top left corner of the window, then the main window starts working for about a second, and then closes. I am on an iMac 10.4

Comment by julianraschke, Apr 30, 2008

tmcdowell: The disappointing bottom line is that you shouldn't use more than one window at a time. I'll add that as a note to the RubyReference to make this more clear because it often seems to cause confusion. I will try to improve on this in Gosu 0.8.x, i.e. either throw an explanative error the moment a second Window is created, or extend Window so multiple windows actually make sense. With the current interface, you couldn't place the popup or make it always in front of the main one.

Comment by tmcdowell, Apr 30, 2008

Thanks! One more thing: How would one go about using 'visible?'? And Can I change the visibility of the background image/spaceship sprite so that a little menu thing popped up in the main screen?

Oh, ANOTHER thing: I know its possible, and maybe not too hard, but is there a built-in way to do sprite collision with Gosu? I would use chipmunk, but I can't figure out how to get that to work on my MAC/with Gosu...

Comment by julianraschke, Apr 30, 2008

I also added some documentation for visible?—basically, it's only useful in finding out whether the Window is already up and running, or still being set up. I would disregard that method, it's only for special cases.

And it's important to note that there are no sprites in Gosu; you just create the illusion that there are actual objects by drawing the same image every frame in Window#draw. So if you don't want things to appear, just don't draw them in draw for as long as you want to emphasize your popup menu :) If you just want to make sure that the popup is not obscured by the ship, you can draw it using a higher Z argument.

For collision detection, it really depends on how your objects and map are shaped, for most things you can just give everything a bounding box for object-object collisions and write a quick class that provides that. For object-map collision, see the approach taken in CptnRuby?.rb.

Comment by christoffer.lerno, May 09, 2008

Hmm.. text is still rendered pretty ugly in Gosu on OS X.

I see you're using the ATSU calls, so an idea here: Wouldn't it be possible to just to jump into Cocoa and do it using the default font rendering on NSImage? That would probably also make sure that no compability issues arise between OS versions. What do you think?

Comment by julianraschke, May 10, 2008

> Hmm.. text is still rendered pretty ugly in Gosu on OS X.

What kind of text, and which font?

Comment by sharphead, May 25, 2008

Hi there is there any way to get code completion for gosu/ruby in any IDE since it comes as a .so library ?

ps. if there's any need of testing or writing some parts of gosu then I can spend some time on that

regards

Comment by julianraschke, May 28, 2008

sharphead: I don't use any kind of IDE so I can't tell. If you do, it's up to you to find out how to do that :)

And if you happen to be on Linux, you are welcome to try to get rid of one of the issues in the tracker ;) Other than that, just write games and share them with the world!

Comment by karamsarkalemim, May 29, 2008

I want to make a buffer, so I create an Image RMagick), but don't know how to blit an other to it (I have experience with SDL). I tried composite, but got an error, I think it is a bug in RMagick: composite!': undefined method cur_image' for #<Array:0x2dc8690> (NoMethodError?)

Thanks!

Comment by julianraschke, May 29, 2008

No, you are just confused by RMagick's very, very weird interface ;) I remember it returns an array with one element when you just expect it to load an image, so you first have to call 0? on it.

Comment by blim8183, May 29, 2008

Is there any way to package my game as a Mac .app file without the source code being accessible?

Comment by julianraschke, May 29, 2008

There's a VERY expensive Ruby-to-C compiler out there that I forgot the name of. You could also take a look if there's a Mac version of the tar2rubyscript tool, or build a code garbler by yourself. Not sure if there's a cheap, professional solution to this :(

Comment by rabbitblue, Jun 01, 2008

I built a smallish Tetris clone, lovingly called Retris.

It's freely available at github: git://github.com/angryrabbit/retris.git

Here's a screen cast: http://rabbitcreative.com/retris.mov

Once again, awesome, awesome work Julian. :)

Comment by julianraschke, Jun 02, 2008

Heh, very stylish! Needs a small bugfix or two, and a posting on GosuUsers after that :)

Comment by di3go.bernardes, Jun 05, 2008

julian you know anything about shaped window? hard to mod gosu to do it? the idea is to make some widgets with gosu

thx!

Comment by julianraschke, Jun 06, 2008

diego, I never did that on any operating systems, so you would have to find out yourself :)

Comment by tmcdowell, Jun 09, 2008

Has their been any update to the ability to create multiple windows?

Comment by julianraschke, Jun 10, 2008

No; actually, at the moment it seems that it will rather be explicitly forbidden because a) there's a LOT that is missing for multiple windows to make sense in any use case (I think), and b) with only one window, all the window arguments could be omitted from the constructors.

But since nothing of that has been made into code yet, what are you trying to build? :)

Comment by PhilCooperKing, Jun 15, 2008

is there a way to detect any key being pressed? as in press any key to contine type thing?

Comment by julianraschke, Jun 15, 2008

If you don't mind mouse clicks and wheel scrolls counting as keys, you can just use Window#button_down for that. Otherwise, just exclude them with a simple if or so :)

Comment by rabbitblue, Jun 21, 2008

Julian, what reasons shaped your decision to make 0, 0 the upper-left hand corner instead of the lower-left as in Cartesian coordinates?

Comment by rabbitblue, Jun 21, 2008

@tmcdowell

For the record, I agree with Julian's stance on not having multiple windows. Name one modern game that uses multiple windows. I'm talking about real OS-level windows, not faux/graphical windows.

I think the only game I've ever played that had multiple windows was called Dungeons of Mordor. Screenshot available here about 1/3 way down:

http://www.vintagecomputing.com/index.php/archives/180

I've forgotten the terminology but those are child windows to a parent. That feels like a feature of Windows specifically because I've never seen a Cocoa app that does that.

Anywho, what you probably need are states. I have a simple state machine you can use over at github:

http://github.com/angryrabbit/retris/tree/master

HTH.

Comment by julianraschke, Jun 23, 2008

rabbitblue, I was used to it from many toolkits, plus it's the way I read, so I thought it felt natural too :)

Comment by rabbitblue, Jun 23, 2008

I agree it feels natural, and up until I drew a Cartesian plane to solve a scrolling problem I never noticed the difference.

It's not a big deal -- I simply draw the negative numbers on the y-axis going upward. Works the same. :)

Comment by nanodeath, Jun 26, 2008

I'm trying a novel idea of using .svg files for certain media with the help of RMagick, but SVGs loaded this way have a solid (white) background when it should be transparent. I've messed around a little with the fucshia color without luck. Thoughts? I'm using Inkscape and outputting "plain SVG" and then loading them in the usual way one loads images. If it doesn't work out I can pick up PNGs without too much trouble.

Comment by julianraschke, Jun 26, 2008

Sounds like a pretty cool idea :) The fuchsia color is only turned transparent by Gosu when loading from a BMP file, not for PNG files or RMagick images. If you don't use any solid white in the images, you can always turn all white transparent by using the RMagick's .transparent methods or what it's called. Other than that, no idea. Seems to be a pretty general RMagick question, do they have a mailing list or so? :) But be prepared for RMagick being a bit annoying to deploy at the moment :( Hope I'll find the time to finally mail the RMagick guys about this. Maybe there's a solution somewhere...

Comment by nanodeath, Jun 26, 2008

Thanks for the prompt response! That turned out to do the trick. For the record, matte_replace is also a helpful function. With little experience with Gosu or RMagick it's hard to tell who's the culprit with things like this. Between learning Gosu, RMagick, and Chipmunk, I definitely have my hands full. At least I already know Ruby! :)

I think I'll end up making a helper function that takes an optional "transparent" argument, which is nil for no transparency, a color name, or a pixel location.

Comment by oli.obk, Jun 29, 2008

just out of curiosity: if I wanna draw a lot of lines or circles or polygons, would it be faster to use open-gl functions (or for lines/triangles/quads the graphics() functions), than to use Gosu::Image? The Images would not change (a lot), so loading times at startup can be ignored

Comment by julianraschke, Jun 29, 2008

oli, I don't think either would hurt in C++ (which you seem to use), but I would go with the image. Pro tip: Try to make it about 500x500 so it can fit on a 512x512 texture (even with some extra padding pixels).

Comment by oli.obk, Jul 01, 2008

wait, I don't understand, you mean even if the actual image would be like 300x100? Wouldn't that be an increadible waste of resources (well I don't care about RAM as long as the graphicscard doesn't start swapping in and out like crazy)? Or are images put on a 512x512 texture anyway?

Comment by julianraschke, Jul 01, 2008

I always through around with images without thinking about it and never had any VRAM troubles :)

Yes, Gosu uses large textures and then allocates all images on them. This way, bitmap fonts don't create hundreds of textures. Also, images too large for a single texture are transparently split up.

Comment by michael.keenan, Today (8 hours ago)

Thank-you so much Julian for Gosu! Making games is now so easy and fun.

Is there any way to make a Gosu Window that extends across more than one monitor? I have two monitors and wanted to make a window that would extend all the way across both (approximately 2560 pixels) but whenever I try to create a window with a width of greater than 1274 pixels, it doesn't appear. The program still runs and the Window.button_down function still gets called, but the window doesn't display. I'm running Gosu on Windows and my resolution is 1280 by 1024.

For example, this causes my problem:

class Game < Window
  def initialize
    super(1275, 480, false) #1274 is ok though
...
end

Any help would be greatly appreciated!

Comment by julianraschke, Today (6 hours ago)

Hi Michael, and thanks! I guess it's 1274 because Windows adds some pixels at the edges, and I've also ran into the fact that Windows prohibits windows from growing larger than the screen around them. I don't know if there's anything I can do about it, but the results of a few quick searches don't make it seem so. The next best thing I can think of are two Gosu applications communication over DRb or so :(


Sign in to add a comment