pythonpygamepymunk

Defining a function in pymunk


I defined a function named add_spring in the following code

import pymunk
import pymunk.pygame_util
import math

pygame.init()
wid, hei = 800, 700
window = pygame.display.set_mode((wid, hei))


def draw(space, window, draw_options):
    window.fill("white")
    space.debug_draw(draw_options)
    pygame.display.update()

def wall(space, wid, hei):
    rects = [
        [(wid/2, hei - 10), (wid, 20)],
        [(wid/2, 10), (wid, 20)]
    ]
    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.4
        shape.friction = 0.5
        space.add(body, shape)

def create_ball(space, radius, mass):
    body = pymunk.Body()
    body.position = (500, 350)
    shape = pymunk.Circle(body, radius)
    shape.mass = mass
    shape.color = (55, 0, 0, 100)
    space.add(body, shape)
    shape.elasticity = 0.9
    shape.friction = 0.4
    return shape

def add_ball(space):
    body = pymunk.Body()
    body.position = (500, 500)
    shape = pymunk.Circle(body, 20)
    shape.mass = 1
    shape.friction = 0.7
    space.add(body, shape)
    return body

def create_ball_a(space, radius, mass):
    body = pymunk.Body(body_type=pymunk.Body.STATIC)
    body.position = (500, 300)
    shape = pymunk.Circle(body, radius)
    shape.mass = mass
    shape.color = (55, 0, 0, 100)
    space.add(body, shape)
    shape.elasticity = 0.9
    shape.friction = 0.4
    return shape

def create_ball_b(space, radius, mass):
    body = pymunk.Body(body_type=pymunk.Body.STATIC)
    body.position = (550, 300)
    shape = pymunk.Circle(body, radius)
    shape.mass = mass
    shape.color = (55, 0, 0, 100)
    space.add(body, shape)
    shape.elasticity = 0.9
    shape.friction = 0.4
    return shape
def add_spring(var1, var2):
    dlx = pymunk.DampedSpring(var1, var2, (0, 0), (0, 0), 5, 70, 0)
    space.add(dlx)



def run(window, wid, hei):
    run = True
    clock = pygame.time.Clock()
    fps = 60
    dt = 1 / fps
    space = pymunk.Space()
    space.gravity = (0, 981)
    big_ball = create_ball(space, 30, 10)
    joina = create_ball_a(space, 5, 10)
    joinb = create_ball_b(space, 5, 10)
    j = pymunk.DampedSpring(big_ball.body, joina.body, (0, 0), (0, 0), 5, 70, 0)
    space.add(j)
    add_spring(joina, big_ball)
    space.add(pymunk.DampedSpring(big_ball.body, joinb.body, (0, 0), (0, 0), 100, 100, 10))
    wall(space, wid, hei)
    draw_options = pymunk.pygame_util.DrawOptions(window)

    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                break
        draw(space, window, draw_options)
        space.step(dt)
        clock.tick(fps)
    pygame.quit()

if __name__ == "__main__":
    run(window, wid, hei)

But the following error shows up when I run it.

