Jump to content

ping pong paddle collision with images in python with pygame

Denz006

ball.icoball.png.0f365ce2fbabf0fc236fa72563e53d3e.pngpaddle.png.602f451aa893f4ca3b98efed7bcde7d6.png

 

so I want to make a collision system with images but i can't seem to figure it out 

and download these images 

 

Link to comment
Share on other sites

Link to post
Share on other sites

oh almost forgot heres the code

# import
import time
import pygame
import random
import math
from pygame.locals import*
pygame.init()

# image import
icon = pygame.image.load('ball.ico')
ball = pygame.image.load('ball.png')
paddle = pygame.image.load('paddle.png')

# window setup
pygame.display.init()
screen = pygame.display.set_mode((1200, 680))
pygame.display.set_caption("ping pong")
pygame.display.set_icon(icon)

# player setup
player1x = 50
player1y = 289
player2x = 1130
player2y = 289
ball2x = 585
ball2y = 345
movement1 = 0
movement2 = 0
ball_speedx = random.choice((1.5,-1.5))
ball_speedy = random.choice((1.5,-1.5))


def player1(x,y):
    screen.blit(paddle, (player1x,player1y))

def player2(x,y):
    screen.blit(paddle,(player2x,player2y))

def ball1(x,y):
    screen.blit(ball,(ball2x,ball2y))
    
def collision(ball2x,ball2y,player1x,player1y):
    distance = math.sqrt(math.pow(ball2x - player1x,2)+math.pow(ball2x - player1y,2))
    if distance < 00:
        ball_speedx = 1.5
        ball_speedy = 1.5
        
# everything esle
running = True
while running:

    
    
    # clock system
    FPS = 120
    clock = pygame.time.Clock()
    ticks = clock.tick(FPS)
    
    screen.fill((0, 0, 0))
    
    # window closing
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
            
        # keyboard controls
        if event.type == pygame.KEYDOWN:
            if event.key == K_s:
                movement1 = 0.6
            if event.key == K_w:
                movement1 = -0.6
            if event.key == K_DOWN:
                movement2 = 0.6 
            if event.key == K_UP:
                movement2 = -0.6
        if event.type == pygame.KEYUP:
            if event.key == K_s or event.key == K_w or event.key == K_DOWN or event.key == K_UP:
                movement1 = 0
                movement2 = 0
                
    # paddle movemnt
    player1y += movement1*ticks
    player2y += movement2*ticks

    #ball movement
    ball2x += ball_speedx 
    ball2y += ball_speedy 
    
    # object position            
    ball1(ball2x, ball2y)
    player2(player2x, player2y)  
    player1(player1x, player1y)

    # paddle border
    if player1y <= 0:
        movement1 = 0
    if player1y >= 538:
        movement1 = 0
    if player2y <= 0:
        movement2 = 0
    if player2y >= 538:
        movement2 = 0

    # ball collision with wall
    if ball2y <= 0:
        ball_speedy = +1.5
    if ball2y >= 649:
        ball_speedy = -1.5
    if ball2x <= 0:
        exit()
    if ball2x >= 1180:
        exit()

    pygame.display.update()
    

 

Link to comment
Share on other sites

Link to post
Share on other sites

Represent the ball as a circle and the paddle as a rectangle. In the drawing phase just calculate where the image should be drawn and move it there, the image is not required for collision calculations.

 

There are vector classes in pygame that you can use to simplify the code: pygame.math.Vector2

ಠ_ಠ

Link to comment
Share on other sites

Link to post
Share on other sites

On 9/18/2022 at 5:30 AM, Denz006 said:

can you show me an example of the code?

Represent your paddle by a rectangle then your ball by a point at it's center. Then make a bounding box at least larger than radius of the ball and use a simple detection to check if the point is inside the rectangle then it's in collision. That would be the fastest code execution in that specific case. For irregular shape you need to use vector or other geometric technique.

Link to comment
Share on other sites

Link to post
Share on other sites

do i use the rect function and what do i use for the circle?

Link to comment
Share on other sites

Link to post
Share on other sites

40 minutes ago, Denz006 said:

do i use the rect function and what do i use for the circle?

If you want. I don't remember the classes in Python, i haven't used that old language in over 25-30 years.

 

all you need is 6 values

4 for the paddle

MinX, MaxX, MinY, MaxY

 

2 for the ball

PosX, PosY

 

The logic is as simple as :

 

if ( PosX >= MinX && PosX <= MaxX && PosY >= MinY && PosY <= MaxY)

{

     // object collide

}

 

Link to comment
Share on other sites

Link to post
Share on other sites

@Denz006 So a quick comment on your code

 

