使用Pygame制作“打砖块”游戏
1. 前言
打砖块(Breakout / Arkanoid) 是一款经典街机游戏,玩家控制一个可左右移动的挡板,接住并反弹球,击碎屏幕上方的砖块。随着砖块被击碎,不仅能获得分数,还可以体验到不断加速或复杂的反弹乐趣。 在本篇文章里,我们将使用 Python 3.x + Pygame 库,手把手实现一个简易版本的打砖块游戏,包含最核心的移动、碰撞和得分功能。
2. 开发环境与准备
- Python 3.x
- Pygame:若尚未安装,可通过命令
pip install pygame
进行安装。 - 桌面系统:Windows、macOS 或绝大多数 Linux 桌面环境都能正常使用 Pygame。
安装完成后,使用 import pygame
测试是否成功即可。
3. 游戏思路
要完成一个打砖块游戏,需要实现以下几个关键模块:
-
挡板(Paddle)
- 位于屏幕底部,可左右移动。
- 通过键盘或鼠标控制位置。
-
球(Ball)
- 从挡板上方出发,向上运动;
- 在碰到墙壁时发生反弹;
- 在碰到挡板或砖块时,需要计算反弹方向,并可能击碎砖块、加分。
-
砖块(Bricks)
- 通常在屏幕上方排列成若干行;
- 一旦被球击中,会被击碎并增加分数;
- 也可以设定一些特殊砖块,击中后会产生道具等(此处仅做简易实现)。
-
游戏结束
- 若球掉出屏幕底部则表示丢失一条命,或者直接游戏结束;
- 如果所有砖块都被击碎,则玩家胜利。
4. 完整示例代码
将以下示例保存为 breakout_game.py
并运行,即可体验一个最基本的打砖块游戏。你也可以根据需求自由添加更多功能或美化界面。
import pygame
import sys
import random
# 初始化 Pygame
pygame.init()
# ----------------------
# 全局配置
# ----------------------
WIDTH, HEIGHT = 600, 600 # 游戏窗口大小
FPS = 60 # 帧率
# 颜色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (100, 100, 100)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# 游戏窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("打砖块 - Pygame 示例")
clock = pygame.time.Clock()
# 字体
font = pygame.font.SysFont("arial", 24)
# ----------------------
# 挡板类
# ----------------------
class Paddle:
def __init__(self):
self.width = 100
self.height = 15
self.x = (WIDTH - self.width) // 2
self.y = HEIGHT - 50
self.speed = 8
def draw(self, surface):
pygame.draw.rect(surface, BLUE, (self.x, self.y, self.width, self.height))
def move_left(self):
self.x -= self.speed
if self.x < 0:
self.x = 0
def move_right(self):
self.x += self.speed
if self.x + self.width > WIDTH:
self.x = WIDTH - self.width
# ----------------------
# 球类
# ----------------------
class Ball:
def __init__(self, paddle):
self.radius = 8
self.x = paddle.x + paddle.width // 2
self.y = paddle.y - 10
# 球初始速度
self.speed_x = random.choice([-4, 4])
self.speed_y = -4
def draw(self, surface):
pygame.draw.circle(surface, RED, (int(self.x), int(self.y)), self.radius)
def update(self, paddle, bricks):
"""
更新球的位置、检查墙体碰撞、挡板碰撞和砖块碰撞
"""
self.x += self.speed_x
self.y += self.speed_y
# 碰撞左右墙
if self.x - self.radius < 0:
self.x = self.radius
self.speed_x = -self.speed_x
elif self.x + self.radius > WIDTH:
self.x = WIDTH - self.radius
self.speed_x = -self.speed_x
# 碰撞上墙
if self.y - self.radius < 0:
self.y = self.radius
self.speed_y = -self.speed_y
# 掉到底部 -> 游戏结束的处理可在主循环中判断
# if self.y + self.radius > HEIGHT:
# pass
# 碰撞挡板
if (self.x > paddle.x and self.x < paddle.x + paddle.width
and self.y + self.radius > paddle.y
and self.y - self.radius < paddle.y + paddle.height):
self.speed_y = -self.speed_y
# 球可能根据撞击位置微调水平速度(可选)
# self.speed_x += random.choice([-1, 0, 1])
# 碰撞砖块
for brick in bricks[:]:
if (self.x + self.radius > brick.x
and self.x - self.radius < brick.x + brick.width
and self.y + self.radius > brick.y
and self.y - self.radius < brick.y + brick.height):
bricks.remove(brick)
self.speed_y = -self.speed_y # 简化反弹,只改变垂直方向
return 10 # 得分10
return 0
# ----------------------
# 砖块类
# ----------------------
class Brick:
def __init__(self, x, y, width, height, color=GREEN):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
def draw(self, surface):
pygame.draw.rect(surface, self.color, (self.x, self.y, self.width, self.height))
pygame.draw.rect(surface, BLACK, (self.x, self.y, self.width, self.height), 1) # 边框
def create_bricks(rows=5, cols=8):
"""
创建指定行列的砖块,返回列表
"""
bricks = []
brick_width = (WIDTH - 40) // cols
brick_height = 20
x_offset = 20
y_offset = 40
for row in range(rows):
for col in range(cols):
x = x_offset + col * brick_width
y = y_offset + row * brick_height
color = random.choice([GREEN, YELLOW, GRAY, BLUE])
brick = Brick(x, y, brick_width, brick_height, color)
bricks.append(brick)
return bricks
# ----------------------
# 主函数
# ----------------------
def main():
paddle = Paddle()
ball = Ball(paddle)
bricks = create_bricks(rows=5, cols=8)
score = 0
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 键盘输入
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
paddle.move_left()
if keys[pygame.K_RIGHT]:
paddle.move_right()
# 更新球的位置
gained_score = ball.update(paddle, bricks)
score += gained_score
# 判断游戏结束:如果球掉到底部 or 砖块全部消失
if ball.y - ball.radius > HEIGHT:
# 球掉出底部
running = False
if len(bricks) == 0:
# 所有砖块被击破
running = False
# 绘制
screen.fill(BLACK)
# 画砖块
for brick in bricks:
brick.draw(screen)
# 画挡板和球
paddle.draw(screen)
ball.draw(screen)
# 显示分数
text_surface = font.render(f"Score: {score}", True, WHITE)
screen.blit(text_surface, (10, 10))
pygame.display.flip()
# 游戏结束后显示结果
game_over(score)
def game_over(score):
"""游戏结束界面"""
screen.fill(GRAY)
msg = f"Game Over! Your Score: {score}"
label = font.render(msg, True, BLACK)
# 居中显示
rect = label.get_rect(center=(WIDTH // 2, HEIGHT // 2))
screen.blit(label, rect)
pygame.display.flip()
pygame.time.wait(3000)
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
核心逻辑解读
-
Paddle(挡板)
- 只需实现水平移动;
- 在超出屏幕边界时,强制回到合法范围内。
-
Ball(球)
- 通过
self.x
,self.y
表示球心位置,self.speed_x
,self.speed_y
表示当前水平和垂直速度; - 每帧更新时,先加上速度;遇到左右墙、上墙时反转速度;遇到底部则表示掉落。
- 在与挡板或砖块相交时,需要根据碰撞方向做出相应反弹。
- 通过
-
Brick(砖块)
- 仅保存坐标、宽高、颜色;
- 被击中后从列表中移除。
-
碰撞检测
- 简化实现:只要球的圆心与砖块矩形区域重叠即可判断为碰撞;
- 在真实游戏中,可以做更精确的检测(圆与矩形边的距离、角度等)或更细致的物理反弹。
-
游戏结束
- 玩家失败:球掉出屏幕底部;
- 玩家胜利:所有砖块被清除。
5. 实现效果
6. 总结
通过本篇文章,你已经学会了如何使用 Python + Pygame 从零构建一个基础的打砖块游戏。该示例涵盖了碰撞检测、游戏循环、对象管理等常见2D游戏开发中的核心逻辑。你可以在此基础上自由发挥,加入更多道具、特效和关卡,从而打造一个更完整、更丰富的打砖块游戏。