[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Bouncing ball - separating the physics from the frame rate



Boer Kees wrote:
The best I think you can do, is, in pseudo code:
mainloop:
-get the current time in ms
-calculate the new position of the ball
-take speed of ball, take direction of ball, calculate the imaginary end position of the ball -keep checking (with calculus), if the line ball-beginpos to ball-endpos crosses a line, if so, say where and at what angle that line is, and calculate the new imaginary endpos, mirrored about the line closest to the beginpos. (so, the position of the ball is correct, even if it bounces a couple of times inside one time-frame) (http://hyperphysics.phy-astr.gsu.edu/hbase/hframe.html for a good physics reference, also, choose radians, steer away from degrees http://en.wikipedia.org/wiki/Sine)

Hi,

Rather than use the angle of the ball, I have used the vertical and horizontal components of the velocity of the ball. If the ball hits a vertical wall then reverse the horizontal component of the velocity taking into account the 'bounce factor'. This seems to work for horizontal and vertical surfaces but I can see how it could fall down when I introduce non-horizontal or vertical surfaces. although I imagine that I could keep using the vectors but convert them into angular vectors on collision. I am still wrestling with what to do when the ball hits a surface and wants to pass through it, currently I am truncating the movement - this will become less accurate as the frame rate gets slower.

Anyway, here is my latest code, not taking into account all of the fantastic responses my post has had over the last day or so. I will have a look at all of them and I'll modify the code accordingly over the next few days. Please not, I'm only just getting to grips with OOP!

Thanks for looking,

Matt

#! /usr/bin/python

import sys, pygame
pygame.init()

xsize = 800
ysize = 600
startx = 192
starty = 0
floor = ysize - 16
ceiling = 0
lwall = 0
rwall = xsize - 16

class world:
        gravity = 1000
        bounce = 0.8

class ball(world):

    def __init__(self):
        self.velocity = [0, 0]
        self.position = [0, 0]
        self.sprite = pygame.image.load('ball.png')

    def put(self, x, y):
        self.position[0] = x
        self.position[1] = y

    def push(self, x, y):
        self.velocity[0] = x
        self.velocity[1] = y

    def update(self, timepassed):
        newvelocity = self.velocity[1] + (world.gravity * timepassed)
self.position[1] = self.position[1] + int(((self.velocity[1] + newvelocity) / 2) * timepassed)
        self.velocity[1] = newvelocity
        self.position[0] = self.position[0] + int(self.velocity[0] * timepassed)

    def checkcollision(self):
        # Check for collisions and rebound if necessary
        if self.position[1] >= floor and self.velocity[1] > 0:
            self.position[1] = floor
            self.velocity[1] = -self.velocity[1] * world.bounce
            self.velocity[0] = self.velocity[0] * world.bounce

        if self.position[1] <= ceiling and self.velocity[1] < 0:
            self.position[1] = ceiling
            self.velocity[1] = -self.velocity[1] * world.bounce
            self.velocity[0] = self.velocity[0] * world.bounce

        if self.position[0] >= rwall and self.velocity[0] > 0:
            self.position[0] = rwall
            self.velocity[0] = -self.velocity[0] * world.bounce
            self.velocity[1] = self.velocity[1] * world.bounce

        if self.position[0] <= lwall and self.velocity[0] < 0:
            self.position[0] = lwall
            self.velocity[0] = -self.velocity[0] * world.bounce
            self.velocity[1] = self.velocity[1] * world.bounce


screen = pygame.display.set_mode((xsize, ysize), 0, 32)
clock = pygame.time.Clock()
ball1 = ball()
ball1.put(startx, starty)
ball1.push(-8000, 4000)

# The main loop
while True:
    # Test for exit
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    # Update the screen
    screen.fill((0, 0, 0))
    screen.blit(ball1.sprite, ball1.position)
    pygame.display.update()

    # Apply physics to the ball
    timepassed = clock.tick(50) / 1000.0
    ball1.checkcollision()
    ball1.update(timepassed)