Rubygame 3: Days 50 & 51
(March 22, 2008 @ 09:18 AM)
Still busy as busy. Clients popping up left and right, wanting new features or wanting the deadline moved up, or both. I also got a promotion, and with it extra responsibilities and things I have to take care of. I think things are starting to settle down now, but I’m pretty bushed.
I’ve been working on Rubygame 3 almost daily (except for this week) for about a month and a half. I’ve made a lot of progress, but there’s still a lot to do. While it would have been nice to get a new Rubygame release out this month, I don’t think that’s going to happen.
I think I’m going to take the next week or so off from Rubygame, and start up again in April. I’ll probably commit a few new revisions as inspiration strikes, but mostly it’s time out.
Rubygame 3: Days 47-49
(March 20, 2008 @ 02:31 PM)
I’m still alive, just very very busy. Nothing new on Rubygame 3 lately.
Rubygame 3: Days 45 & 46
(March 17, 2008 @ 05:10 PM)
Yesterday (day 45), I made these changes:
Event hooks can be (de)activated by manipulating their @active attribute. This is nice if you want to temporarily turn off a hook, without removing it entirely.
Added MouseReleaseTrigger, the counterpart to MouseClickTrigger. It fires when a mouse button is released.
Added PreStepEvent and Sprite#pre_step, which allows the Sprite to perform an action prior to each step of the simulation. (Mostly this is useful for “slewing”, which is the Chipmunk word for “updating the velocity so that the body will reach a specified position after the next simulator step”.)
To try out all those changes (actually, as the motivation for making those changes), I updated the panda ball demo to allow the user to click and drag panda balls around with the mouse. You can even “throw” them by releasing the mouse button while the mouse is still moving.
Today (day 46), I fixed the math used by Camera to convert between screen coordinates and world coordinates. It now correctly accounts for the camera’s position, rotation, and zoom level. Camera doesn’t rotate or zoom the background yet, though.
I tried out the new camera math by adding controls to move, rotate, and zoom the camera in the panda ball demo, but I haven’t checked it in yet. I’m going to do that tomorrow, after I clean up the code a little bit.
Some other things I need to do:
Fix how sprites are undrawing themselves from the screen. They leave trails behind if they move too fast. This is generally a symptom of undrawing the sprite at the new position instead of the old; it should be an easy fix.
Investigate slowness in updating dirty rects on the screen. I’m not sure if it’s just slowness from the Ruby-implemented Rect class, or if there’s something wrong in the new code.
Make it more convenient to specify the camera mode. Right now you have to create a Screen and background surface, pack those in a RenderModeSDL, and then pass that as an argument when creating the Scene. Lots of hoops being jumped through, there.
Rubygame 3: Day 44
(March 15, 2008 @ 09:43 PM)
Several changes today. Collision events now carry references to the shapes that collided with each other, not the sprites. It’s trivial to find out the sprite when given the shape (my_shape.sprite), but very difficult to go the other way. Utility wins out.
But by far the more exciting development is the addition of the contain_vect? method to Chipmunk’s Circle and Segment classes (Poly as well, as soon as I get it working). As you could guess, this method returns true if the given vector point is inside (or touching) the shape. In other words, it’s a point collision test.
So why is that such a big deal? Because now it’s possible to check if the user has clicked on a sprite! It’s quite simple to use, too; simply create a MouseClickTrigger and pass the shape as the second argument, “area” to its initialization. That will cause the trigger to only fire when the click hits the given shape.
To test this new feature out, I’ve updated the Panda Ball demo so that if you click on a ball, it will push the ball away from the mouse cursor. It’s simple, but fun! The demo is almost turning into a minigame, to see how many you can stack before they fall down (my high score is about 32).
P.S. I loathe Comcast. They gobbled up my old ISP, and are switching over the networks. Suddenly, last night, I was unable to post or view to this blog or the wiki, or to SSH to the server. The problem has continued for over 24 hours now, and I’ve done some tests. All traceroutes from an outside server to my home computer get lost after hopping through a Comcast server in Michigan; I’m assuming that my return packets when viewing or posting to this blog are being lost in the same way. I’m hoping it’ll resolve itself soon; in the meantime, I’m using a proxy to post.
Rubygame 3: Day 43
(March 15, 2008 @ 09:21 AM)
Today I enhanced the Sprite class to store a temporary, rotated/zoomed version of their image, as I was thinking about on Day 38. This temporary image is regenerated whenever the sprite’s rotation/size change beyond a certain threshold, compared to the rotation/size depicted in the temporary image. The result is a significant boost in performance compared to before, especially in the case of many, mostly-stationary sprites. And the code actually got slightly cleaner as a result of this optimization, albeit slightly more complex (as one would expect when adding a new feature).
All this goes on behind the scenes, so developers don’t even have to think about it (but if they do want to think about it, they can adjust the threshold for regenerating the image. The default threshold will cause the image to be regenerated if the rotation changes by 0.03 radians (~2 degrees), or if the size changes by 0.1 (that’s multiples of the original size, e.g. a change from 3x to 3.1x size).
So, that’s all well and good, but it’s really just thought-practice for making the background image rotate/zoom when the camera does. Right now, the background stays static even as the objects in the scene change, which is somewhat disconcerting, and a big potential surprise for developers.
My approach for this is going to be mostly the same as it was for sprites: store a temporary rotated/zoomed version of the background. I’m anticipating room for optimization later, because backgrounds can be rather large (and thus extra slow to rotozoom), and the entire background may not be visible at once. Rotating a 1600x1200 background image in real time out of the question, but if only 640x480 of that would show on the screen, the whole background doesn’t need to be rotated, just the part that you’d see.
But, I don’t think that particular optimization will be in 3.0.0; instead, I’ll hide behind an interface so I can sneak it in later without breaking compatibility.
Speaking of which, don’t be surprised if I “clamp down” the interfaces for certain classes. In the past, Rubygame classes have been rather lax about interfaces, letting developers play fast and loose with its innards. (“Attr_accessors all around! Huzzah!”). The problem there, as I hinted, is that any changes to those innards would break compatibility.
So, the moral of the story is: keep your nose clean and your interface separate from your implementation.
See you ruby cowboy.
Rubygame 3: Days 40-42
(March 13, 2008 @ 07:47 PM)
Has it been 3 days since I last posted? Huh.
Work deadlines abound lately, so there hasn’t been a terribly large amount of work done these past few days. But, I have done some poking around at various things:
CollisionHandler now generates Start and End collision events properly. It also has an attribute, @slop, that controls how long two objects must be out-of-contact before the collision is considered to have “ended”. (This prevents End events from being emitted over and over as two objects alternate between colliding and not colliding every other frame.)
Sprites have a @name attribute, which is purely aesthetic and doesn’t affect their functionality at all. What it does do is make it easier to differentiate between sprites of the same class programmatically. I can foresee developers filling the name slot with “Player 1”, “Joe”, “red ball”, whatever they want. You could perhaps use it to draw name tags above players, or some such thing.
Per-Shape @emit_collide and @solid attributes. This allows sprites to have some parts be solid and other parts non-solid. If the per-Shape attributes aren’t specified, they are inherited from the sprite they belong to.
Rubygame 3: Day 39, Part 2
(March 10, 2008 @ 05:16 PM)
I updated the keyboard event symbols as I was thinking about this morning. I’ll let it sit, and see how I like it in a few days. I also reverted the changes to Chipmunk that I had made, but now aren’t necessary. I’ll see about generating patches for the things that are necessary, and submitting them to the Chipmunk project.
But, most of my day was actually spent working on a new Rails app I had an idea for: an API documentation building, maintenance, and viewing application. I’m calling it “Ape Doctor”, an awful play on “API Documentor”. (Ook ook, me deserve rotten banana for thinking of that one, yes?)
My Rails-fu is a bit rusty (and wasn’t all that strong anyway), but I’m making decent progress. When it’s reached a usable and halfway-stable point (in terms of database tables not shifting around), I’ll set it up online and use it to document some of the features in Rubygame 3. So, it’s a little bit of a vacation from Rubygame, but not really.
Rubygame 3: Day 39
(March 10, 2008 @ 02:46 AM)
A bit early to be posting about day 39 (it’s only 8AM on said day), but I need to think through what I’m working on now, and writing about it has proven to be a good way of doing that.
I’m doing some filtering of keyboard event names to make them prettier symbols. I’ve already changed from integer constants like K_QUOTEDBL to symbols like :"\"". But how horribly unreadable is that?
In addition to the troubles with ruby symbols not liking literal punctuation marks (and thus having to put them in quotes), I’ve also discovered that ruby symbols don’t like starting with digits, eithers. Sorry friends, but as cute as it is, :3 is not a valid symbol (:"3" is, though).
So, the question is what to do with these unruly symbols.
For punctuation, it feels natural to me (as an English speaker/writer) is to write out what it’s called in English. :comma, :colon, :backslash, :double_quote, and so on. Some of them might get a little wordy (:exclamation_mark, :right_parenthesis), but altogether they’re more readable. (Again, that’s from an English-speaking perspective. Non-English-speakers are sadly under-represented among the collection of me, myself, and I.)
Numbers are a little different. Somehow it doesn’t feel right to write them out as :one, :two, etc. Then there’s the difficulty that there are two sets of number keys on a standard English keyboard: the row above the letter keys, and the keypad on the right side. The keypad numbers will probably end up as e.g. :keypad_1. The number row might become :number_1.
Rubygame 3: Day 38
(March 09, 2008 @ 04:07 PM)
More unit tests today, this time for the Event Action and Event Trigger types. Well, most of the event triggers, anyway; there are still a few fruit left to pick there.
While I’m thinking about it, here are more things I could/should/might do (or think about) before releasing 3.0.0, in addition to the big fat list I posted a few days ago:
Investigate why collision start and end events are being emitted almost as often as plain old collision events. The obvious answer is that the object is “jittering” slightly, and so actually not always colliding with the floor every frame. May need to add a “threshold” of how many frames it has to be out of contact before the collision is considered to have ended.
Either implement or remove the behavior of MouseClickTrigger and MouseHoverTrigger to be able to test that the event occurred within a certain area (or colliding with a certain shape). I think it’s pretty important to have a trigger for “when the sprite is clicked on”, but if it would delay release too much, that could be dropped for now and added later.
Consider renaming some events names. MouseDown -> MouseClick, MouseUp -> MouseRelease, MouseMotion -> MouseMove (or MouseHover). Likewise replacing Down/Up with Press/Release for keyboard and joystick events. I’m undecided here. If I decide not to go this way, will need to rename MouseClickTrigger and such, to match the event names.
Think about #dup and #clone semantics for Sound and Surface. Should #dup and #clone both be “shallow”, with the only difference being that one (I forget which) copies the object’s frozen status? If I go that way, there would later be #deep_copy or whatnot. Or I might have #dup be a deep copy and #clone shallow. Eh. Something to think about.
What to do about camera backgrounds when the camera has been rotated/zoomed?
Should sprites keep a copy of their rotated/scaled image so that it doesn’t have to be regenerated every frame? It would (I am guessing) speed things up considerably, especially for sprites that aren’t changing much. I might also add a way to control how often that temp surface gets updated.
How do moving cameras play into that?
What to do about sprites changing size? Are they allowed to do that now? If not, how should I “reserve” @size for future versions? If they are, how does Chipmunk deal with it?
Rubygame 3: Days 36 & 37
(March 08, 2008 @ 10:21 PM)
Feeling blah lately, so not a whole lot of progress. I wrote some unit tests for Sound today. Was thinking of writing a tutorial on Event Handler and related, but didn’t feel up to it.
Rubygame 3: Day 35
(March 06, 2008 @ 06:01 PM)
Since last time, I fully implemented and documented the new Sound class. There’s not much left to do there, except for unit tests if I feel up to it.
So, what else could I do before I let Rubygame 3.0.0 out into the wild?
- Mixer::Music needs a few tweaks. Also, the Mixer module is going away, so I need to move Music to be under Rubygame.
- Get rid of Mixer. Move the initialization function to be, perhaps, Rubygame.init_audio ?
- Rename Sprites module to OldSprites ?
- There a ROADMAP item about the old sprite group’s #collide_group, with the killa and killb stuff.
- I feel like adding Surface#dup, now that I know how to implement that. But that could probably be done later.
- Lots of documentation to write for the new sprites.
- Lots of unit tests, too. (Ugh.) I could probably put these off till ‘tomorrow’ when I should do them ‘today’.
- Update the ROADMAP and Changelog.
- Figure out which of my changes to Chipmunk are necessary, and submit them as patches.
- Probably configure the Rakefile to be able to compile and install the packaged Chipmunk (nothing fancy), until a new version of Chipmunk with the changes comes.
- Change the docs template. They should properly have a Sourceforge.net button/link since I’m hosting them there (as per their policy).
Probably some other stuff… I’m sure I can come up with an infinite amount of stuff so that I can put off actually releasing Rubygame 3.
*yawns, sleeps*
Rubygame 3: Day 34
(March 05, 2008 @ 01:59 PM)
I’m definitely crazy. But I’m crazy in the way that gets things done, so it’s all good.
I’ve designed the API for the new Sound class, which will replace the Mixer::Sample class and several of the Mixer module methods (regarding channel allocation and playback).
Sound is a fairly high-level, object-oriented wrapper around SDL_mixer’s Channel and Chunk classes, simplifying their use. No need for the user to allocate channels or decide which channel to play a sound on; all that stuff is taken care of under the hood, using an available channel if there is one, or allocating a new one if needed.
There will also be a simple but effective system that allows multiple Sound objects to reference the same audio data, so that you can have many Sound objects, each with their own volume and effects, but without having to load the sound file multiple times (which would use lots of memory).
It’s pretty exciting, but I’m taking care to rein myself in and not get carried away. For Rubygame 3.0.0, Sound will just have the basic stuff that Mixer and Mixer::Sample can do now (which one simple addition: changing volume!). The idea is to take advantage of the break in backwards compatibility to set up a new, nicer foundation. Then, later versions can add more features on top of the foundation.
Back to the grind with me, now.
Rubygame 3: Day 33
(March 04, 2008 @ 05:08 PM)
I didn’t have a whole lot of time for Rubygame today, but I did look into the issue yesterday with certain Surface flags not ‘sticking’. Nothing conclusive, but all of the flags are ”request to do X” – it’s entirely possible that the things the flags are requesting just aren’t possible on my system.
Rubygame 3: Days 31 & 32
(March 03, 2008 @ 07:42 PM)
Not much to report for Day 31 (yesterday) except that I checked in the updated demo that I posted a screenshot of. As I mentioned last time, work deadlines took priority yesterday, so no time for Rubygame.
Today, I made several enhancements to the “magic_hooks” method:
- The left value in each pair (the trigger) can now be a class to magically create a hook which matches events of that class.
- The right value in each pair (the action) can now be a Proc (or Method) to make a hook that calls the Proc, passing in the hook owner and the event that triggered it. This was suggested by a comment in the previous post. Thanks, Brian!
I also tweaked MethodAction so that methods don’t have to take the event as an argument; if you want, they can take no arguments at all, and it’ll work just fine now.
And lastly, I’ve converted Screen and Surface to use :symbols instead of integer constants for its flags (:fullscreen, :noframe, etc.). Although there’s something suspicious going on, as certain flags never seem to stick (like :hardware and :colorkey) while others do fine (like :resizable and :fullscreen). Will have to poke at it more tomorrow.
Rubygame 3: Day 30, Part 2
(March 01, 2008 @ 08:22 PM)
Got pandas?
Why, yes. Yes I do. Quite a few of them, in fact.

In other news, I went and made that handy event hook factory. Take a look at it in use:
# It's so easy, it's magic!
scene.magic_hooks(:mouse_right => :add_panda,
:print_screen => :take_screenshot,
:r => :refresh,
:s => :toggle_smooth,
:q => :quit,
:escape => :quit)
I’m really excited about Rubygame 3’s sprite and event systems. They have far exceeded my initial expectations for ease of use and power, which is pretty sweet; and it’s getting better every day!
Unfortunately, since I spent all afternoon, evening, and night working on Rubygame 3 today, I’m probably not going to have much time for it tomorrow. Darn work deadlines. *sigh*
We’ll see.
Rubygame 3: Day 30
(March 01, 2008 @ 12:20 PM)
Well, ippa has convinced me that :mouse1 etc. are just a bit too cryptic, and people would need to look at the docs if they forget which number means which button. 4 and 5 are especially confusing; even I have a hard time remembering which one is wheel-up, and which is wheel-down. I also realized that the ‘advantage’ of allowing an arbitrary number of mouse buttons is rather tenuous, given that the vast majority of mice fit the 3-button-plus-wheel (or less) schema.
So, I’ve changed over to :mouse_left, :mouse_middle, :mouse_right, :mouse_wheel_up, and :mouse_wheel_down. Other mouse buttons, if they should occur, will generate :mouse_N symbols (where N is the button number). No reason to exclude them altogether (although I suspect the current SDL doesn’t even recognize buttons above 5).
Another topic that came up in the comments yesterday was compatibility with Ruby 1.9. It bears repeating here (with a lovely diagram for emphasis), that it would be helpful for the Ruby 1.9-eager folks to submit a Rubygame bug report for anything in Rubygame (either svn trunk or the latest release) that doesn’t work with Ruby 1.9 (including/especially compile errors). Please be sure to select the “Ruby 1.9” group, as illustrated below:
Rubygame 3: Day 29
(February 29, 2008 @ 08:59 PM)
Lots of poking around in the guts of events today. Most notable is that I threw out all the keyboard integer constants, as I was talking about a week ago. No more Rubygame::K_QUOTEDBL, hurray!
Likewise for mouse integer constants; I changed them to :mouseN where N is the mouse button number. So, the left mouse is :mouse1, middle is :mouse2, right is :mouse3, wheel-up is :mouse4, and wheel-down is :mouse5. I’m torn between the mouse numbers and the mouse button names. :mouse_left might be nice. The nice thing about the numbered scheme is that it supports an arbitrary number of buttons (got any 10-buttoned mice lying around? It’ll probably work!). Also, it doesn’t make any assumptions about which button is where (e.g., mouse buttons 4 & 5 are usually, but sometimes not, mouse wheel-up and wheel-down).
Next I’ll probably get rid of the Surface/Screen integer flags, as I also mentioned. Death to the integer constants! Long live the symbol!
And now for something completely different…
I had an idea for making it even more convenient to add an event hook to sprites/scenes. I figure that, by and large, most event hooks that developers will create are of the form “press this -> character does that”. So, why not have a factory function to create new event hooks that call a method in the sprite? Something like this:
sprite.keydown_hook(:up, :jump)
Wolud be equivalent to:
sprite.append_hook(
:owner => sprite,
:trigger => KeyDownTrigger(:up),
:action => MethodAction(:jump)
)
Which means “when the user presses the up arrow, call sprite#jump”.
Of course, there wolud be similar factory functions for mouse clicks, etc.
