乒乓球与垫的侧面发生碰撞



我正在尝试在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中进行编程。

您必须在两个步骤上拆分移动和Chek碰撞。仅在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()

最新更新