作为一名刚接触编程不久的大一学生,最近在学习 Python 时发现了一个很有趣的库 ——Pygame。它让游戏开发变得简单易懂,非常适合编程新手入门。今天就来分享一下我用 Pygame 制作简单打砖块游戏的过程,希望能帮助到和我一样刚入门的同学。

一、准备工作

首先需要安装 Pygame 库,如果你还没有安装,可以打开命令行输入:

bash

pip install pygame

安装完成后,我们就可以开始编写游戏了。这个打砖块游戏的核心逻辑很简单:通过键盘控制挡板,接住小球,打掉砖块得分。

二、游戏基本框架

任何游戏都有一个基本框架,Pygame 也不例外。一个最简单的游戏框架包含以下几个部分:

  1. 初始化 Pygame
  2. 设置游戏窗口
  3. 游戏主循环(事件处理、逻辑更新、画面渲染)
  4. 退出游戏

下面是基础框架代码:

python

运行

import pygame
import sys

# 初始化Pygame
pygame.init()

# 设置窗口大小和标题
width, height = 800, 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("打砖块游戏")

# 游戏主循环
running = True
while running:
    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    
    # 填充背景色(黑色)
    screen.fill((0, 0, 0))
    
    # 更新显示
    pygame.display.flip()

# 退出游戏
pygame.quit()
sys.exit()

运行这段代码,会出现一个黑色窗口,点击关闭按钮可以正常退出。

三、添加游戏元素

接下来我们需要添加游戏中的各种元素:挡板、小球和砖块。

1. 挡板类

我们用面向对象的方式来创建挡板类,方便管理挡板的属性和行为:

python

运行

class Paddle(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.width = 100
        self.height = 15
        self.image = pygame.Surface((self.width, self.height))
        self.image.fill((0, 255, 0))  # 绿色挡板
        self.rect = self.image.get_rect()
        # 初始位置在屏幕底部中央
        self.rect.centerx = width // 2
        self.rect.bottom = height - 10
        self.speed = 8  # 移动速度

    def update(self):
        # 获取键盘状态
        keys = pygame.key.get_pressed()
        # 左右移动
        if keys[pygame.K_LEFT] and self.rect.left > 0:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT] and self.rect.right < width:
            self.rect.x += self.speed

2. 小球类

同样地,我们创建一个小球类:

python

运行

