2

I am working with Pygame and Pymunk and my ball which is done with pymunk won’t stop rolling I think it has something to do with the friction but i do not know. Please help me. Thanks already. Is there a way to maybe set a rotation speed(but i think this would not fix it either since it is just glitching if i set the mass high up, and it still moves). I do not really know what to write here now since this is my first Question but just ask me and I will respond soon. Also I know that there are not that many people that have experience with Pymunk but I hope I find some!

Here is my code:

import pymunk
import math
import pymunk.pygame_util

pygame.init()
pygame.display.init()

WIDTH, HEIGHT = 1500, 960
BLACK = (0, 0, 0)
window = pygame.display.set_mode((WIDTH, HEIGHT))

trys_left = 3
font1 = pygame.font.SysFont(None, 25)
font = pygame.font.Font('C:\\Users\\Admin\\Downloads\\Decay-M5RB.ttf', 10)

run = True

RED = (255, 0, 0)

def message_to_screen(msg, color):
    screen_text = font1.render(msg, True, color)
    window.blit(screen_text, (30, 30))

def message_to_screen2(msg, color):
    screen_text = font.render(msg, True, color)
    window.blit(screen_text, (20, 200))


def message_to_screen3(msg, color):
    screen_text = font.render(msg, True, color)
    window.blit(screen_text, (20, 200))

def calculate_distance(p1, p2):
    return math.sqrt((p2[1] - p1[1])**2 + (p2[0] - p1[0])**2)
def calculate_angle(p1, p2):
    return math.atan2(p2[1] - p1[1], p2[0] - p1[0])





def draw(space, window, draw_options, line):
    global run
    window.fill("white")
    message_to_screen(f"You got: {trys_left} tries", RED)
    message_to_screen2(f"You can only place balls in this field", RED)
    #if run == False:
     #   message_to_screen3()

    if line:
        pygame.draw.line(window, "black", line[0], line[1], 3)
    pygame.draw.rect(window, "black", pygame.Rect(0, 0, 300, 200),1)
    #pygame.draw.line(window, "black", (300, 0), (300, 200))
    #pygame.draw.line(window, "black", (0, 200), (300, 200))
    space.debug_draw(draw_options)

    pygame.display.update()

def level_rects(space, width, height):
    rects = [
        [(width / 3, height - 300), (width, 5)],
        [(width / 1, height - 200), (width / 1, 5)]



    ]

    for pos, size in rects:
        body = pymunk.Body(body_type=pymunk.Body.STATIC)
        body.position = pos

        shape = pymunk.Poly.create_box(body, size)
        shape.color = (255, 0, 0, 100)
        shape.elasticity = 0.1
        shape.friction = 2
        space.add(body, shape)



def create_boundaries(space, width, height):
        rects = [
            [(width / 4, height - 10), (width, 20)], [(width / 2, 10), (width, 20)], [(10,  height / 2), (20, height)], [(width - 10, height / 2), (20, height)]

        ]

        for pos, size in rects:

            body = pymunk.Body(body_type=pymunk.Body.STATIC)
            body.position = pos
            shape = pymunk.Poly.create_box(body, size)
            shape.elasticity = 0.8
            shape.friction = 0.5
            space.add(body, shape)

def create_structure(space, width, height):
    BROWN = (139, 69, 19,100)
    CYAN = (0, 100, 100, 100)
    rects = [
        [(300, height - 120), (40, 200), CYAN, 100],
        [(600, height - 120), (40, 200), BROWN, 100],
        [(450, height - 240), (340, 40), BROWN, 150],
        #[(1000, height - 600), (340, 40), BROWN, 150]#dieses Stäbchen

    ]
    for pos, size, color , mass in rects:
        body = pymunk.Body()
        body.position = pos
        shape = pymunk.Poly.create_box(body, size, radius = 2)
        shape.color = color
        shape.mass = mass
        shape.collision_type = 2
        shape.elasticity = 0.4
        shape.friction = 0.4
        space.add(body, shape)
        print("pos is: ",pos  )
        print("size is: " ,size)
        print("color is: " , color)
        print("mass is: " , mass)

def create_swinging_ball(space):
    rotation_center_body = pymunk.Body(body_type=pymunk.Body.STATIC)
    rotation_center_body.position = (500, 170)
    body = pymunk.Body()
    body.position = (500, 200 )
    line = pymunk.Segment(body, (0, 0), (255, 0), 5)
    circle = pymunk.Circle(body, 40, (255, 0))
    line.friction = 1
    circle.friction = 1
    line.mass = 8
    circle.mass = 30
    circle.elasticity = 0.95
    rotation_center_joint = pymunk.PinJoint(body, rotation_center_body, (0, 0))
    space.add(circle, line, body, rotation_center_joint)

