使用 Pygame 实现经典 Pong 游戏

举报
Damon小智 发表于 2025/01/31 14:25:20 2025/01/31
【摘要】 Pong 是电子游戏历史上的一款经典之作:两个挡板、一只小球、简单的反弹逻辑,却引爆了早期的家用电视游戏市场。玩家各自控制一根挡板来击球,不让小球穿过自己的防线,先失误者输。本篇示例将使用 Python + Pygame 来简单复刻 Pong 游戏的核心玩法,并适当加以改进或美化,帮助初学者快速入门 2D 游戏开发。

1. 前言

Pong 是电子游戏历史上的一款经典之作:两个挡板、一只小球、简单的反弹逻辑,却引爆了早期的家用电视游戏市场。玩家各自控制一根挡板来击球,不让小球穿过自己的防线,先失误者输。本篇示例将使用 Python + Pygame 来简单复刻 Pong 游戏的核心玩法,并适当加以改进或美化,帮助初学者快速入门 2D 游戏开发。


2. 环境准备

  1. Python 3.x
  2. Pygame:可通过 pip install pygame 安装。
  3. 桌面环境:Windows、macOS 或大多数 Linux 均可。

测试 import pygame 没有报错即可开始。


3. 游戏设计思路

  1. 游戏对象

    • 左挡板(Player A)和右挡板(Player B),玩家或 AI 分别控制。
    • 小球在屏幕中移动,与边界或挡板碰撞后反弹。
  2. 移动与控制

    • 双人对战:
      • 左挡板用 W/S 控制上/下;
      • 右挡板用 ↑/↓ 控制上/下。
    • 单人模式:
      • 由玩家控制一边挡板,另一边为简单 AI 或保持不动。
  3. 碰撞检测

    • 当球与挡板矩形重叠时,球的水平速度反转,同时可在碰撞瞬间增加一些竖直速度变化。
    • 当球与上下边界碰撞时,垂直速度反转。
  4. 得分与重置

    • 如果球飞出屏幕左边或右边,表示玩家失分,对方加 1 分;
    • 重置球到屏幕中央,方向可随机或默认给分者发球。
  5. 游戏结束

    • 可以设置一个上限分数(如 5 分或 10 分),先到者获胜。
    • 或持续进行,看谁先中途退出。

4. 完整示例代码

将以下内容保存为 pong_game.py 并运行,即可体验一个基础版本的 Pong 游戏。你可以随时修改画面尺寸、速度、AI 等逻辑。

import pygame
import sys
import random

# 初始化 Pygame
pygame.init()

# ---------------------
# 全局配置
# ---------------------
WIDTH, HEIGHT = 800, 500
FPS = 60

# 颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# 窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pong - Pygame 示例")
clock = pygame.time.Clock()

# 字体
font = pygame.font.SysFont("arial", 36)

# ---------------------
# 挡板类
# ---------------------
class Paddle:
    def __init__(self, x, y, width=20, height=100, speed=7):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.speed = speed

    def draw(self, surface):
        pygame.draw.rect(surface, WHITE, (self.x, self.y, self.width, self.height))

    def move_up(self):
        self.y -= self.speed
        if self.y < 0:
            self.y = 0

    def move_down(self):
        self.y += self.speed
        if self.y + self.height > HEIGHT:
            self.y = HEIGHT - self.height

    def get_rect(self):
        return pygame.Rect(self.x, self.y, self.width, self.height)

# ---------------------
# 球类
# ---------------------
class Ball:
    def __init__(self, x, y, radius=10, speed_x=5, speed_y=5):
        self.x = x
        self.y = y
        self.radius = radius
        # 初始水平速度和垂直速度
        self.speed_x = speed_x * random.choice([-1, 1])
        self.speed_y = speed_y * random.choice([-1, 1])

    def draw(self, surface):
        pygame.draw.circle(surface, WHITE, (int(self.x), int(self.y)), self.radius)

    def update(self, paddle_left, paddle_right):
        """
        更新球的位置、检查与上下边界/挡板/左右边界的碰撞。
        返回: -1 表示飞出左侧, +1 表示飞出右侧, 0 表示正常继续
        """
        self.x += self.speed_x
        self.y += self.speed_y

        # 碰撞上下边界
        if self.y - self.radius < 0:
            self.y = self.radius
            self.speed_y = -self.speed_y
        elif self.y + self.radius > HEIGHT:
            self.y = HEIGHT - self.radius
            self.speed_y = -self.speed_y

        # 碰撞左挡板
        if pygame.Rect(paddle_left.x, paddle_left.y, paddle_left.width, paddle_left.height).collidepoint(self.x - self.radius, self.y):
            self.speed_x = -self.speed_x
            # 可以根据碰撞位置微调 self.speed_y
            # 使得球的反弹更灵活
        # 碰撞右挡板
        if pygame.Rect(paddle_right.x, paddle_right.y, paddle_right.width, paddle_right.height).collidepoint(self.x + self.radius, self.y):
            self.speed_x = -self.speed_x

        # 检查是否飞出左右边界
        if self.x < 0:
            return -1  # 飞出左侧
        elif self.x > WIDTH:
            return 1   # 飞出右侧

        return 0

    def reset_position(self, x, y):
        """将球重置到初始位置,并随机发球方向。"""
        self.x = x
        self.y = y
        self.speed_x *= random.choice([-1, 1])
        self.speed_y *= random.choice([-1, 1])

