1

recently I've been trying to create a bouncing ball in pygame and I have been successful using sprite rect collide, however when it comes to a floating block the ball doesn't know whether to inverse horizontal or vertical velocity or if it hits a corner so I started to use collide points but after many failed attempts, when the ball should become stationary vertically, the ball just vibrates.

Here is my code to handle collisions:

def HitHorizontal(self):
        self.velocity[0] = self.velocity[0] * self.bounce
        self.velocity[1] = -self.velocity[1] * self.bounce
        self.move_y = self.velocity[1]


    def HitVertical(self):
        self.velocity[0] = -self.velocity[0] * self.bounce
        self.velocity[1] = self.velocity[1] * self.bounce
        self.move_x = self.velocity[0]



    def move_checker(self,obj):
        rect = obj.rect
        #hits left or right of ball
        horizontal = False
        vertical = False
        if rect.collidepoint((self.rect.topleft[0]+self.move_x,self.rect.topleft[1])):
            vertical = True
        elif rect.collidepoint((self.rect.topright[0]+self.move_x,self.rect.topright[1])):
            vertical = True
        elif rect.collidepoint((self.rect.bottomleft[0]+self.move_x,self.rect.bottomleft[1])):
            vertical = True
        elif rect.collidepoint((self.rect.bottomright[0]+self.move_x,self.rect.bottomright[1])):
            vertical = True

        #hits top or bottom of ball

        if rect.collidepoint((self.rect.topleft[0],self.rect.topleft[1]+self.move_y)):
            horizontal = True
        elif rect.collidepoint((self.rect.topright[0],self.rect.topright[1]+self.move_y)):
            horizontal = True
        elif rect.collidepoint((self.rect.bottomleft[0],self.rect.bottomleft[1]+self.move_y)):
            horizontal = True
        elif rect.collidepoint((self.rect.bottomright[0],self.rect.bottomright[1]+self.move_y)):
            horizontal = True

        #hits corner of wall

        if rect.collidepoint((self.rect.topleft[0]+self.move_x,self.rect.topleft[1]+self.move_y)):
            vertical = True
            horizontal = True
        elif rect.collidepoint((self.rect.topright[0]+self.move_x,self.rect.topright[1]+self.move_y)):
            vertical = True
            horizontal = True
        elif rect.collidepoint((self.rect.bottomleft[0]+self.move_x,self.rect.bottomleft[1]+self.move_y)):
            vertical = True
            horizontal = True
        elif rect.collidepoint((self.rect.bottomright[0]+self.move_x,self.rect.bottomright[1]+self.move_y)):
            vertical = True
            horizontal = True

        if horizontal:
            self.HitHorizontal()
        if vertical:
            self.HitVertical()

Here is the full code:

import sys, pygame, random, math, time
pygame.init()

xsize = 800
ysize = 600
startx = 600
starty = 100

class Wall(pygame.sprite.Sprite):
    def __init__(self, x, y, w, h):
        super().__init__()
        self.image = pygame.Surface((w, h))
        self.image.fill((0,0,0))
        self.rect = self.image.get_rect(topleft=(x, y))