def create_ball(space, radius, mass, pos):



    body = pymunk.Body(body_type=pymunk.Body.STATIC)
    body.position = pos
    
    shape = pymunk.Circle(body, radius)
    shape.mass = mass
    shape.collision_type = 1
    shape.elasticity = 0.9
    shape.friction = 0.4
    shape.color = (255, 0, 0, 100)
    space.add(body, shape)
    global trys_left
    trys_left -= 1
    #if body.is_sleeping:
       # pygame.quit()






    return shape  # warum?


def collide(arbiter, space, data):
    global run
    run = False
    print("GG U WON")





def run(window, width, height):
    global run
    run = True

    clock = pygame.time.Clock()
    fps = 60
    dt = 1 / fps
    space = pymunk.Space()
    space.gravity = (0, 981)
    create_boundaries(space, width, height)
    create_structure(space, width, height)
    create_swinging_ball(space)
    level_rects(space, width, height)
    handler = space.add_collision_handler(1, 2)
    handler.separate = collide



    draw_options = pymunk.pygame_util.DrawOptions(window)
    #ball = create_ball(space, 30, 10)
    pressed_pos = None
    ball = None

    while run:
        pygame.display.update()



        line = None
        if ball and pressed_pos:
            line = [pressed_pos, pygame.mouse.get_pos()]
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                break
            if event.type == pygame.MOUSEBUTTONDOWN:


                if not ball:
                    pressed_pos = pygame.mouse.get_pos()
                    #if pressed_pos[0] <= 300 or pressed_pos[1] <= 200: keine ahnung was das ist
                    #if not pressed_pos[0] < 300 or not pressed_pos[1] < 200:
                    #if pressed_pos[0] >= 300 or pressed_pos[1] >= 200:
                    if pressed_pos[0] <= 300 and pressed_pos[1] <= 200:
                        #geht nicht zeichen
                        ball = create_ball(space, 30, 10, pressed_pos)


                #and is only true when both are true
                #or is true when at least one is true


                    #create_ball(space, 30, 10, pressed_pos)
                    if trys_left == -1:
                        return False
                        #return True


                elif pressed_pos:

                    ball.body.body_type=pymunk.Body.DYNAMIC
                    angle = calculate_angle(*line)
                    force = calculate_distance(*line) * 60
                    fx = math.cos(angle) * force
                    fy = math.sin(angle) * force

                    ball.body.apply_impulse_at_local_point((fx, fy), (0, 0))
                    pressed_pos = None



                else:
                    space.remove(ball, ball.body)
                    ball = None






        draw(space, window, draw_options, line)
        space.step(dt)
        clock.tick(fps)
    pygame.quit()


if __name__ == "__main__":
    run(window, WIDTH, HEIGHT)
Hadeaiki
  • 21
  • 2

1 Answers1

1

Pymynk does not support "rolling" friction (because the underlying engine, Chipmunk does not support it). Its quite complicated which its why its not supported.

An easy way to make everything come to a stand-still after a while is to set damping on the Space, i.e. space.damping = 0.5 for a very aggressive damping. http://www.pymunk.org/en/latest/pymunk.html#pymunk.Space.damping

Another option which is more precise is to reduce the angular velocity of the ball each step. Like this: ball.body.angular_velocity *= 0.9 http://www.pymunk.org/en/latest/pymunk.html#pymunk.Body.angular_velocity

There's an old thread in the Chipmunk forum about the same issue here: https://chipmunk-physics.net/forum/viewtopic.php?t=536

viblo
  • 4,159
  • 4
  • 20
  • 28
  • Hi! Thank you! It works now(still a bit laggy with the damping) but ig it is alright. Do you know how to implement the issleeping method? – Hadeaiki Jul 18 '22 at 07:26
  • For sleeping to work (unless you force sleep the bodies yourself) you need to set the sleep_time_threshold on the space: http://www.pymunk.org/en/latest/pymunk.html#pymunk.Space.sleep_time_threshold There's a example of sleeping here: https://github.com/viblo/pymunk/blob/master/examples/box2d_pyramid.py – viblo Jul 26 '22 at 09:08