Ping Pong Pygame与垫的侧面相撞

时间:2017-12-21 13:11:27

标签: python pygame collision-detection collision

我正在尝试在python中编写一个乒乓球比赛,我能够让球从球垫侧面反弹。但是,我无法让球从垫的顶部和底部反弹。我目前只做左边的垫(pad1)。这是我的代码:

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

width, height = 1200, 675

screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
clock = pygame.time.Clock()


FPS = 120

xmb1 = False
xmf1 = False
ymb1 = False
ymf1 = False

xmb2 = False
xmf2 = False
ymb2 = False
ymf2 = False

squareh = 275
squarew = 35
squares = 3

x1 = 100
y1 = (height / 2) - (squareh / 2)

x2 = width - 100 - squarew
y2 = (height / 2) - (squareh / 2)

BLACK = (0,0,0)
WHITE = (255,255,255)

font = pygame.font.SysFont("arial", 30)

text = font.render("Press Space to start", True, WHITE)
text3 = font.render("3", True, WHITE)
text2 = font.render("2", True, WHITE)
text1 = font.render("1", True, WHITE)
startt = font.render("Start!", True, WHITE)

text3b = False
text2b = False
text1b = False
starttb = False

start = False
startballmove = False

bx = width / 2
by = height / 2
br = 40
bms = 6
bxm = random.randint(-bms, bms)
bym = random.randint(-bms, bms)

btc = by
blc = bx
bbc = by + br + br
brc = bx + br + br

circle=pygame.Surface((br * 2, br  * 2))
circle.fill((0, 0, 0))
pygame.draw.circle(circle, WHITE , (br, br), br, 0)
circle.set_colorkey((0, 0, 0))

pad1 = pygame.Rect(x1, y1, squarew, squareh)
pad2 = pygame.Rect(x2, y2, squarew, squareh)