# ---------------------
# 主函数
# ---------------------
def main():
    # 创建两个挡板和一个球
    paddle_left = Paddle(x=30, y=(HEIGHT // 2 - 50))
    paddle_right = Paddle(x=(WIDTH - 50), y=(HEIGHT // 2 - 50))
    ball = Ball(x=WIDTH // 2, y=HEIGHT // 2)

    score_left = 0
    score_right = 0
    game_over = False

    while True:
        clock.tick(FPS)

        # 1) 事件处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        # 如果游戏没有结束才更新
        if not game_over:
            # 2) 键盘输入
            keys = pygame.key.get_pressed()
            if keys[pygame.K_w]:
                paddle_left.move_up()
            if keys[pygame.K_s]:
                paddle_left.move_down()
            if keys[pygame.K_UP]:
                paddle_right.move_up()
            if keys[pygame.K_DOWN]:
                paddle_right.move_down()

            # 3) 更新球位置
            result = ball.update(paddle_left, paddle_right)
            if result == -1:
                score_right += 1
                ball.reset_position(WIDTH // 2, HEIGHT // 2)
            elif result == 1:
                score_left += 1
                ball.reset_position(WIDTH // 2, HEIGHT // 2)

            # 检测是否结束(可设置上限或一直玩)
            if score_left >= 5 or score_right >= 5:
                game_over = True

        # 4) 绘制
        screen.fill(BLACK)

        # 显示挡板和球
        paddle_left.draw(screen)
        paddle_right.draw(screen)
        ball.draw(screen)

        # 显示得分
        score_text = font.render(f"{score_left} : {score_right}", True, WHITE)
        screen.blit(score_text, (WIDTH // 2 - 20, 20))

        # 如果游戏结束,显示提示
        if game_over:
            msg = "Game Over! " + ("Left Wins" if score_left >= 5 else "Right Wins")
            label = font.render(msg, True, WHITE)
            screen.blit(label, (WIDTH // 2 - 100, HEIGHT // 2 - 20))

        pygame.display.flip()

if __name__ == "__main__":
    main()

核心逻辑解析

  1. Paddle(挡板)

    • 封装为一个类,包含位置 (x, y)、宽高、移动速度等信息;
    • move_up()move_down() 方法允许挡板进行上下移动,并在到达边界时进行限制。
  2. Ball(球)

    • 初始化时,将水平 (speed_x) 和垂直 (speed_y) 速度加上随机正负号;
    • update() 方法每帧调用:移动球,检查与上下边界、左右挡板的碰撞,并返回球是否飞出屏幕左侧或右侧(-1 或 1)以便计分。
    • reset_position() 在失分时将球重置到屏幕中央,并再次随机发球方向。
  3. 游戏循环

    • paddle_leftW/Spaddle_right↑/↓ 控制上下移动。
    • 每帧根据 ball.update(...) 返回的结果增减分数并重置球。
    • 当分数达到 5 分时,游戏结束,停止更新球,但仍保持在循环中以显示“Game Over”提示。
    • 用户点击关闭窗口按钮即可退出。

5. 运行效果

image.png


6. 总结

通过本篇博客,你已经学会了如何使用 Pygame 编写一个基础版的 Pong 游戏。该示例涵盖碰撞检测得分与重置对象封装等常见 2D 游戏编程中的核心逻辑。在此基础上,你可以根据自己的创意或需求,轻松添加更多机制或美化细节。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。