class Ball(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.radius = 10
        self.image = pygame.Surface((self.radius*2, self.radius*2), pygame.SRCALPHA)
        pygame.draw.circle(self.image, (255, 255, 0), (self.radius, self.radius), self.radius)  # 黄色小球
        self.rect = self.image.get_rect()
        # 初始位置在挡板上方
        self.rect.centerx = width // 2
        self.rect.bottom = height - 30
        self.speed_x = 4
        self.speed_y = -4  # 初始向上移动

    def update(self):
        self.rect.x += self.speed_x
        self.rect.y += self.speed_y
        
        # 左右边界碰撞检测
        if self.rect.left <= 0 or self.rect.right >= width:
            self.speed_x *= -1  # 反向
        
        # 上边界碰撞检测
        if self.rect.top <= 0:
            self.speed_y *= -1  # 反向

3. 砖块类

最后是砖块类:

python

运行

class Brick(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.width = 75
        self.height = 20
        self.image = pygame.Surface((self.width, self.height))
        self.image.fill((0, 0, 255))  # 蓝色砖块
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

四、实现游戏逻辑

现在我们需要将这些元素组合起来,并实现游戏逻辑:

  1. 创建精灵组来管理游戏元素
  2. 生成砖块矩阵
  3. 实现碰撞检测
  4. 添加得分系统
  5. 处理游戏结束条件

完整代码如下:

python

运行

import pygame
import sys

# 初始化Pygame
pygame.init()

# 设置窗口大小和标题
width, height = 800, 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("打砖块游戏")

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

# 挡板类
class Paddle(pygame.sprite.Sprite):
    # [前面定义的Paddle类代码]

# 小球类
class Ball(pygame.sprite.Sprite):
    # [前面定义的Ball类代码]

# 砖块类
class Brick(pygame.sprite.Sprite):
    # [前面定义的Brick类代码]

# 创建精灵组
all_sprites = pygame.sprite.Group()
bricks = pygame.sprite.Group()
paddle_group = pygame.sprite.Group()

# 创建挡板
paddle = Paddle()
all_sprites.add(paddle)
paddle_group.add(paddle)

# 创建小球
ball = Ball()
all_sprites.add(ball)

# 创建砖块矩阵
brick_rows = 5
brick_cols = 10
for row in range(brick_rows):
    for col in range(brick_cols):
        brick_x = col * (75 + 10) + 30  # 75是砖块宽度,10是间距
        brick_y = row * (20 + 10) + 50  # 20是砖块高度,10是间距
        brick = Brick(brick_x, brick_y)
        all_sprites.add(brick)
        bricks.add(brick)

# 得分
score = 0
font = pygame.font.Font(None, 36)

# 游戏主循环
clock = pygame.time.Clock()
running = True
game_over = False

while running:
    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # 按空格键重新开始游戏
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE and game_over:
                # 重置游戏
                game_over = False
                score = 0
                # 重置小球位置
                ball.rect.centerx = width // 2
                ball.rect.bottom = height - 30
                ball.speed_x = 4
                ball.speed_y = -4
                # 重新创建砖块
                bricks.empty()
                for row in range(brick_rows):
                    for col in range(brick_cols):
                        brick_x = col * (75 + 10) + 30
                        brick_y = row * (20 + 10) + 50
                        brick = Brick(brick_x, brick_y)
                        all_sprites.add(brick)
                        bricks.add(brick)
    
    if not game_over:
        # 更新所有精灵
        all_sprites.update()
        
        # 挡板和小球碰撞检测
        if pygame.sprite.spritecollide(ball, paddle_group, False):
            # 小球碰到挡板反弹
            ball.speed_y *= -1
            # 让小球根据碰到挡板的位置改变水平方向
            offset = (ball.rect.centerx - paddle.rect.centerx) / (paddle.width / 2)
            ball.speed_x = offset * 5
        
        # 小球和砖块碰撞检测
        brick_hits = pygame.sprite.spritecollide(ball, bricks, True)
        if brick_hits:
            score += len(brick_hits)
            ball.speed_y *= -1
        
        # 小球碰到下边界,游戏结束
        if ball.rect.bottom >= height:
            game_over = True
        
        # 所有砖块被打掉,游戏胜利
        if len(bricks) == 0:
            game_over = True
    
    # 填充背景色
    screen.fill(BLACK)
    
    # 绘制所有精灵
    all_sprites.draw(screen)
    
    # 显示得分
    score_text = font.render(f"得分: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))
    
    # 游戏结束显示
    if game_over:
        if len(bricks) == 0:

与其他文章做出足够的差异化

已完成思考

为了让博客在 CSDN 的同类 Pygame 入门文中更有辨识度,我会从「新手真实踩坑视角」出发,用「问题拆解 + 分步调试」的思路替代传统的「代码堆砌」,同时加入「轻量化优化」和「个性化拓展」模块,让大一学生不仅能复现游戏,还能理解每一步的设计逻辑。

大一学 Python 半个月,我用 Pygame 做了个打砖块游戏(附踩坑实录 + 优化技巧)

作为一名刚学 Python 基础的大一新生,总觉得 “print 输出” 和 “循环判断” 太枯燥 —— 直到发现了 Pygame!这个库能把枯燥的代码变成可视化的游戏,简直是编程入门的 “快乐催化剂”。

最近花了 3 天时间,从 0 到 1 做了一个打砖块游戏,过程中踩了不少新手才会犯的错(比如窗口卡死、小球穿墙),也总结了一套 “新手友好” 的实现思路。这篇文章不只是贴代码,更想跟大家分享 “怎么从一个想法落地成游戏”,适合和我一样刚入门的同学参考。

一、先想清楚:新手做游戏,别一开始就贪多

很多教程上来就做 “带关卡 + 音效 + 道具” 的复杂版本,新手很容易看到一半就放弃。我的经验是:先实现 “最小可行版本”,再一点点加功能

这个打砖块游戏的 “最小版本” 只需要 3 个核心元素:

  1. 挡板:用键盘左右控制,接住小球
  2. 小球:反弹碰撞,打掉砖块
  3. 砖块:被小球碰到就消失,计分

先搞定这三点,再考虑优化 —— 这是避免中途放弃的关键!

二、准备工作:新手必看的环境配置(避坑版)

1. 安装 Pygame(别直接 pip!)

刚开始我直接在命令行输pip install pygame,结果因为 Python 版本和 Pygame 版本不匹配,运行时一直报错。正确的做法是:

  • 先查自己的 Python 版本(命令行输python --version),比如我的是 3.9
  • 去 Pygame 官网看对应版本(3.9 推荐装 Pygame 2.1.2)
  • 指定版本安装:pip install pygame==2.1.2

2. 用 Pycharm 建项目(一定要开虚拟环境!)

大一可能同时学多个 Python 课程,不同项目的库版本容易冲突。建项目时选 “Virtualenv”,相当于给这个游戏单独开一个 “隔离环境”,不会影响其他作业:

  1. 打开 Pycharm → New Project
  2. Location 选自己的文件夹(比如 “D:\PythonGames\BrickBreaker”)
  3. 勾选 “New environment using” → 选 “Virtualenv”
  4. 点击 Create,等待环境创建完成

三、从零写游戏:按 “问题拆解” 思路来,别慌!

第一步:写一个 “能打开的窗口”(解决 “窗口卡死” 问题)

任何游戏的基础都是 “一个能正常关闭的窗口”。刚开始我只写了窗口创建,没加 “退出事件处理”,结果点关闭按钮没反应,只能强制结束进程。

正确的基础框架代码(带注释):

python

import pygame
import sys  # 一定要导入sys,不然关不了窗口

# 1. 初始化Pygame(必须第一步做)
pygame.init()

# 2. 设置窗口:宽800,高600,标题“打砖块”
screen_width, screen_height = 800, 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("大一新手的打砖块游戏")

# 3. 游戏主循环(核心中的核心!)
running = True
while running:
    # 处理事件(比如点击关闭、按键操作)
    for event in pygame.event.get():
        # 关键:检测“关闭窗口”事件
        if event.type == pygame.QUIT:
            running = False  # 退出循环
            pygame.quit()    # 关闭Pygame
            sys.exit()       # 彻底退出程序
    
    # 填充背景色(黑色,RGB值(0,0,0))
    screen.fill((0, 0, 0))
    
    # 更新屏幕(必须有,不然画面不显示)
    pygame.display.flip()

运行这段代码,会弹出一个黑色窗口,点击关闭能正常退出 —— 这就完成了第一步!

第二步:用 “类” 来定义游戏元素(新手也能懂的面向对象)

为什么要用 “类”?比如挡板和小球都有 “位置”“大小”“移动速度”,用类封装起来,改参数时不用到处找代码。

1. 写一个 “能左右动的挡板”(解决 “移动越界” 问题)

刚开始我没限制挡板的移动范围,结果挡板能跑出屏幕外。这里加个判断:左边不超过 0,右边不超过屏幕宽度。

python

class Paddle:  # 挡板类
    def __init__(self):
        # 挡板属性:宽100,高15,绿色
        self.width = 100
        self.height = 15
        self.color = (0, 255, 0)  # RGB绿色
        
        # 挡板位置:底部中央(bottom是底边的y坐标)
        self.x = (screen_width - self.width) // 2  # 水平居中
        self.y = screen_height - 20  # 距离底部20像素
        
        # 移动速度(每帧走8像素)
        self.speed = 8

    def draw(self):
        # 画挡板:rect(屏幕, 颜色, (x, y, 宽, 高))
        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))

    def move(self):
        # 获取键盘按键状态(持续按键有效)
        keys = pygame.key.get_pressed()
        # 左移:按左箭头,且x>0(不超过左边界)
        if keys[pygame.K_LEFT] and self.x > 0:
            self.x -= self.speed
        # 右移:按右箭头,且x+宽<屏幕宽(不超过右边界)
        if keys[pygame.K_RIGHT] and self.x + self.width < screen_width:
            self.x += self.speed
2. 写一个 “会反弹的小球”(解决 “穿墙” 问题)

小球反弹的核心是 “碰到边界就反向速度”。刚开始我只算了 x 轴和 y 轴的反弹,结果小球偶尔会 “卡” 在边界 —— 后来发现是碰撞检测的时机不对,要在每次移动后就判断。

python

class Ball:  # 小球类
    def __init__(self):
        # 小球属性:半径10,黄色
        self.radius = 10
        self.color = (255, 255, 0)  # RGB黄色
        
        # 小球位置:挡板正上方
        self.x = screen_width // 2
        self.y = screen_height - 20 - self.radius  # 距离挡板顶部一个半径
        
        # 移动速度:x轴4像素,y轴-4像素(向上)
        self.speed_x = 4
        self.speed_y = -4

    def draw(self):
        # 画小球:circle(屏幕, 颜色, (圆心x,y), 半径)
        pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius)

    def move(self):
        # 移动小球
        self.x += self.speed_x
        self.y += self.speed_y
        
        # 碰到左右边界:x速度反向
        if self.x - self.radius <= 0 or self.x + self.radius >= screen_width:
            self.speed_x *= -1
        # 碰到上边界:y速度反向
        if self.y - self.radius <= 0:
            self.speed_y *= -1
        
        # 碰到下边界:游戏结束(后面会用到)
        global game_over
        if self.y + self.radius >= screen_height:
            game_over = True