class Ball(pygame.sprite.Sprite):

    def __init__(self):
        super().__init__()
        self.velocity = [0, 0]
        self.image = pygame.image.load('ball.png')
        self.image = pygame.transform.scale(self.image,(50,50))
        self.gravity = 9.81
        self.bounce = 0.8

        self.rect = self.image.get_rect()
        self.put(startx, starty)
        self.collision = [False] * 9
        self.velocity[0] = 0
        self.velocity[1] = 0

    def put(self, x, y):
        self.rect.x = x
        self.rect.y = y

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

    def Get_Move(self):
        self.move_x = self.velocity[0]
        self.velocity[1] += (self.gravity * 0.2)
        self.move_y = self.velocity[1]



    def update(self):
        self.rect.x += self.move_x
        self.rect.y += self.move_y



    def HitHorizontal(self):
        self.velocity[0] = self.velocity[0] * self.bounce
        self.velocity[1] = -self.velocity[1] * self.bounce
        self.move_y = self.velocity[1]


    def HitVertical(self):
        self.velocity[0] = -self.velocity[0] * self.bounce
        self.velocity[1] = self.velocity[1] * self.bounce
        self.move_x = self.velocity[0]



    def move_checker(self,obj):
        rect = obj.rect
        #hits left or right of ball
        horizontal = False
        vertical = False
        if rect.collidepoint((self.rect.topleft[0]+self.move_x,self.rect.topleft[1])):
            vertical = True
        elif rect.collidepoint((self.rect.topright[0]+self.move_x,self.rect.topright[1])):
            vertical = True
        elif rect.collidepoint((self.rect.bottomleft[0]+self.move_x,self.rect.bottomleft[1])):
            vertical = True
        elif rect.collidepoint((self.rect.bottomright[0]+self.move_x,self.rect.bottomright[1])):
            vertical = True

        #hits top or bottom of ball

        if rect.collidepoint((self.rect.topleft[0],self.rect.topleft[1]+self.move_y)):
            horizontal = True
        elif rect.collidepoint((self.rect.topright[0],self.rect.topright[1]+self.move_y)):
            horizontal = True
        elif rect.collidepoint((self.rect.bottomleft[0],self.rect.bottomleft[1]+self.move_y)):
            horizontal = True
        elif rect.collidepoint((self.rect.bottomright[0],self.rect.bottomright[1]+self.move_y)):
            horizontal = True

        #hits corner of wall

        if rect.collidepoint((self.rect.topleft[0]+self.move_x,self.rect.topleft[1]+self.move_y)):
            vertical = True
            horizontal = True
        elif rect.collidepoint((self.rect.topright[0]+self.move_x,self.rect.topright[1]+self.move_y)):
            vertical = True
            horizontal = True
        elif rect.collidepoint((self.rect.bottomleft[0]+self.move_x,self.rect.bottomleft[1]+self.move_y)):
            vertical = True
            horizontal = True
        elif rect.collidepoint((self.rect.bottomright[0]+self.move_x,self.rect.bottomright[1]+self.move_y)):
            vertical = True
            horizontal = True

        if horizontal:
            self.HitHorizontal()
        if vertical:
            self.HitVertical()



class Game:

    def __init__(self):
        self.AllSprites = pygame.sprite.Group()
        self.Walls = pygame.sprite.Group()
        self.total_shots = 0
        self.putting = False
        self.LoadLevel()

    def LoadLevel(self):
        self.GetWalls()

    def start(self):
        self.ball.Moving = True


    def GetWalls(self):
        self.wall_list = [[0,300,xsize,600],[0,-30,xsize,30],[-30,0,30,ysize],[xsize,0,30,ysize],[0,100,300,20 ]]

    def CreateWalls(self):
        for wally in self.wall_list:
            new_wall = Wall(wally[0],wally[1],wally[2],wally[3])
            self.Walls.add(new_wall)
            self.AllSprites.add(new_wall)

    def CreateBall(self):
        self.ball = Ball()
        self.ball.put(300,100)
        self.AllSprites.add(self.ball)


    def DetectWallCollide(self):
        for wall in self.Walls:
            if self.ball.rect.colliderect(wall.rect):
                self.ball.move_checker(wall)



def main():
    screen = pygame.display.set_mode((xsize, ysize), 0, 32)
    clock = pygame.time.Clock()

    game = Game()
    game.CreateWalls()
    game.CreateBall()

    game.start()



    # 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((255, 255, 0))

        game.ball.Get_Move()
        game.DetectWallCollide()
        game.ball.update()
        game.AllSprites.draw(screen)
        pygame.display.update()
        clock.tick(50)


main()

Thanks for any help, Adam.

A Tsang
  • 87
  • 9
  • If you know the direction the ball is travelling, you should be able to determine the side and position of the collision on the rectangle. For example, if the ball is travelling downward and to the left, it probably didn't collide with the bottom or the left of the rectangle. You can also use the position of the ball and the rectangle at the time of the collision to determine whether the ball hit the top, bottom, left, or right of the rectangle first. – Benjamin Hoving Nov 05 '19 at 21:38
  • The colliding physics works now though, the problem is the fact the ball doesn't become stationary. Thanks for the help, Adam. – A Tsang Nov 06 '19 at 08:46

0 Answers0