0
votes

I'm trying to code a pong game on Python with Pygame. Weirdly, the game works good, the ball bounces off on edges, respawns using space, the paddles move (up/down arrow and i/k keys) without leaving the screen. Most of the time the ball collides with paddles but some other times the ball acts weirdly or teleports.

I thought the problem might with the collision logic. So that's what I'm sharing, if you want more there's the link below.

P1 and P2 represent the paddles. Basically I check if x is near the paddle and then check if y is in the paddle range (from topPaddleY to bottomPaddleY) For more code, I'm sharing it with codeskulptor3. https://py3.codeskulptor.org/#user305_Voqctw5Vzh_0.py

class Ball:
def __init__(self, radius, center, color):
    self.radius = radius
    self.initial_attributes = center
    self.center = list(center)
    self.color = color
    self.vel = [random.choice(VELOCITIES), random.choice(VELOCITIES)]

def draw(self):
    pygame.draw.circle(screen, self.color, tuple(self.center), self.radius )

def update(self, p1, p2):
    x = self.center[0]
    y = self.center[1]
    y_adjusted = (y+self.radius, y-self.radius)
    
    if y_adjusted[0] >= HEIGHT or y_adjusted[1] <= 0:
        self.vel[1] = -self.vel[1]

    if x <= 28 or x >= WIDTH - 28:
        p1_range = [p1.pos[1], p1.pos[1] + 100]
        if p1_range[0] <= y <= p1_range[1]:
            self.vel[0] = (-self.vel[0])

        p2_range = [p2.pos[1], p2.pos[1] + 100]
        if p2_range[0] <= y <= p2_range[1]:
            self.vel[0] = (-self.vel[0])



def move(self, p1, p2):
    self.center[0] = self.center[0] + self.vel[0]
    self.center[1] = self.center[1] + self.vel[1]
    self.update(p1, p2)

    keys = pygame.key.get_pressed()

    if keys[pygame.K_SPACE]:
        self.spawn()

def spawn(self):
    self.center = list(self.initial_attributes)
    self.vel = [random.choice(VELOCITIES), random.choice(VELOCITIES)]

Edit : I was able to fix it by using as suggested the y_adjusted + adding a print statement to check the position of the ball during the collision. It appeared that velocity changed more than once during the collision So i added a flag for reflection. It seems to be rolling good now. Thanks SO.

def update(self, p1, p2):
    x = self.center[0]
    y = self.center[1]
    y_adjusted = (y+self.radius, y-self.radius)
    reflected = False
    
    if y_adjusted[0] >= HEIGHT or y_adjusted[1] <= 0:
        self.vel[1] = -self.vel[1]

    if x <= 28 or x >= WIDTH - 28:
        p1_range = [p1.pos[1], p1.pos[1] + 100]
        if ((p1_range[0] <= y_adjusted[0] <= p1_range[1]) or (p1_range[0] <= y_adjusted[1] <= p1_range[1])) and (not(reflected)):
            self.vel[0] = (-self.vel[0])
            reflected = True

        p2_range = [p2.pos[1], p2.pos[1] + 100]
        if ((p2_range[0] <= y_adjusted[0] <= p2_range[1]) or (p2_range[0] <= y_adjusted[1] <= p2_range[1])) and (not(reflected)):
            self.vel[0] = (-self.vel[0])
            reflected = True
    else :
        reflected = False
1
I didn't check for errors in your code, but highly suggest using pygames own collision detection methods. - Dschoni
Welcome to SO. as written your question feels a bit broad. This isn't a forum. You should reduce your example to a minimal reproducible example as much as possible. Please read How to Ask and the other links found on that page. Have you tried firing events and displaying a flag on the screen when the collision criteria have been met? Have you tried that along with slowing down the velocity of the objects? - wwii
if p2_range[0] <= y <= p2_range[1]: What's the reason for not using y_adjusted as you did above? - TheLazyScripter
Or, have you set up a criteria with a larger area than the collision area then logged positions and velocities while in that larger area (getting close to a collision) it might give you a feel for what might be happening - could it be a timing issue, one step it is close the next step it is still close but on the other side. Maybe the collision area needs to be adjusted/scaled for velocities. The objects are moving in discrete steps - vel/time - digital not analog. - wwii

1 Answers

0
votes

I was able to fix it by using as suggested the y_adjusted + adding a print statement to check the position of the ball during the collision. It appeared that velocity changed more than once during the collision So i added a flag for reflection. It seems to be rolling good now.

def update(self, p1, p2):
    x = self.center[0]
    y = self.center[1]
    y_adjusted = (y+self.radius, y-self.radius)
    reflected = False
    
    if y_adjusted[0] >= HEIGHT or y_adjusted[1] <= 0:
        self.vel[1] = -self.vel[1]

    if x <= 28 or x >= WIDTH - 28:
        p1_range = [p1.pos[1], p1.pos[1] + 100]
        if ((p1_range[0] <= y_adjusted[0] <= p1_range[1]) or (p1_range[0] <= y_adjusted[1] <= p1_range[1])) and (not(reflected)):
            self.vel[0] = (-self.vel[0])
            reflected = True

        p2_range = [p2.pos[1], p2.pos[1] + 100]
        if ((p2_range[0] <= y_adjusted[0] <= p2_range[1]) or (p2_range[0] <= y_adjusted[1] <= p2_range[1])) and (not(reflected)):
            self.vel[0] = (-self.vel[0])
            reflected = True
    else :
        reflected = False