3. 写一批 “能被打掉的砖块”(解决 “砖块重叠” 问题)

砖块要排成矩阵,新手容易犯的错是 “间距没算好”,导致砖块挤在一起。这里用 “列数 ×(砖块宽 + 间距)” 来计算每个砖块的 x 坐标。

python

class Brick:  # 砖块类
    def __init__(self, x, y):
        # 砖块属性:宽75,高20,蓝色
        self.width = 75
        self.height = 20
        self.color = (0, 0, 255)  # RGB蓝色
        
        # 砖块位置:由外部传入(矩阵排列用)
        self.x = x
        self.y = y

    def draw(self):
        # 画砖块
        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))

第三步:把元素拼起来,实现核心逻辑

现在有了挡板、小球、砖块,接下来要解决 3 个关键问题:碰撞检测、计分、游戏结束判断。

1. 初始化所有元素(在主循环前加)

python

# 初始化游戏元素
paddle = Paddle()  # 挡板
ball = Ball()      # 小球
bricks = []        # 砖块列表

# 生成砖块矩阵:5行10列,间距10像素
brick_rows = 5
brick_cols = 10
brick_gap = 10  # 砖块间距
for row in range(brick_rows):
    for col in range(brick_cols):
        # 计算每个砖块的x、y坐标
        brick_x = col * (75 + brick_gap) + 30  # 左边留30像素边距
        brick_y = row * (20 + brick_gap) + 50  # 上边留50像素边距
        bricks.append(Brick(brick_x, brick_y))  # 加入列表

