Rubygame 3: Day 16

Did some more Chipmunk R&D work today.

Small news is that I found out that it actually is possible to reassign a Shape to a different body. In fact, there was already a Shape#body= accessor that I somehow missed.

Bigger news is that I added a new method, Poly#set_verts, which allows the vertices of a Poly to be changed after creation. I tested it out in one of the demos, by making a shape that changes size at random. Sudden, dramatic changes in shape can cause undesired effects (like falling through the wall), but there's no real problem with gradual (or even moderate) changes in shape.

Thanks to Poly#set_verts, I'll be able to allow sprites to be resized and otherwise transformed, which is nice!

Speaking of transforming Polys, I've been working on a Matrix class for Chipmunk, to store transformation information. It's complete except for a bug in the matrix multiplication math that's causing some incorrect values. Once I fix that, I think it's ready to go.

Unfortunately, Chipmunk does not distinguish between points and vectors. While their data structures are equivalent (both have an X and Y component), there are behavioral differences when it comes to transformations. In particular, vectors should not be affected by translation (movement) operations, while points should be.

I'm not sure how I'll handle this. The obsessive compulsive streak in me thinks that there should be a new Point class, but that would require, I think, more changes to Chipmunk's guts than I want to make. Perhaps I could add an integer field to the Vect struct, which would indicate whether it was representing a vector or a point. Not the cleanest solution in the world, but serviceable.

Might make another report later about my fuzzy, shifting thoughts on sprites and sprite bodies, but now it's back to the code mines to figure out this matrix math.


n/a submitted a comment on #

When you’re talking about fitting sprites into “chipmunkobjects”, are you talking about plain old bitmapsprites or OpenGLobjects?

Scott Lembcke submitted a comment on #

On thing. Be aware that changing the shape of an object is producing non-physical behavior. It produces movement without any velocity change. Very much an abuse of the interpenetration correction. If I had my way, I wouldn’t allow such things. ;)

John Croisant submitted a comment on #

@Scott: Indeed the solution is rather non-kosher. But it’s important (to me) that objects can change size at times; think of Mario becoming larger when he eats a mushroom.

My initial thought on how to do such a thing was to remove the old shape and replace it with a new one at a different size. But, it seems that would be extra work while being just as abusive of the interpenetration correction. ;)

I am being sure to sprinkle the docs liberally with the phrase “Use with caution!”, of course.

Scott Lembcke submitted a comment on #

Oh, and the usual way of handling points vs. vectors is to use the homogenous coordinates to your advantage. For vectors, zero out the scale coordinate before transforming, and don’t re-normalize the scale.

require 'matrix'

def scale(s)
		[  s, 0.0, 0.0],
		[0.0,   s, 0.0],
		[0.0, 0.0, 1.0]

def translate(x, y)
		[1.0, 0.0,   x],
		[0.0, 1.0,   y],
		[0.0, 0.0, 1.0]

def dialate(x, y, s)
	translate(x, y)*scale(s)*translate(-x, -y)

def perspective_divide(v)
	s = 1.0/v[2]
	Vector[v[0]*s, v[1]*s, 1.0]

def discard_scale(v)
	Vector[v[0], v[1], 0.0]

p vec = Vector[1.0, 2.0, 1.0]
p mat = dialate(1.0, 1.0, 3.0)

# transform and renormalize the scale component
p perspective_divide(mat*vec)

# discard the scale component and transform
vec = discard_scale(vec)
p mat*vec

Produces the output:

Vector[1.0, 2.0, 1.0]
Matrix[[3.0, 0.0, -2.0], [0.0, 3.0, -2.0], [0.0, 0.0, 1.0]]
Vector[1.0, 4.0, 1.0]
Vector[3.0, 6.0, 0.0]

So it works correctly as you can see. The first output is dilated away from point correctly, while the second ignores the translations and only scales the vector.

Have something interesting to add to the discussion? Email your thoughtful comments to