3

I want to create a pinball game but the ball sometimes doesn't collide with other objects. example: https://youtu.be/HwSXwJ4-d2w

Here's the code

import pyglet, pymunk
from pymunk.pyglet_util import DrawOptions

win = pyglet.window.Window(1280, 720, resizable=False)
options = DrawOptions()

space = pymunk.Space()
space.gravity = 0, -1000



def Ball(mass, radius, coords):
    circle_moment = pymunk.moment_for_circle(mass, 0, radius)
    circle_body = pymunk.Body(mass, circle_moment)
    circle_shape = pymunk.Circle(circle_body, radius)    
    circle_shape.elasticity = 1.0    
    circle_body.position= coords
    space.add(circle_body, circle_shape)

def BouncyCircle(mass, coords, radius):
    circle_moment = pymunk.moment_for_circle(mass, 0, radius)
    circle_body = pymunk.Body(mass, circle_moment, pymunk.Body.STATIC)
    circle_shape = pymunk.Circle(circle_body, radius)    
    circle_shape.elasticity = 2.0
    circle_body.position= coords
    space.add(circle_body, circle_shape)

def Segment(mass, PointA, PointB, thickness):
    segment_moment = pymunk.moment_for_segment(mass, PointA, PointB, thickness)
    segment_body = pymunk.Body(mass, segment_moment, pymunk.Body.STATIC)
    segment_shape = pymunk.Segment(segment_body, PointA, PointB, thickness)
    segment_shape.elasticity = 0.7
    segment_body.position = 0,0
    space.add(segment_body, segment_shape)



Ball(0.1, 15, (640, 550)) #Falling Ball

BouncyCircle(1, (650,100), 40) #Ball

Segment(10, (105,55), (1195,55), 5) #Border
Segment(10, (100, 50), (100,680), 5)
Segment(10, (105, 675), (1195,675), 5)
Segment(10, (1200, 50), (1200, 680), 5)


@win.event

def on_draw():
    win.clear()
    space.debug_draw(options)

def update(dt):
    space.step(dt)


if __name__ == "__main__":
    pyglet.clock.schedule_interval(update, 1/60)
    pyglet.app.run()

It also happens when it's very slow and sometimes it bounces 10 times until it stops working. Does anybody know how to fix it?

1 Answers1

0

Its most likely because the ball is moving too fast. If a object, such as the ball, moves from one side of the wall to the other side of the wall in a single simulation step (a call to space.step()) the ball will tunnel through.

There are several ways to mitigate this problem. Sometimes it might be a good idea to do more than one of these.

  1. Make sure the velocity of objects never get too high. One way to do that is to use a custom velocity function with a limit built in on the bodies that have a tendency to move too fast:

    def limit_velocity(body, gravity, damping, dt):
        max_velocity = 1000
        pymunk.Body.update_velocity(body, gravity, damping, dt)
        l = body.velocity.length
        if l > max_velocity:
            scale = max_velocity / l
            body.velocity = body.velocity * scale
    
    body_to_limit.velocity_func = limit_velocity
    
  2. Depending on the requirements it might make more sense to clamp the velocity over multiple frames instead. Then the limit function could look like this instead:

    def limit_velocity(body, gravity, damping, dt):
        max_velocity = 1000
        pymunk.Body.update_velocity(body, gravity, damping, dt)
        if body.velocity.length > max_velocity:
            body.velocity = body.velocity * 0.99
    
  3. Use a smaller value for dt in the call to space.step. A simple way is to call space.step multiple times each frame in your application. This will also help to make the overall simulation more stable.

I think 1 or 2 is the best option for you.

I updated the pymunk docs with this explanation + a little more here: http://www.pymunk.org/en/latest/overview.html#object-tunneling

viblo
  • 4,159
  • 4
  • 20
  • 28