# 游戏状态变量
score = 0          # 得分
game_over = False  # 游戏是否结束
font = pygame.font.Font(None, 36)  # 字体(用于显示得分)
2. 实现碰撞检测(核心!)

碰撞检测的本质是 “判断两个图形是否重叠”。新手不用写复杂算法,用 Pygame 的rect(矩形)来简化判断:

python

def check_collisions():
    global score
    # 1. 小球和挡板碰撞
    # 用rect模拟小球的碰撞范围(简化圆形碰撞为矩形)
    ball_rect = pygame.Rect(ball.x - ball.radius, ball.y - ball.radius, 
                            ball.radius*2, ball.radius*2)
    # 挡板的rect
    paddle_rect = pygame.Rect(paddle.x, paddle.y, paddle.width, paddle.height)
    
    # 如果两个rect重叠,小球y速度反向
    if ball_rect.colliderect(paddle_rect):
        ball.speed_y *= -1
        # 进阶:让小球根据碰撞位置改变x速度(更有操作性)
        hit_pos = (ball.x - (paddle.x + paddle.width//2)) / (paddle.width//2)
        ball.speed_x = hit_pos * 5  # 碰撞位置越偏,x速度越大
    
    # 2. 小球和砖块碰撞
    for brick in bricks[:]:  # 用切片遍历,避免删除元素时出错
        brick_rect = pygame.Rect(brick.x, brick.y, brick.width, brick.height)
        if ball_rect.colliderect(brick_rect):
            ball.speed_y *= -1  # 反弹
            bricks.remove(brick)  # 移除砖块
            score += 10  # 加10分
            break  # 一次只碰一个砖块
3. 更新主循环(把所有逻辑串起来)

修改之前的主循环,加入 “元素绘制”“移动”“碰撞检测”:

python

# 游戏主循环(更新版)
clock = pygame.time.Clock()  # 控制帧率
while running:
    # 1. 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
            pygame.quit()
            sys.exit()
        # 按空格键重新开始游戏
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE and game_over:
                # 重置游戏状态
                game_over = False
                score = 0
                ball = Ball()  # 重新创建小球
                bricks = []    # 重新创建砖块
                for row in range(brick_rows):
                    for col in range(brick_cols):
                        brick_x = col * (75 + brick_gap) + 30
                        brick_y = row * (20 + brick_gap) + 50
                        bricks.append(Brick(brick_x, brick_y))
    
    # 2. 游戏逻辑(只在游戏未结束时执行)
    if not game_over:
        paddle.move()    # 挡板移动
        ball.move()      # 小球移动
        check_collisions()  # 碰撞检测
        # 如果砖块全被打掉,游戏胜利
        if len(bricks) == 0:
            game_over = True
    
    # 3. 画面渲染
    screen.fill((0, 0, 0))  # 清屏(必须先清屏再重绘)
    paddle.draw()           # 画挡板
    ball.draw()             # 画小球
    for brick in bricks:
        brick.draw()        # 画所有砖块
    
    # 显示得分
    score_text = font.render(f"得分: {score}", True, (255, 255, 255))
    screen.blit(score_text, (10, 10))  # 把文字画在屏幕上
    
    # 显示游戏结束信息
    if game_over:
        if len(bricks) == 0:
            end_text = font.render("恭喜胜利!按空格键重来", True, (255, 0, 0))
        else:
            end_text = font.render("游戏结束!按空格键重来", True, (255, 0, 0))
        # 文字居中显示
        screen.blit(end_text, (screen_width//2 - end_text.get_width()//2, screen_height//2))
    
    # 4. 更新屏幕
    pygame.display.flip()
    clock.tick(60)  # 锁定60帧率(避免速度过快)

四、新手也能做的 “轻量化优化”(让游戏更像回事)

完成基础版本后,花 10 分钟加几个小优化,游戏体验会提升很多:

1. 给砖块加不同颜色和分数

把砖块类的颜色改成传入参数,不同行的砖块用不同颜色,得分也不一样:

python

# 修改Brick类的__init__
def __init__(self, x, y, color, score):
    self.width = 75
    self.height = 20
    self.color = color  # 外部传入颜色
    self.x = x
    self.y = y
    self.score = score  # 外部传入得分

# 生成砖块时改一下
colors = [(0,0,255), (0,128,255), (0,255,255), (0,255,128), (0,255,0)]  # 蓝到绿的渐变
scores = [10, 20, 30, 40, 50]  # 越下面的砖块得分越高
for row in range(brick_rows):
    for col in range(brick_cols):
        brick_x = col * (75 + brick_gap) + 30
        brick_y = row * (20 + brick_gap) + 50
        # 每行用不同颜色和得分
        bricks.append(Brick(brick_x, brick_y, colors[row], scores[row]))

# 碰撞检测时改得分
if ball_rect.colliderect(brick_rect):
    ball.speed_y *= -1
    score += brick.score  # 用砖块自己的得分
    bricks.remove(brick)

2. 加个背景音乐(1 行代码搞定)

Pygame 播放音乐很简单,在初始化 Pygame 后加:

python

# 播放背景音乐(需要提前准备一个mp3文件,放在项目文件夹里)
pygame.mixer.music.load("bgm.mp3")  # 音乐文件路径
pygame.mixer.music.play(-1)  # -1表示循环播放
pygame.mixer.music.set_volume(0.3)  # 音量调小一点(0-1之间)

五、踩坑总结:大一新手最容易犯的 5 个错

  1. 忘记处理退出事件:窗口卡死,只能强关(一定要加pygame.QUIT的判断)
  2. 没清屏就重绘:画面会出现 “拖影”(screen.fill()必须在绘制元素前)
  3. 砖块遍历删除出错:直接for brick in bricks删除会漏元素(用for brick in bricks[:]切片遍历)
  4. 帧率没锁定:不同电脑速度不一样(用clock.tick(60)锁定帧率)
  5. 碰撞检测用圆形:新手算圆形碰撞容易出错(先用rect简化,熟练后再用mask像素级检测)

六、下一步进阶:新手可以尝试的拓展功能

如果觉得基础版本太简单,可以试试这些方向:

  1. 加道具:比如 “变大挡板”“小球分裂”(用随机生成道具类实现)
  2. 加关卡:不同关卡砖块排列不同,小球速度更快
  3. 加存档:用json保存最高分(前面学的文件操作终于用上了!)
  4. 加粒子效果:砖块被打掉时出现碎片(用小矩形的移动模拟)

最后想说的话

作为大一新生,刚开始写游戏时总觉得 “好难,肯定做不出来”,但拆成 “窗口→元素→逻辑→优化” 一步步来,发现其实没那么可怕。Pygame 最棒的地方就是 “所见即所得”—— 改一行代码,运行就能看到效果,这种反馈感比做课后习题强太多了。

如果这篇文章帮到了你,欢迎在评论区交流你的游戏版本~ 也可以告诉我你踩过的坑,咱们一起避坑!

更多推荐