Pygame: How can i correct falling balls from moving upwards?

Viewed 104

The blocks in the code below are falling against gravity. They are moving from the bottom of the screen to the top when I run this code. I have tried to adjust the Gravity function but it's still moving from bottom to top which is opposite gravity. The code is however running well when I tested with another Laptop. I currently learning pygame.

import sys, random
import pygame
from pygame.locals import *
import pymunk
import pymunk.pygame_util
from random import seed
from random import choice

def add_circular_weight(space,mass=1,x=150,y=550):
    radius = 5 + mass/10
    inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0))
    body = pymunk.Body(mass, inertia)
    body.position = x, y
    shape = pymunk.Circle(body, radius, (0,0))
    space.add(body, shape)
    return shape


def main():
    masses=[10,20,30,40,50,60,70,80,90,100]
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    pygame.display.set_caption("Experiments")
    clock = pygame.time.Clock()

    space = pymunk.Space()
    space.gravity = (0.0, -900.0)


    balls = []
    draw_options = pymunk.pygame_util.DrawOptions(screen)

    ticks_to_next_ball = 10
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit(0)
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                sys.exit(0)
            '''if event.key == pg.K_a:
                self.body.angular_velocity = 5.5
            elif event.key == pg.K_w:
                self.body.apply_impulse_at_local_point(Vec2d(0, 900))'''

        ticks_to_next_ball -= 1
        if ticks_to_next_ball <= 0:
            ticks_to_next_ball = 25
            ball_shape = add_circular_weight(space, mass=choice(masses), x = random.randint(120,380))
            balls.append(ball_shape)

        screen.fill((255,255,255))

        balls_to_remove = []
        for ball in balls:
            if ball.body.position.y < 150:
                balls_to_remove.append(ball)

        for ball in balls_to_remove:
            space.remove(ball, ball.body)
            balls.remove(ball)

        space.debug_draw(draw_options)

        space.step(1/50.0)

        pygame.display.flip()
        clock.tick(5)

if __name__ == '__main__':
    main()
1 Answers

The problem is most likely a change that was made between pymunk 5.7 and 6.0. In the old version pymunk treated the direction of y opposite to how pygame does it when drawing a space with pymunk_utils. To simplify things this was changed, so that both Pymunk and Pygame do the same thing.

To get the old behavior back you can set positive_y_is_up in pygame_util to True: pymunk.pygame_util.positive_y_is_up = True. However, if you dont have a lot of old code I suggest instead to modify the positions and gravity. This will make it simpler to reason about if you need to draw anything using pygame directly. (To convert you do converted_y_value = surface.get_height() - old_y_value)

Converted your code would then look like:

import random
import sys
from random import choice, seed

import pygame
import pymunk
import pymunk.pygame_util
from pygame.locals import *


def add_circular_weight(space,mass=1,x=150,y=150):
    radius = 5 + mass/10
    inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0))
    body = pymunk.Body(mass, inertia)
    body.position = x, y
    shape = pymunk.Circle(body, radius, (0,0))
    space.add(body, shape)
    return shape


def main():
    masses=[10,20,30,40,50,60,70,80,90,100]
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    pygame.display.set_caption("Experiments")
    clock = pygame.time.Clock()

    space = pymunk.Space()
    space.gravity = (0.0, 900.0)
    #print(pymunk.pygame_util.positive_y_is_up)
    #print(pymunk.version)


    balls = []
    draw_options = pymunk.pygame_util.DrawOptions(screen)

    ticks_to_next_ball = 10
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit(0)
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                sys.exit(0)
            '''if event.key == pg.K_a:
                self.body.angular_velocity = 5.5
            elif event.key == pg.K_w:
                self.body.apply_impulse_at_local_point(Vec2d(0, -900))'''

        ticks_to_next_ball -= 1
        if ticks_to_next_ball <= 0:
            ticks_to_next_ball = 25
            ball_shape = add_circular_weight(space, mass=choice(masses), x = random.randint(120,380))
            balls.append(ball_shape)

        screen.fill((255,255,255))

        balls_to_remove = []
        for ball in balls:
            if ball.body.position.y > 550:
                balls_to_remove.append(ball)

        for ball in balls_to_remove:
            space.remove(ball, ball.body)
            balls.remove(ball)

        space.debug_draw(draw_options)

        space.step(1/50.0)

        pygame.display.flip()
        clock.tick(5)

if __name__ == '__main__':
    main()
Related