2

I follow a youtube video 'https://www.youtube.com/watch?v=cCiXqK9c18g' and in the video he make a class that represent a ball and he used pymunk to make a body and added it to the space and after that he created a method inside the ball class that will use pygame to draw the ball and I did almost like him

import pygame
import pymunk

pygame.init()

fps = 60
dt = 1/fps
dsX = 800 # screen width
dsY = 500 # screen height

display = pygame.display.set_mode((dsX, dsY))
space = pymunk.Space()
clock = pygame.time.Clock()

def convert_cor(point): # convet the coordinates from pymunk to pygame coordinates
    return point[0], dsY - point[1]

class Particle: # v: velocity, pos: position[x, y], r: radius of particle(Circle)

    def __init__(self, pos = [0, 0], v = [0, 0], r = 10, color = (255, 0, 0)):

        self.pos = pos
        self.v = v
        self.r = r
        self.color = color
        self.body = pymunk.Body()
        self.body.position = self.pos
        self.body.velocity = self.v # this is the veclocity
        self.shape = pymunk.Circle(self.body, self.r)
        self.shape.dencity = 1
        self.shape.elasticity = 1
        space.add(self.body, self.shape)

    def draw(self):

        pygame.draw.circle(display, self.color, convert_cor(self.pos), self.r)

class Box: # thickness of the sides of the box and L1, L2, L3, L4 are the sides of the box

    def __init__(self, thickness, color):

        self.thickness = thickness
        self.color = color
        L1 = pymunk.Body(body_type = pymunk.Body.STATIC)
        L2 = pymunk.Body(body_type = pymunk.Body.STATIC)
        L3 = pymunk.Body(body_type = pymunk.Body.STATIC)
        L4 = pymunk.Body(body_type = pymunk.Body.STATIC)
        L1_shape = pymunk.Segment(L1, (0, 0), (dsX, 0), self.thickness)
        L2_shape = pymunk.Segment(L2, (dsX, 0), (dsX, dsY), self.thickness)
        L3_shape = pymunk.Segment(L3, (dsX, dsY), (0, dsY), self.thickness)
        L4_shape = pymunk.Segment(L4, (0, dsY), (0, 0), self.thickness)
        space.add(L1, L1_shape)
        space.add(L2, L2_shape)
        space.add(L3, L3_shape)
        space.add(L4, L4_shape)

    def draw(self):

        pygame.draw.line(display, self.color, convert_cor((0, 0)), convert_cor((dsX, 0)), self.thickness * 2)
        pygame.draw.line(display, self.color, convert_cor((dsX, 0)), convert_cor((dsX, dsY)), self.thickness * 2)
        pygame.draw.line(display, self.color, convert_cor((dsX, dsY)), convert_cor((0, dsY)), self.thickness * 2)
        pygame.draw.line(display, self.color, convert_cor((0, dsY)), convert_cor((0, 0)), self.thickness * 2)

def Sim(): # the infinite while loop as a function

    box = Box(2, (0, 255, 255))
    particle = Particle(pos =[dsX/2, dsY/2], v = [-200, 500]) # here i gave the position and the velocity

    while True:

        for event in pygame.event.get():

            if event.type == pygame.QUIT:

                return

        display.fill((255, 255, 255))
        box.draw()
        particle.draw()
        clock.tick(fps)
        space.step(dt)
        pygame.display.update()

Sim()

pygame.quit()

The thing is, I did also a class that will add a rigid sides for the display and i drew the sides from the Box class using the method 'draw' The problem is in the time 5:58 in the video he gave the ball velocity and it start moving and in my code it does not move. any idea why it doen't move? note: I called the ball particle in my code

2 Answers2

2

You error is both a typo and using the wrong variable.

Inside your particles draw function...

# OLD
def draw(self):
        pygame.draw.circle(display, self.color, convert_cor(self.pos), self.r)

# New
def draw(self):
        pygame.draw.circle(display, self.color, convert_cor(self.body.position), self.r)

You have to use the body's position cause that is the position of the physics body in pymunk's space.

Secondly...

class Particle: # v: velocity, pos: position[x, y], r: radius of particle(Circle)

    def __init__(self, pos, v, r=10, color=(255, 0, 0)):
        ...
        # Old
        self.shape.dencity = 1
    
        # New
        self.shape.density = 1

Since density was not set to anything Pymunk was having a divide by zero error so it wouldn't update the body's position.

TeddyBearSuicide
  • 1,377
  • 1
  • 6
  • 11
1
self.body.position = self.pos

To be clear about the problem:

From what I could find in the documentation, pymunk.Body.position is a property; it expects you to pass either an ordinary Python tuple or a Vec2d (not a list, although anything it's relying on internally to handle a tuple probably handles a list just fine), and calls some internal code written in another programming language. The effect is that, instead of storing your list object and then making changes to the list (which would be visible in your class, since it would be the same object), it just gets the initial values out of your list, and then doesn't use the list object.

This means that when Pymunk applies physics calculations, self.body.position changes, but self.pos does not. So the current self.pos is useless; we can't use it to check the object position.

If you don't need to do that, then there is no need to create a self.pos at all - just feed self.body.position = pos directly, and make sure to use self.body.position when drawing.

If you do, I recommend using your own property instead of trying to set self.pos. Do the above, and then add to the class:

@property
def pos(self):
    return self.body.position

And if you want to change the position from your code (but you probably shouldn't! Why else are you using the physics engine in the first place?), also add:

@pos.setter
def pos(self, value):
    self.body.position = value
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153