Search code examples
pymunk

Grouping (without collision), adding and removing multiple bodies and polygons in pymunk?


I'm using code from the pymunk index_video to create a generic function that creates multiple cars which race each other and if they reach the right extreme of the screen, they are removed from Space and re-generated on the left extreme of the screen.

The problem is, that in the example code, each part of the car (chassis, pin joint, motor, wheels) is added to Space separately. I wanted to treat the entire car as a single body whose coordinates I can keep track of by storing the reference of the entire car body in a List and add or delete it to the Space easily.

Also, if the wheels are too close to the chassis, they collide with each other. I presume using a ShapeFilter can help avoid such collisions, but for that I need all parts of the car as a single body.

Please bear with me. I'm completely new to this jargon.

def car(space):
    pos = Vec2d(100,200)

    wheel_color = 52,219,119
    shovel_color = 219,119,52
    mass = 100
    radius = 25
    moment = pymunk.moment_for_circle(mass, 20, radius)
    wheel1_b = pymunk.Body(mass, moment)
    wheel1_s = pymunk.Circle(wheel1_b, radius)
    wheel1_s.friction = 1.5
    wheel1_s.color = wheel_color
    space.add(wheel1_b, wheel1_s)

    mass = 100
    radius = 25
    moment = pymunk.moment_for_circle(mass, 20, radius)
    wheel2_b = pymunk.Body(mass, moment)
    wheel2_s = pymunk.Circle(wheel2_b, radius)
    wheel2_s.friction = 1.5
    wheel2_s.color = wheel_color
    space.add(wheel2_b, wheel2_s)

    mass = 100
    size = (50,30)
    moment = pymunk.moment_for_box(mass, size)
    chassi_b = pymunk.Body(mass, moment)
    chassi_s = pymunk.Poly.create_box(chassi_b, size)
    space.add(chassi_b, chassi_s)

    vs = [(0,0),(25,45),(0,45)]
    shovel_s = pymunk.Poly(chassi_b, vs, transform = pymunk.Transform(tx=85))
    shovel_s.friction = 0.5
    shovel_s.color = shovel_color
    space.add(shovel_s)

    wheel1_b.position = pos - (55,0)
    wheel2_b.position = pos + (55,0)
    chassi_b.position = pos + (0,-25)

    space.add(
        pymunk.PinJoint(wheel1_b, chassi_b, (0,0), (-25,-15)),
        pymunk.PinJoint(wheel1_b, chassi_b, (0,0), (-25, 15)),
        pymunk.PinJoint(wheel2_b, chassi_b, (0,0), (25,-15)),
        pymunk.PinJoint(wheel2_b, chassi_b, (0,0), (25, 15))
        )

    speed = 4
    space.add(
        pymunk.SimpleMotor(wheel1_b, chassi_b, speed),
        pymunk.SimpleMotor(wheel2_b, chassi_b, speed)
)

Solution

  • So this question is actually two questions.

    A. How to make a "car object" that consists of multiple parts

    There is no built in support for this, you have keep track of it yourself.

    One way to do it is to create a car class that contains all the parts of the car. Something like this (not complete code, you need to fill in the full car)

    class Car():
        def __init__(self, pos):
            self.wheel_body = pymunk.Body()
            self.wheel_shape = pymunk.Circle()
            self.chassi_body = pymunk.Body()
            self.chassi_shape = pymunk.Poly()
            self.motor = pymunk.SimpleMotor(wheel_body, chassi_body, 0)
    
        def add_to_space(self, space)
            space.add(self.wheel_body, self.wheel_shape, self.chassi_body, self.chassi_shape, self.motor)
    
        def set_speed(self, speed)
            self.motor.rate = speed
    
        def car_position(self)
            return self.chassi_body.position
    

    B. How to make parts of the car to not collide with each other

    This is quite straight forward, just as you already found the ShapeFilter is the way to go. For each "car", create a ShapeFilter and set a unique non-zero group on it. Then set that ShapeFilter as the filter property on each shape that makes up the car. It doesnt matter if the shapes belong to the same body or not, any shape with a ShapeFilter with a group set will not collide to other shapes with the same group set.