乒乓球拍有一些奇怪的错误阻止让玩家得分

Pong paddles have some weird bug preventing from letting a player score

我做了一个乒乓球游戏。现在的问题是,当我移动球拍时,球并没有越过球拍,而是在一些看不见的墙上弹跳。这是我的代码,你自己 运行 你可以看到问题所在(你必须稍微移动一下桨)

# Pong

# Importing libraries
import pygame
import random
import time

# Initializing PyGame
pygame.init()

# Creating a font
font = pygame.font.SysFont(None, 30)

# Set the height and width of the screen
window_width = 700
window_height = 500
size = [window_width, window_height]
game_win = pygame.display.set_mode(size)


# Creating a messaging system
def message(sentence, x, y):
    sentence = font.render(sentence, True, white)
    game_win.blit(sentence, [x, y])


# Creating a color
white = (225, 225, 225)
black = (0, 0, 0)

# Setting up ball
ball_size = 25


class Ball:
    """
    Class to keep track of a ball's location and vector.
    """

    def __init__(self):
        self.x = 0
        self.y = 0
        self.change_x = 0
        self.change_y = 0


def make_ball():
    ball = Ball()
    # Starting position of the ball.
    # Take into account the ball size so we don't spawn on the edge.
    ball.x = 350
    ball.y = 250

    # Speed and direction of rectangle
    ball.change_x = 5
    ball.change_y = 5

    return ball


def main():
    # Scores
    left_score = 0
    right_score = 0

    pygame.init()

    pygame.display.set_caption("Ping Pong")

    # Loop until the user clicks the close button.
    done = False

    # Used to manage how fast the screen updates
    clock = pygame.time.Clock()

    ball_list = []

    ball = make_ball()
    ball_list.append(ball)

    # Right paddle coordinates
    y = 200
    y_change = 0
    x = 50
    # Left paddle coordinates
    y1 = 200
    y1_change = 0
    x1 = 650

    while not done:
        # --- Event Processing
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w:
                    y_change = -5

                elif event.key == pygame.K_s:
                    y_change = 5

                elif event.key == pygame.K_UP:
                    y1_change = -5

                elif event.key == pygame.K_DOWN:
                    y1_change = 5

            elif event.type == pygame.KEYUP:
                y_change = 0
                y1_change = 0

        y += y_change
        y1 += y1_change

        if y > window_height - 100:
            y -= 5
        if y < 50:
            y += 5
        if y1 > window_height - 100:
            y1 -= 5
        if y1 < 50:
            y1 += 5

        message("Left player score: " + str(left_score), 10, 10)
        message("Right player score: " + str(right_score), 490, 10)

        # Drawing a left paddle
        pygame.draw.rect(game_win, white, [x, y, 25, 100])
        # Drawing a right paddle
        pygame.draw.rect(game_win, white, [x1, y1, 25, 100])

        # Updating screen to changes take place
        pygame.display.update()

        # Logic
        for ball in ball_list:
            # Move the ball's center
            ball.x += ball.change_x
            ball.y += ball.change_y

            # Bounce the ball if needed
            if ball.y > 50 - ball_size or ball.y < ball_size:
                ball.change_y *= -1
            if ball.x > window_width - ball_size:
                ball.change_x *= -1
                left_score += 1
            if ball.x < ball_size:
                ball.change_x *= -1
                right_score += 1
            # Here is the part where it all becomes weird and buggy
            if ball.x-ball_size <= x <= ball.x + ball_size:
                ball.change_x *= -1
            if ball.x-ball_size <= x1 <= ball.x + ball_size:
                ball.change_x *= -1
            if ball.y-ball_size <= y <= ball.y + ball_size:
                ball.change_x *= -1
            if ball.y-ball_size <= y1 <= ball.y + ball_size:
                ball.change_x *= -1

            if right_score == 10:
                message('RIGHT PLAYER HAS WON!!', 300, 200)
                time.sleep(10)
                done = True
            elif left_score == 10:
                message("LEFT PLAYER HAS WON!!", 300, 200)
                time.sleep(10)
                done = True

        # Drawing
        # Set the screen background
        game_win.fill(black)

        # Draw the balls
        for ball in ball_list:
            pygame.draw.circle(game_win, white, [ball.x, ball.y], ball_size)

        # Wrap-up
        # Limit to 60 frames per second
        clock.tick(60)

        # Go ahead and update the screen with what we've drawn.
        pygame.display.flip()

    # Close everything down
    pygame.quit()


if __name__ == "__main__":
    main()

当我把球拍移开时,球仍然可以从一些看不见的墙上弹回来。其他的都很好,就是我放# Bounce if needed.

的部分

我建议计算球和球拍的边界矩形,并使用 pygame.Rect and colliderect() 检测球和球拍之间的碰撞。
另见 .

例如:

