0

I am making a putt putt game. I made the walls and the balls with classes and each class has a rect defining its position. All of the walls are in a list and I check the list using colliderect to see if the ball is hitting any of the walls. If so, depending on the wall (vertical or horizontal), I change the direction the ball is going. The problem is that occasionally, the ball will hit the wall and get stuck inside. I imagine that it is just continually colliding with the wall and keeps changing direction, making it just stay still.

Ive tried adding a cooldown, but even that doesn't always work. The speed of the ball shouldn't be the issue as if it moves 3px per frame, if would be moving that same speed out on the next frame after its direction was changed. However, slower speeds help but still dont completely solve this issue. Also, I am detection collisions before I move the ball on each frame.

for wall in walls:
    if wall.type == "hwall":
        if wall.rect.colliderect(ball.rect):
            ball.y_change = -(ball.y_change)
    elif wall.type == "vwall":
        if wall.rect.colliderect(ball.rect):
            ball.x_change = -(ball.x_change)

Here is the full code: https://pastebin.com/85Ge175i

10
  • if ball colides with wall then move ball a little back so it will only touch wall - if it moves left then ball.rect.left = wall.rect.right , if it moves right then ball.rect.right = wall.rect.left Commented Jul 9, 2019 at 23:40
  • 1
    with Sprite.Group() you could check collisin with all walls at once without for loop. And there is method that first move ball only on X and check with all walls (and eventually move it little back), next you move ball only on Y and check it with all walls again (and eventually move it little back). This way you can resolves some problems - ie. if you stuck in corner. Commented Jul 9, 2019 at 23:44
  • in example you can see this method in update(). Commented Jul 9, 2019 at 23:47
  • 1
    there is no sense to try resolve it without code. We can't guess what is the problem. Commented Jul 10, 2019 at 3:08
  • 1
    I checked code. You have problem because you have ball's position in two places: (ball.x,ball.y) and (ball.rect.x, ball.rect.y). First you move ball ball.x += ball.y_change but later you check collision using old position in ball.rect. You should use only ball.rect - ball.rect.x += ball.y_change and then it works correctly, almost ideal. If you slow down to clock.tick(10) then you can see that ball doesn't go inside wall. Sometimes it doesn't touch wall but it is problem for ball.rect.left = wall.rect.right Commented Jul 11, 2019 at 2:40

2 Answers 2

1

A quick solution could be to check not only for collisions, but also the position of the edges of the rectangles of walls and ball.
The code should be self explanatory:

for wall in walls:
    if wall.rect.colliderect(ball.rect):
        if wall.type == "hwall" and wall.rect.bottom < ball.rect.bottom and ball.y_change > 0:
            ball.y_change = -(ball.y_change)
        elif wall.type == "hwall" and wall.rect.top > ball.rect.top and ball.y_change < 0:
            ball.y_change = -(ball.y_change)
        elif wall.type == "vwall" and wall.rect.right < ball.rect.right and ball.x_change > 0:
            ball.x_change = -(ball.x_change)
        elif wall.type == "vwall" and wall.rect.left > ball.rect.left and ball.x_change < 0:
            ball.x_change = -(ball.x_change)

This way you are sure that once the velocity component is flipped, it's not flipped back immediately.

Sign up to request clarification or add additional context in comments.

Comments

0

Tried all methods suggested and none worked for me. Gave up on using the pygame colliderect feature as it doesnt seem to work for my specific needs. Instead I checked the ball position with all walls and manual got collision that way. Also upon collision I move the ball back a bit to prevent it getting stuck in walls.

# Check for collision
for wall in walls:
    if wall.type == "hwall":

        if ball.y_change < 0:
            if wall.rect.top <= ball.rect.top <= wall.rect.bottom and wall.rect.left <= ball.rect.center[0] <= wall.rect.right:
                ball.y_change = -(ball.y_change)
                ball.y += speed_y * 2
        else:
            if wall.rect.top <= ball.rect.bottom <= wall.rect.bottom and wall.rect.left <= ball.rect.center[0] <= wall.rect.right:
                ball.y_change = -(ball.y_change)
                ball.y -= speed_y * 2


    elif wall.type == "vwall":

        if ball.x_change < 0:
            if wall.rect.left <= ball.rect.left <= wall.rect.right and wall.rect.top <= ball.rect.center[1] <= wall.rect.bottom:
                ball.x_change = -(ball.x_change)
                ball.x += speed_x * 2
        else:
            if wall.rect.left <= ball.rect.right <= wall.rect.right and wall.rect.top <= ball.rect.center[1] <= wall.rect.bottom:
                ball.x_change = -(ball.x_change)
                ball.x -= speed_x * 2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.