you are using like player1(x, y) as a function, but you don't actually use the parameters x or y.  Instead you are using the global variable.

 

Also a fun fact, the way you implemented movement, if you tap down when at the bottom you can clip through the ground.

 

Anyways, onto your issue though.  The trick is at this point don't think about doing physics based on an image.  It complicates things in that then you need to consider physics a bit (like if they import a triangle).  Instead for something like this, I would keep it simple

 

You know the width of the paddle, and the size of the ball.  (Ball is 30 wide, and paddle is 21 wide 142 tall).

Now the collision as the ball comes left is pretty easy.  Just have to factor in the width of the paddle with the ball position...and check the heights.

    #  check x positions first to see if it's in range.
    #  Then check if the top of the ball is above the bottom of paddle
    #  Then check if the bottom of the ball is below the top of the paddle
    #  Finally check that the ball is moving left
    if ball2x < player1x + 21 and (ball2y - 31 > player1y and ball2y < player1y + 142) and ball_speedx < 0:
        ball_speedx *= -1

The above is the primitive, hardcoded way of it.  Not really ideal but you will see the bounce 😉

Player 2 is similar, except you factor in the width of the ball instead of the width of the paddle.   I'll let you try that though.  If you need more guided then just reply with what you tried

3735928559 - Beware of the dead beef

Link to comment
Share on other sites

Link to post
Share on other sites

thanks it works but it does not collide with the top part of the paddle

Link to comment
Share on other sites

Link to post
Share on other sites

That's because you're not checking if the ball intersects with the top of the paddle.

 

Besides checking for the side and top collisions, ideally you would also want to check the corners but that means representing your ball in a more complex way 

 

Here's a tip : https://study.com/skill/learn/determining-if-a-point-lies-inside-outside-or-on-a-circle-given-the-center-point-a-radius-explanation.html

 

See attached picture, and to the right. Save it and open it in MS Paint, zoom it to max and check "Gridlines", makes it easier.

Untitled.png.f743bd43ebc7ca4bd31c36e67307531c.pngIn the picture, if we consider 0,0 top corner of the picture, then the center of the circle is at (21,21) and its radius is 16  - it's a 32x32 pixel circle. 

The green pixel (the top left corner) of the rectangle is at (33, 34)

If the Y of top left corner of the rectangle is between those orange lines (determine those Y1 and Y2 relative to circle center) then you want to check if  that left corner of the rectangle is inside, outside or on the actual circle. 

You can then use the formulas in the link above. 

 

Again, our circle is at (21,21) and radius is 16,  and the green dot is at (33,34)

 

We use formula : (x−h)2+(y−k)2=r2

where h and k are the circle center coordinates :   h = 21, k = 21 , r = 16

So  (x−21)2+(y−21)2=162

 

Now we can put the coordinates of the dot in the formula to see if we're on the circle:

 

(33−21)2+(34−21)2=162

122 + 132 = 162   or 144 + 169 = 256 .. 313 = 256 which is not true, so the (33,34) is NOT on the circle. 

 

Now figure out if it's outside or inside the circle ... Distance = sqrt( (33−21)2+(34−21)2 )  = sqrt (313) =  17.69

 

Because 17.69 is bigger than our radius of 16, we know the green dot is outside the circle 

 

In the picture, (30,34) is basically on the circle (but practically is INSIDE the circle due to pixels being square and not round). 

If you put 30,34 in formula you would have  92 + 132 = 16  so 250 = 256 .. so you can add some tolerance, for example you could say if result is within 245..256, you're already hitting the circle. 

 

For 31,34 (one pixel to the right of the circle), you would have 102 +132 = 269 which is more than 256 so it's outside (correct) and the distance would be sqrt (269 ) = 16.4

So you could probably say if the square root is between 16 and 17, you're just about to collide. 

 

As another example (35,29)  ...  (35-21)+(29-21)2 =16  ..14 + 8 = 16 .. 196+64 = 260  which is bigger than 256, so the point is outside  and distance is sqrt(260) = 16.12, very close to the circle. 

The next pixel over (36,29) would make it 152 + 8= 225+64 = 289  and sqrt(289) = 17 ... 

 

EDIT : You could also just precompute ALL the pixels that are part of the circle ... ex look in the picture above and put in an array all the points on the circle circumference, but make the coordinates relative to the top left corner of the circle, or the center of the ball ... then you'd simply check if the corner of the rectangle has the same coordinates as one of the points in the array of points of the circle (with +1 for x axis) 

You can do this easily because it's a nice simple geometric figure, a circle. You could even store in array just one quarter of the circle, because the circle is symmetric so you can just do  * -1  for x and y axis as needed. 

 

 

 

Untitled.zip

 

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×