def main():
    # [...]

    while not done:
        # [...]

        # Logic
        for ball in ball_list:
            # [...]

            ball_rect = pygame.Rect(ball.x-ball_size, ball.y-ball_size, ball_size*2, ball_size*2)
            
            left_paddle_rect = pygame.Rect(x, y, 25, 75)
            if ball.change_x < 0 and ball_rect.colliderect(left_paddle_rect):
                ball.change_x = abs(ball.change_x)
            
            right_paddle_rect = pygame.Rect(x1, y1, 25, 75)
            if ball.change_x > 0 and ball_rect.colliderect(right_paddle_rect):
                ball.change_x = -abs(ball.change_x)

此外,window 的高度是 500 而不是 50_

if ball.y > 50 - ball_size or ball.y < ball_size:

if ball.y > 500 - ball_size or ball.y < ball_size:

我建议分别删除对 pygame.display.flip() 的多次调用 pygame.display.update()。在主应用程序循环结束时只更新一次显示。查看完整示例:

# Importing libraries
import pygame
import random
import time

# Initializing PyGame
pygame.init()

# Creating a font
font = pygame.font.SysFont(None, 30)

# Set the height and width of the screen
window_width = 700
window_height = 500
size = [window_width, window_height]
game_win = pygame.display.set_mode(size)


# Creating a messaging system
def message(sentence, x, y):
    sentence = font.render(sentence, True, white)
    game_win.blit(sentence, [x, y])


# Creating a color
white = (225, 225, 225)
black = (0, 0, 0)

# Setting up ball
ball_size = 25


class Ball:
    """
    Class to keep track of a ball's location and vector.
    """

    def __init__(self):
        self.x = 0
        self.y = 0
        self.change_x = 0
        self.change_y = 0


def make_ball():
    ball = Ball()
    # Starting position of the ball.
    # Take into account the ball size so we don't spawn on the edge.
    ball.x = 350
    ball.y = 250

    # Speed and direction of rectangle
    ball.change_x = 5
    ball.change_y = 5

    return ball


def main():
    # Scores
    left_score = 0
    right_score = 0

    pygame.init()

    pygame.display.set_caption("Ping Pong")

    # Loop until the user clicks the close button.
    done = False

    # Used to manage how fast the screen updates
    clock = pygame.time.Clock()

    ball_list = []

    ball = make_ball()
    ball_list.append(ball)

    # Right paddle coordinates
    y = 200
    y_change = 0
    x = 50
    # Left paddle coordinates
    y1 = 200
    y1_change = 0
    x1 = 650

    while not done:
        # --- Event Processing
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w:
                    y_change = -5

                elif event.key == pygame.K_s:
                    y_change = 5

                elif event.key == pygame.K_UP:
                    y1_change = -5

                elif event.key == pygame.K_DOWN:
                    y1_change = 5

            elif event.type == pygame.KEYUP:
                y_change = 0
                y1_change = 0

        y += y_change
        y1 += y1_change

        if y > window_height - 100:
            y -= 5
        if y < 50:
            y += 5
        if y1 > window_height - 100:
            y1 -= 5
        if y1 < 50:
            y1 += 5

        message("Left player score: " + str(left_score), 10, 10)
        message("Right player score: " + str(right_score), 490, 10)


        # Logic
        for ball in ball_list:
            # Move the ball's center
            ball.x += ball.change_x
            ball.y += ball.change_y

            # Bounce the ball if needed
            if ball.y > 500 - ball_size or ball.y < ball_size:
                ball.change_y *= -1
            if ball.x > window_width - ball_size:
                ball.change_x *= -1
                left_score += 1
            if ball.x < ball_size:
                ball.change_x *= -1
                right_score += 1
            
            # Here is the part where it all becomes weird and buggy
            ball_rect = pygame.Rect(ball.x-ball_size, ball.y-ball_size, ball_size*2, ball_size*2)
            
            left_paddle_rect = pygame.Rect(x, y, 25, 75)
            if ball.change_x < 0 and ball_rect.colliderect(left_paddle_rect):
                ball.change_x = abs(ball.change_x)
            
            right_paddle_rect = pygame.Rect(x1, y1, 25, 75)
            if ball.change_x > 0 and ball_rect.colliderect(right_paddle_rect):
                ball.change_x = -abs(ball.change_x)

            if right_score == 10:
                message('RIGHT PLAYER HAS WON!!', 300, 200)
                time.sleep(10)
                done = True
            elif left_score == 10:
                message("LEFT PLAYER HAS WON!!", 300, 200)
                time.sleep(10)
                done = True

        # Drawing
        # Set the screen background
        game_win.fill(black)

        # Drawing a left paddle
        pygame.draw.rect(game_win, white, [x, y, 25, 100])
        # Drawing a right paddle
        pygame.draw.rect(game_win, white, [x1, y1, 25, 100])

        # Draw the balls
        for ball in ball_list:
            pygame.draw.circle(game_win, white, [ball.x, ball.y], ball_size)

        # Go ahead and update the screen with what we've drawn.
        pygame.display.flip()

        # Wrap-up
        # Limit to 60 frames per second
        clock.tick(60)

    # Close everything down
    pygame.quit()


if __name__ == "__main__":
    main()