pygame 2.0.1 (SDL 2.0.14, Python 3.8.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "e:/pymunk/2D-cloth-simulation/string_d.py", line 104, in <module>
    run(window, wid, hei)
  File "e:/pymunk/2D-cloth-simulation/string_d.py", line 88, in run
    add_spring(joina, big_ball)
  File "e:/pymunk/2D-cloth-simulation/string_d.py", line 71, in add_spring
    dlx = pymunk.DampedSpring(var1, var2, (0, 0), (0, 0), 5, 70, 0)
  File "C:\Users\Kishlay\AppData\Local\Programs\Python\Python38\lib\site-packages\pymunk\constraints.py", line 617, in __init__
    _constraint = lib.cpDampedSpringNew(
TypeError: initializer for ctype 'struct cpBody *' must be a cdata pointer, not Body

When I do the same thing without defining a function for it, it works, but in order to keep the code clean, I need it to convert it to a function so that I can do it multiple times without hassle.


Solution

  • You have two mistakes.

    1. It needs .body (like in other DampedSpring in your code)

      You can get it from var1, var2:

      dlx = pymunk.DampedSpring(var1.body, var2.body, (0, 0), (0, 0), 5, 70, 0)
      

      Or you can send .body:

      add_spring(joina.body, big_ball.body)
      
    2. You have to send also space to this function (to run space.add()

      Get it in function:

      def add_spring(space, var1, var2):
      

      Send it to function:

      add_spring(space, joina.body, big_ball.body)
      

    Full code:

    import pygame
    import pymunk
    import pymunk.pygame_util
    import math
    
    # --- constants ---  # PEP8: `UPPER_CASE_NAMES`
    
    WIDTH = 800
    HEIGHT = 700
    FPS = 60
    
    # --- functions ---  # PEP8: all function before main code
    
    def draw(space, window, draw_options):
        window.fill("white")
        space.debug_draw(draw_options)
        pygame.display.update()
    
    def wall(space, width, height):
        rects = [
            [(width/2, height - 10), (width, 20)],
            [(width/2, 10), (width, 20)]
        ]
        
        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.4
            shape.friction = 0.5
            
            space.add(body, shape)
    
    def create_ball(space, radius, mass):
        body = pymunk.Body()
        body.position = (500, 350)
        
        shape = pymunk.Circle(body, radius)
        shape.mass = mass
        shape.color = (55, 0, 0, 100)
        shape.elasticity = 0.9
        shape.friction = 0.4
    
        space.add(body, shape)
        
        return shape
    
    def add_ball(space):
        body = pymunk.Body()
        body.position = (500, 500)
        
        shape = pymunk.Circle(body, 20)
        shape.mass = 1
        shape.friction = 0.7
        
        space.add(body, shape)
        
        return body
    
    def create_ball_a(space, radius, mass):
        body = pymunk.Body(body_type=pymunk.Body.STATIC)
        body.position = (500, 300)
        
        shape = pymunk.Circle(body, radius)
        shape.mass = mass
        shape.color = (55, 0, 0, 100)
        shape.elasticity = 0.9
        shape.friction = 0.4
        
        space.add(body, shape)
        
        return shape
    
    def create_ball_b(space, radius, mass):
        body = pymunk.Body(body_type=pymunk.Body.STATIC)
        body.position = (550, 300)
        
        shape = pymunk.Circle(body, radius)
        shape.mass = mass
        shape.color = (55, 0, 0, 100)
        shape.elasticity = 0.9
        shape.friction = 0.4
    
        space.add(body, shape)
        
        return shape
    
    def add_spring(space, body1, body2):
        dlx = pymunk.DampedSpring(body1, body2, (0, 0), (0, 0), 5, 70, 0)
        
        space.add(dlx)
        
        return dlx
    
    def run(WIDTH, HEIGHT):
        pygame.init()
        window = pygame.display.set_mode((WIDTH, HEIGHT))
    
        dt = 1 / FPS
    
        clock = pygame.time.Clock()
        
        space = pymunk.Space()
        space.gravity = (0, 981)
        
        big_ball = create_ball(space, 30, 10)
        joina = create_ball_a(space, 5, 10)
        joinb = create_ball_b(space, 5, 10)
        
        j = pymunk.DampedSpring(big_ball.body, joina.body, (0, 0), (0, 0), 5, 70, 0)
        space.add(j)
        
        add_spring(space, joina.body, big_ball.body)
        
        space.add(pymunk.DampedSpring(big_ball.body, joinb.body, (0, 0), (0, 0), 100, 100, 10))
        
        wall(space, WIDTH, HEIGHT)
        draw_options = pymunk.pygame_util.DrawOptions(window)
    
        run = True
        while run:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    run = False
                    break
                
            draw(space, window, draw_options)
            
            space.step(dt)
            clock.tick(FPS)
            
        pygame.quit()
    
    if __name__ == "__main__":
        run(WIDTH, HEIGHT)
    

    PEP 8 -- Style Guide for Python Code