4

Hey i am trying to create a breakout clone with pygame, and i used

self.course(180 - self.course) % 360

To bounce the ball of the paddle, however i was looking into the vector 2 class, but i got no idea how to convert my Ball class using this. If anyone could guide me in the right direction.

here is my code that i want to convert using vector2.

import pygame
import math

class Ball(pygame.sprite.Sprite):

    course = 130

    def __init__(self):
        # Calling the parent class (Sprite)
        pygame.sprite.Sprite.__init__(self)

        # Creating the ball and load the ball image
        self.image = pygame.image.load("ball.png").convert()
        self.rect = self.image.get_rect()
        self.rect.x = 0
        self.rect.y = 270

    # Creating a bounce function to make the ball bounce of surfaces.
    def bounce(self, diff):
        self.course = (180 - self.course) % 360
        self.course -= diff
        
    # Create the function that will update the ball.
    def update(self):
        course_radianse = math.radians(self.course)
        self.rect.x += 10 * math.sin(course_radianse)
        self.rect.y -= 10 * math.cos(course_radianse)
        self.rect.x = self.rect.x
        self.rect.y = self.rect.y
        
        # Check if ball goes past top
        if self.rect.y <= 0:
            self.bounce(0)
            self.rect.y = 1
            
        # Check if ball goes past left side
        if self.rect.x <= 0:
            self.course = (360 - self.course) % 360
            self.rect.x = 1
            
        # Check if ball goes past right side
        if self.rect.x >= 800:
            self.course = (360 - self.course) % 360
            self.rect.x = 800 - 1
            
        if self.rect.y > 600:
            return True
        else:
            return False
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
MerrinX
  • 183
  • 1
  • 2
  • 12
  • What exactly do you want to achieve by using it? – michalwa Feb 13 '20 at 17:14
  • I want to avoid using cos and sin, to get familiar using vector2 in pygame. I belive i need to declare all my objects in using vector2 but i am not familiar with the procedure. Hope this answered your question – MerrinX Feb 13 '20 at 17:30

1 Answers1

11

A vector defines a direction and an amount. You have to add the vector to the location of the ball. Sadly pygame.Rect stores integral numbers only, so the location of the object has to be stored in a pygame.math.Vector2, too. You need 1 vector for the location of the object and a 2nd one for the direction. Every time when the location changes, then the .rect attribute has to be set by the rounded location. If the object hits a surface then the Ball is reflected (.reflect()) by the Normal vector to the surface.

Minimal example: repl.it/@Rabbid76/PyGame-BallBounceOffFrame

import pygame
import random

class Ball(pygame.sprite.Sprite):

    def __init__(self, startpos, velocity, startdir):
        super().__init__()
        self.pos = pygame.math.Vector2(startpos)
        self.velocity = velocity
        self.dir = pygame.math.Vector2(startdir).normalize()
        self.image = pygame.image.load("ball.png").convert_alpha()
        self.rect = self.image.get_rect(center = (round(self.pos.x), round(self.pos.y)))

    def reflect(self, NV):
        self.dir = self.dir.reflect(pygame.math.Vector2(NV))

    def update(self):
        self.pos += self.dir * self.velocity
        self.rect.center = round(self.pos.x), round(self.pos.y)
   
pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()

all_groups = pygame.sprite.Group()
start, velocity, direction = (250, 250), 5, (random.random(), random.random())
ball = Ball(start, velocity, direction)
all_groups.add(ball)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    all_groups.update()

    if ball.rect.left <= 100:
        ball.reflect((1, 0))
    if ball.rect.right >= 400:
        ball.reflect((-1, 0))
    if ball.rect.top <= 100:
        ball.reflect((0, 1))
    if ball.rect.bottom >= 400:
        ball.reflect((0, -1))

    window.fill(0)
    pygame.draw.rect(window, (255, 0, 0), (100, 100, 300, 300), 1)
    all_groups.draw(window)
    pygame.display.flip()

Lets assume you have a group of blocks:

block_group = pygame.sprite.Group()

Detect the collision of the ball and the block_group. Once a collision (pygame.sprite.spritecollide()) is detected, reflect the ball on the block:

block_hit = pygame.sprite.spritecollide(ball, block_group, False)
if block_hit:
    bl = block_hit[0].rect.left  - ball.rect.width/4
    br = block_hit[0].rect.right + ball.rect.width/4
    nv = (0, 1) if bl < ball.rect.centerx < br else (1, 0)
    ball.reflect(nv)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174