while 1:
    if start and not text1b and not text2b and not text3b and not starttb and not startballmove:
        text3b = True
        pygame.time.set_timer(pygame.USEREVENT, 1000)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.display.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            # pad 2 check if key is down
            if event.key == pygame.K_UP:
                ymb2 = True
            if event.key == pygame.K_DOWN:
                ymf2 = True
            # pad 1 check if key is down
            if event.key == pygame.K_w:
                ymb1 = True
            if event.key == pygame.K_s:
                ymf1 = True
            if event.key == pygame.K_SPACE:
                start = True
        elif event.type == pygame.KEYUP:
            #pad 2 check if key goes up
            if event.key == pygame.K_UP:
                ymb2 = False
            if event.key == pygame.K_DOWN:
                ymf2 = False
            # pad 1 check if key goes up
            if event.key == pygame.K_w:
                ymb1 = False
            if event.key == pygame.K_s:
                ymf1 = False
        # check if window has been resized
        if event.type == pygame.VIDEORESIZE:
            width = event.dict['size'][0]
            height = event.dict['size'][1]
            screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
        if event.type == pygame.USEREVENT:
            # check if start should be hidden
            if starttb:
                starttb = False
                startballmove = True
            # check if start should be showed
            if text1b and not text2b and not text3b:
                text1b = False
                text2b = False
                text3b = False
                starttb = True
            # check if 1 should be showed
            if text2b and not text3b and not text1b:
                text3b = False
                text2b = False
                text1b = True
            # check if 2 should be showed
            if text3b and not text2b and not text1b:
                text3b = False
                text2b = True
                text1b = False

    # check if pad 1 is out of bounds and move it      
    if ymb1 and not (y1 <= 0): y1 -= squares
    if ymf1 and not (y1 + squareh >= height): y1 += squares
    if y1 > (height - squareh) + 1: y1 -= squares

    # check if pad 2 is out of bounds and move it      
    if ymb2 and not (y2 <= 0): y2 -= squares
    if ymf2 and not (y2 + squareh >= height): y2 += squares
    if y2 > (height - squareh) + 1: y2 -= squares

    # put pads in center if game has not started
    if not start:
        # pad 1
        x1 = 75
        y1 = (height / 2) - (squareh / 2)
        # pad 2
        x2 = width - 75 - squarew
        y2 = (height / 2) - (squareh / 2)
        #ball
        bx = width / 2 - br
        by = height / 2 - br

    # put pads in center in x if game has started
    else:
        # pad 1
        x1 = 75
        # pad 2
        x2 = width - 75 - squarew
    # if ball has not started moving center it
    if not startballmove:
        bx = width / 2 - br
        by = height / 2 - br
    # check if movement variables are 0
    while bxm == 0 or bym == 0:
        if bxm == 0:
            bxm = random.randint(-6, 6)
        if bym == 0:
            bym = random.randint(-6, 6)

    screen.fill(BLACK)
    # draw starting text if game has not started
    if not start:
        screen.blit(text,((width / 2) - text.get_width() // 2, (height / 4) - text.get_height() // 2))
    # put 3 on screen
    if start and text3b:
        screen.blit(text3,((width / 2) - 15, (height / 4) - (text.get_height() / 2)))
    # put 2 on screen
    if start and text2b:
        screen.blit(text2,((width / 2) - 15, (height / 4) - (text.get_height() / 2)))   
    # put 1 on screen
    if start and text1b:
        screen.blit(text1,((width / 2) - 15, (height / 4) - (text.get_height() / 2)))
    # put start on screen
    if start and starttb:
        screen.blit(startt,((width / 2) - (text.get_width() / 8), (height / 4) - (text.get_height() / 2)))   
    # check if ball is out of bounds
    btc = by
    blc = bx
    bbc = by + br + br
    brc = bx + br + br
    if start and startballmove:
        # screen
        if btc <= 0:
            bym = bym * -1
            print("top side")
        if bbc >= height:
            bym = bym * -1
            print("bottom side")
        if blc <= 0:
            bxm = bxm * -1
            print("left side")
        if brc >= width:
            bxm = bxm * -1
            print("right side")
        # left pad
        pad1 = pygame.Rect(x1, y1, squarew, squareh)
        if pad1.collidepoint(int(bx), int(by)):
            bxm = bxm * -1
            bx += abs(bxm)
            print("Collision")
    # move ball
    if start and startballmove:
        bx += bxm
        by += bym
    # draw circle if game start
    if start:
        screen.blit(circle, (int(bx), int(by)))  
    # draw pad 1
    pad1 = pygame.Rect(x1, y1, squarew, squareh)
    pygame.draw.rect(screen, WHITE, pad1, 0)
    # draw pad 2
    pad2 = pygame.Rect(x2, y2, squarew, squareh)
    pygame.draw.rect(screen, WHITE, pad2, 0)

    pygame.display.flip()
    clock.tick(FPS)

有谁知道怎么做?我最近才学会用python和pygame编程。

1 个答案:

答案 0 :(得分:2)

你必须在两个步骤上分开移动和cheking碰撞。首先仅在X中移动然后您可以识别前方碰撞。后来在Y中移动,你可以认识到侧面碰撞。

您的代码非常混乱,因此可能需要进行大量更改。您应该组织代码并为变量使用更好的名称,以使其更具可读性。

你可以使用elif和嵌套if,这样它会更干净。

import sys
import pygame
import random
import math

# --- constants --- (UPPER_CASE_NAMES)

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

FPS = 60

SQUARE_HEIGHT = 275
SQUARE_WIDTH  = 35
SQUARE_SPEED  = 3

BALL_R = 40

# --- main ---

window_width = 1200
window_height = 675

# - init -

pygame.init()

screen = pygame.display.set_mode((window_width, window_height), pygame.RESIZABLE)
screen_rect = screen.get_rect()

# - text -

font = pygame.font.SysFont("arial", 30)

# - text - press space -

text_press_space = font.render("Press Space to start", True, WHITE)
text_press_space_rect = text_press_space.get_rect()
text_press_space_rect.centerx = screen_rect.centerx
text_press_space_rect.centery = screen_rect.height // 4

# - text - count down -

text_1 = font.render("1", True, WHITE)
text_1_rect = text_1.get_rect()
text_1_rect.centerx = screen_rect.centerx
text_1_rect.centery = screen_rect.height // 4 


text_2 = font.render("2", True, WHITE)
text_2_rect = text_2.get_rect()
text_2_rect.centerx = screen_rect.centerx
text_2_rect.centery = screen_rect.height // 4 

text_3 = font.render("3", True, WHITE)
text_3_rect = text_3.get_rect()
text_3_rect.centerx = screen_rect.centerx
text_3_rect.centery = screen_rect.height // 4 

text_start = font.render("Start!", True, WHITE)
text_start_rect = text_start.get_rect()
text_start_rect.centerx = screen_rect.centerx
text_start_rect.centery = screen_rect.height // 4 

display_text_3 = False
display_text_2 = False
display_text_1 = False
display_text_start = False

# - ball -

ball = pygame.Surface((BALL_R * 2, BALL_R  * 2))
# circle.fill(BLACK) # not need it because surface is black as default
ball.set_colorkey(BLACK)
pygame.draw.circle(ball, WHITE , (BALL_R, BALL_R), BALL_R, 0)
ball_rect = ball.get_rect()
ball_rect.center = screen_rect.center

ball_speed = 6

ball_speed_x = ball_speed * random.choice([1, -1])
ball_speed_y = ball_speed * random.choice([1, -1])

ball_move = False

# - pads -

pad1_rect = pygame.Rect(0, 0, SQUARE_WIDTH, SQUARE_HEIGHT)
pad1_rect.left = 100
pad1_rect.centery = screen_rect.centery
pad1_move_up = False
pad1_move_down = False

pad2_rect = pygame.Rect(0, 0, SQUARE_WIDTH, SQUARE_HEIGHT)
pad2_rect.right = screen_rect.right - 100
pad2_rect.centery = screen_rect.centery
pad2_move_up = False
pad2_move_down = False

# --- mainloop ---

play_start = False

clock = pygame.time.Clock()

while True:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            # pad 2 check if key is down
            if event.key == pygame.K_UP:
                pad2_move_up = True
            elif event.key == pygame.K_DOWN:
                pad2_move_down = True
            # pad 1 check if key is down
            elif event.key == pygame.K_w:
                pad1_move_up = True
            elif event.key == pygame.K_s:
                pad1_move_down = True

            elif event.key == pygame.K_SPACE:
                if not play_start:
                    play_start = True
                    pygame.time.set_timer(pygame.USEREVENT, 1000)
                    display_text_3 = True

        elif event.type == pygame.KEYUP:
            #pad 2 check if key goes up
            if event.key == pygame.K_UP:
                pad2_move_up = False
            elif event.key == pygame.K_DOWN:
                pad2_move_down = False
            # pad 1 check if key goes up
            elif event.key == pygame.K_w:
                pad1_move_up = False
            elif event.key == pygame.K_s:
                pad1_move_down = False

        # check if window has been resized
        if event.type == pygame.VIDEORESIZE:
            window_width = event.dict['size'][0]
            window_height = event.dict['size'][1]
            screen = pygame.display.set_mode((window_width, window_height), pygame.RESIZABLE)
            screen_rect = screen.get_rect()

        if event.type == pygame.USEREVENT:
            if display_text_3:
                display_text_3 = False
                display_text_2 = True
            elif display_text_2:
                display_text_2 = False
                display_text_1 = True
            elif display_text_1:
                display_text_1 = False
                display_text_start = True
            elif display_text_start:
                display_text_start = False
                ball_move = True

    # - moves (without draws) -

    # move paddle 1

    if pad1_move_up and pad1_rect.top > 0: # > screen_rect.top:
        pad1_rect.y -= SQUARE_SPEED
        if pad1_rect.top < 0:
            pad1_rect.top = 0

    if pad1_move_down and pad1_rect.bottom < screen_rect.bottom:
        pad1_rect.y += SQUARE_SPEED
        if pad1_rect.bottom > screen_rect.bottom:
            pad1_rect.bottom =  screen_rect.bottom

    # move paddle 2

    if pad2_move_up and pad2_rect.top > 0: # > screen_rect.top:
        pad2_rect.y -= SQUARE_SPEED
        if pad2_rect.top < 0:
            pad2_rect.top = 0

    if pad2_move_down and pad2_rect.bottom < screen_rect.bottom:
        pad2_rect.y += SQUARE_SPEED
        if pad2_rect.bottom > screen_rect.bottom:
            pad2_rect.bottom =  screen_rect.bottom

    # check if ball is out of bounds
    if play_start:

        # move ball
        if ball_move:
            ball_rect.x += ball_speed_x

            # check FRONT collision with pads

            if pad1_rect.colliderect(ball_rect):
                #if 
                ball_rect.left = pad1_rect.right 
                ball_speed_x = -ball_speed_x 
                print("Front collision right pad")

            if pad2_rect.colliderect(ball_rect):
                ball_rect.right = pad2_rect.left
                ball_speed_x = -ball_speed_x 
                print("Front collision left pad")

            ball_rect.y += ball_speed_y

            # check SIDE collision with pads

            if pad1_rect.colliderect(ball_rect):
                # move from top
                if ball_speed_y > 0:
                    ball_rect.bottom = pad1_rect.top
                    print("Top collision right pad")

                # move from bottom
                else: # elif ball_speed_y < 0:
                    ball_rect.top = pad1_rect.bottom
                    print("Bottom collision right pad")
                # change both or only Y (depends on what effect you need)
                ball_speed_x = -ball_speed_x
                ball_speed_y = -ball_speed_y

            if pad2_rect.colliderect(ball_rect):
                # move from top
                if ball_speed_y > 0:
                    ball_rect.bottom = pad2_rect.top
                    print("Top collision left pad")

                # move from bottom
                else: # if ball_speed_y < 0:
                    ball_rect.top = pad2_rect.bottom
                    print("Bottom collision left pad")
                # change both or only Y (depends on what effect you need)
                ball_speed_x = -ball_speed_x
                ball_speed_y = -ball_speed_y

            # check collision with border

            if ball_rect.left <= 0: # <= screen_rect.left:
                ball_speed_x = -ball_speed_x 
                print("left side")
                print("point for left player")
                # move ball to center 
                ball_rect.center = screen_rect.center
                ball_speed_x = ball_speed * random.choice([1, -1])
                ball_speed_y = ball_speed * random.choice([1, -1])
            if ball_rect.right >= screen_rect.right:
                ball_speed_x = -ball_speed_x 
                print("right side")
                print("point for right player")
                # move ball to center 
                ball_rect.center = screen_rect.center
                ball_speed_x = ball_speed * random.choice([1, -1])
                ball_speed_y = ball_speed * random.choice([1, -1])


            if ball_rect.top <= 0: # <= screen_rect.top:
                ball_speed_y = -ball_speed_y
                print("top side")
            if ball_rect.bottom >= screen_rect.bottom:
                ball_speed_y = -ball_speed_y
                print("bottom side")


    # - draws (without moves) -

    screen.fill(BLACK)

    if not play_start:
        screen.blit(text_press_space, text_press_space_rect)
    else: # if play_start:
        if display_text_3:
            screen.blit(text_3, text_3_rect)
        if display_text_2:
            screen.blit(text_2, text_2_rect)   
        if display_text_1:
            screen.blit(text_1, text_1_rect)
        if display_text_start:
            screen.blit(text_start, text_start_rect)

        screen.blit(ball, ball_rect)  

    # draw pads
    pygame.draw.rect(screen, WHITE, pad1_rect, 0)
    pygame.draw.rect(screen, WHITE, pad2_rect, 0)

    pygame.display.flip()

    clock.tick(FPS)

# --- end ---

pygame.quit()