Search code examples
pythonpython-2.7box2dgame-physicsphysics-engine

Odd Box2D error when converting to world coordinates


I wrote a function to draw my Box2D box using pygame, however in the step where I multiply the vertex vectors of the box by the body's transform, the program crashes.

Here is the function:

def draw(self):
    pointlist = []
    for vertex in self.fixture.shape.vertices:
        vertex = vec2(vertex[0], vertex[1])
        print vertex, self.body.transform
        vertex * self.body.transform
        pointlist.append(world_to_screen(
            vertex[0],
            vertex[1]
            ))
    pygame.draw.polygon(SCREEN, RED, pointlist)

And here is the error that I receive:

b2Vec2(-0.4,-0.4) b2Transform(
    R=b2Mat22(
            angle=0.0,
            col1=b2Vec2(1,0),
            col2=b2Vec2(-0,1),
            inverse=b2Mat22(
                        angle=-0.0,
                        col1=b2Vec2(1,-0),
                        col2=b2Vec2(0,1),
                        inverse=b2Mat22((...) )
    angle=0.0,
    position=b2Vec2(6,5.99722),
    )
Traceback (most recent call last):
...
line 63, in draw
    vertex * self.body.transform
TypeError: in method 'b2Vec2___mul__', argument 2 of type 'float32'
[Finished in 2.4s with exit code 1]

I don't understand it. I am passing self.body.transform.__mul__() what seem to be valid arguments, the transform and a vector, but it gives a weird error that I don't understand.


Solution

  • You try to multiply a vertex with a matrix. That's not supported, try it the other way round:

    transform * vertex
    

    Also, you are needlessly copying but then not assigning the results of the applied transformation.

    This should work:

    def draw(self):
        pointlist = []
        for vertex in self.fixture.shape.vertices:
           transformed_vertex = vertex * self.body.transform
           pointlist.append(world_to_screen(
              transformed_vertex[0],
              transformed_vertex[1]
              ))
        pygame.draw.polygon(SCREEN, RED, pointlist)
    

    I would also suggest you make your world_to_screen take a vertex, and thus making the whole affair a simple

    def draw(self):
        t = self.body.transform
        pointlist = [w2s(t * v) for v in self.fixture.shape.vertices]
        pygame.draw.polygon(SCREEN, RED, pointlist)