使用 Pygame 实现经典 Pong 游戏
【摘要】 Pong 是电子游戏历史上的一款经典之作:两个挡板、一只小球、简单的反弹逻辑,却引爆了早期的家用电视游戏市场。玩家各自控制一根挡板来击球,不让小球穿过自己的防线,先失误者输。本篇示例将使用 Python + Pygame 来简单复刻 Pong 游戏的核心玩法,并适当加以改进或美化,帮助初学者快速入门 2D 游戏开发。
1. 前言
Pong 是电子游戏历史上的一款经典之作:两个挡板、一只小球、简单的反弹逻辑,却引爆了早期的家用电视游戏市场。玩家各自控制一根挡板来击球,不让小球穿过自己的防线,先失误者输。本篇示例将使用 Python + Pygame 来简单复刻 Pong 游戏的核心玩法,并适当加以改进或美化,帮助初学者快速入门 2D 游戏开发。
2. 环境准备
- Python 3.x
- Pygame:可通过
pip install pygame
安装。 - 桌面环境:Windows、macOS 或大多数 Linux 均可。
测试 import pygame
没有报错即可开始。
3. 游戏设计思路
-
游戏对象
- 左挡板(Player A)和右挡板(Player B),玩家或 AI 分别控制。
- 小球在屏幕中移动,与边界或挡板碰撞后反弹。
-
移动与控制
- 双人对战:
- 左挡板用 W/S 控制上/下;
- 右挡板用 ↑/↓ 控制上/下。
- 单人模式:
- 由玩家控制一边挡板,另一边为简单 AI 或保持不动。
- 双人对战:
-
碰撞检测
- 当球与挡板矩形重叠时,球的水平速度反转,同时可在碰撞瞬间增加一些竖直速度变化。
- 当球与上下边界碰撞时,垂直速度反转。
-
得分与重置
- 如果球飞出屏幕左边或右边,表示玩家失分,对方加 1 分;
- 重置球到屏幕中央,方向可随机或默认给分者发球。
-
游戏结束
- 可以设置一个上限分数(如 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()
核心逻辑解析
-
Paddle(挡板)
- 封装为一个类,包含位置 (
x
,y
)、宽高、移动速度等信息; move_up()
和move_down()
方法允许挡板进行上下移动,并在到达边界时进行限制。
- 封装为一个类,包含位置 (
-
Ball(球)
- 初始化时,将水平 (
speed_x
) 和垂直 (speed_y
) 速度加上随机正负号; update()
方法每帧调用:移动球,检查与上下边界、左右挡板的碰撞,并返回球是否飞出屏幕左侧或右侧(-1 或 1)以便计分。reset_position()
在失分时将球重置到屏幕中央,并再次随机发球方向。
- 初始化时,将水平 (
-
游戏循环
paddle_left
用 W/S,paddle_right
用 ↑/↓ 控制上下移动。- 每帧根据
ball.update(...)
返回的结果增减分数并重置球。 - 当分数达到 5 分时,游戏结束,停止更新球,但仍保持在循环中以显示“Game Over”提示。
- 用户点击关闭窗口按钮即可退出。
5. 运行效果
6. 总结
通过本篇博客,你已经学会了如何使用 Pygame 编写一个基础版的 Pong 游戏。该示例涵盖碰撞检测、得分与重置、对象封装等常见 2D 游戏编程中的核心逻辑。在此基础上,你可以根据自己的创意或需求,轻松添加更多机制或美化细节。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)