Question

I'm writing a Pong game with Pygame and this is the code for my Ball class so far:

class Ball(pygame.sprite.Sprite):

    def __init__(self, game, vector=Vec2D.Vec2D()):
        super(Ball, self).__init__()

        self.image = pygame.Surface((BALL_RADIUS*2, BALL_RADIUS*2))
        self.rect = self.image.get_rect()
        self.__draw_ball()

        screen = pygame.display.get_surface()
        self.area = screen.get_rect().inflate(-GAP*2, 0)

        self.vector = vector
        self.game = game
        self.reinit()

    def __draw_ball(self):
        self.image.fill(BLACK)
        self.image.set_colorkey(BLACK, RLEACCEL)
        pygame.draw.circle(self.image, WHITE, (self.rect.centerx, self.rect.centery), BALL_RADIUS)

    def reinit(self):
        self.rect.centerx = self.area.centerx
        self.rect.centery = self.area.centery
        self.vector = Vec2D.Vec2D.from_magn_and_angle(BALL_SPEED, 0)

    def update(self):
        self.rect = self.calcnewpos()
        self.handle_collision()

    def calcnewpos(self):
        (dx, dy) = self.vector.get_xy()
        return self.rect.move(dx, dy)

    def handle_collision(self):
        (dx, dy) = self.vector.get_xy()

        if not self.area.contains(self.rect):
            if self.__hit_topbottom():
                dy = -dy
            elif self.__hit_leftright():
                self.game.increase_score()
                self.reinit()
        else:
            for paddle in self.hit_paddle(dx):
                if dx < 0: self.rect.left = GAP + PADDLE_WIDTH
                elif dx > 0: self.rect.right = SCREEN_WIDTH - (GAP + PADDLE_WIDTH)

                dx = -dx
                dy = paddle.hitpos / 4
                paddle.collided = True

        self.vector = Vec2D.Vec2D(dx, dy)

    def _hit_topbottom(self):
        return self.rect.top < 0 or self.rect.bottom > SCREEN_HEIGHT

    def _hit_leftright(self):
        return self.rect.left < self.area.left or self.rect.right > self.area.right

    def hit_paddle(self, dx):
        if dx < 0: paddle = self.game.paddles['left']
        elif dx > 0: paddle = self.game.paddles['right']

        if self.rect.colliderect(paddle.rect): return [paddle]
        else: return []  

Well, after the player (or the AI) scores, the ball calls its reinit method that places the ball in the middle of the screen and resets the vector:

def reinit(self):
    self.rect.centerx = self.area.centerx
    self.rect.centery = self.area.centery
    self.vector = Vec2D.Vec2D.from_magn_and_angle(BALL_SPEED, 0)

But, somehow, the ball still maintains the vector it had before reinit was called. So when the ball gets through the left side with a vector like (-5.0 -2.0), it changes quickly in the reinit call and then change back to (-5.0, -2.0). Can someone please tell me why this is happening?

Was it helpful?

Solution

The problem, is in your handle_collision method.

The short story:
The first thing the function does, is set dx and dy to the current vector. Then it calls reinit(). Then, it sets them back to what the first were at the end of the function.

To fix:
Change

def handle_collision(self):
    (dx, dy) = self.vector.get_xy() # <-- It first sets (dx, dy) to the old vector

    if not self.area.contains(self.rect):
        if self.__hit_topbottom():
            ...
        elif self.__hit_leftright():
            ...  # <-- here is where the reinit gets called, which changes the vector to new values.
    else:
        for paddle in self.hit_paddle(dx):
            ...

    self.vector = Vec2D.Vec2D(dx, dy)  # <-- Then the vector gets changed again, to the OLD vector saved above in (dx, dy)

To

def handle_collision(self):
    (dx, dy) = self.vector.get_xy()

    if not self.area.contains(self.rect):
        if self.__hit_topbottom():
            ...
        elif self.__hit_leftright():
            ...
            return  # <-- With the return here, the parsing never gets to change it back
    else:
        for paddle in self.hit_paddle(dx):
            ...

    self.vector = Vec2D.Vec2D(dx, dy)

This will prevent the vector getting set back to what it was, while still setting it when it needs to be.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top