当前位置: 首页 > news >正文

Pygame第11课——实现经典打方块小游戏

在这里插入图片描述

目录

    • 专栏导读
    • 前言
    • 🎮 游戏预览
    • 🏗️ 项目架构
      • 模块职责分工
    • 🔧 技术实现详解
      • 1. 配置管理 (config.py)
      • 2. 游戏实体设计 (entities.py)
        • 挡板类 (Paddle)
        • 小球类 (Ball)
        • 方块类与关卡生成
      • 3. 核心游戏逻辑 (main.py)
        • 挡板-小球碰撞算法
        • 方块碰撞与方向判断
        • 主游戏循环架构
    • 🎯 核心特性实现
      • 1. 生命系统与游戏重置
      • 2. 难度递增机制
      • 3. 用户界面与反馈
    • 🚀 运行与安装
      • 环境要求
      • 快速开始
      • 操作说明
    • 完整代码
    • 🎨 扩展思路
      • 游戏性扩展
      • 技术优化
      • 平台适配
    • 📚 学习收获
    • 🏆 结语

专栏导读

  • 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手

  • 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注

  • 👍 该系列文章专栏:请点击——>Python办公自动化专栏求订阅

  • 🕷 此外还有爬虫专栏:请点击——>Python爬虫基础专栏求订阅

  • 📕 此外还有python基础专栏:请点击——>Python基础学习专栏求订阅

  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏

  • ❤️ 欢迎各位佬关注! ❤️

前言

  • 在这个项目中,我将带你从头开始实现一个经典的打方块(Breakout)小游戏。这个游戏不仅能让你体验到编程的乐趣,还能学到游戏开发的核心概念。

🎮 游戏预览

这是一个基于 pygame 的经典打方块游戏,包含:
  • 彩色方块阵列(6行10列,每行不同颜色)
  • 可控制的挡板(左右方向键)
  • 物理反弹的小球
  • 分数系统和生命值
  • Game Over 与重新开始机制
  • 通关后自动进入下一关并提升难度

🏗️ 项目架构

为了让代码结构清晰、易于维护,我将项目分为三个核心模块:
打方块小游戏/
├── config.py      # 游戏配置与常量
├── entities.py    # 游戏实体类(挡板、小球、方块)
├── main.py        # 主游戏循环与逻辑
└── requirements.txt # 依赖管理

模块职责分工

  1. config.py - 集中管理所有配置参数
  2. entities.py - 定义游戏中的各种对象
  3. main.py - 处理游戏循环、事件、碰撞检测

🔧 技术实现详解

1. 配置管理 (config.py)

将所有游戏参数集中在配置文件中,便于调试和平衡性调整:
# 窗口设置
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
FPS = 60# 挡板设置
PADDLE_WIDTH = 100
PADDLE_HEIGHT = 15
PADDLE_SPEED = 8# 小球设置
BALL_RADIUS = 10
BALL_SPEED_X = 3
BALL_SPEED_Y = -3# 方块阵列设置
BRICK_ROWS = 6
BRICK_COLS = 10
BRICK_COLORS = [RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE]

这种设计的好处是:

  • 易于调试快速修改游戏参数无需深入代码
  • 平衡性调整轻松测试不同的难度设置
  • 可维护性避免魔法数字散布在代码各处

2. 游戏实体设计 (entities.py)

挡板类 (Paddle)

类实现了玩家控制的挡板:

class Paddle:def __init__(self):# 挡板初始位置:水平居中,距离底部40像素self.rect = Rect((WINDOW_WIDTH - PADDLE_WIDTH) // 2,WINDOW_HEIGHT - 40,PADDLE_WIDTH, PADDLE_HEIGHT)def move(self, dx):# 边界检测,确保挡板不会移出屏幕self.rect.x += dx * self.speedself.rect.x = max(0, min(self.rect.x, WINDOW_WIDTH - self.rect.width))

设计亮点

  • 使用 pygame.Rect 简化碰撞检测
  • 内置边界检测防止挡板移出屏幕
  • 支持变速移动(通过 self.speed 调节)
小球类 (Ball)

类是游戏的核心,实现了物理运动和墙壁碰撞:

def update(self):# 更新位置self.rect.x += self.vxself.rect.y += self.vy# 墙壁碰撞检测if self.rect.left <= 0 or self.rect.right >= WINDOW_WIDTH:self.vx *= -1  # 水平反弹if self.rect.top <= 0:self.vy *= -1  # 垂直反弹

物理模拟要点

  • 简单的欧拉积分法更新位置
  • 完美弹性碰撞(速度分量取反)
  • 边界检测确保小球不会穿墙
方块类与关卡生成

类设计简洁,重点在于状态管理:

class Brick:def __init__(self, x, y, width=BRICK_WIDTH, height=BRICK_HEIGHT, color=(200, 200, 200)):self.rect = Rect(x, y, width, height)self.color = colorself.alive = True  # 核心状态:是否还存在

函数负责生成整齐排列的方块阵列:

def create_bricks():bricks = []total_width = BRICK_COLS * BRICK_WIDTH + (BRICK_COLS - 1) * BRICK_PADDINGstart_x = (WINDOW_WIDTH - total_width) // 2  # 水平居中for row in range(BRICK_ROWS):color = BRICK_COLORS[row % len(BRICK_COLORS)]  # 每行不同颜色for col in range(BRICK_COLS):x = start_x + col * (BRICK_WIDTH + BRICK_PADDING)y = BRICK_TOP_MARGIN + row * (BRICK_HEIGHT + BRICK_PADDING)bricks.append(Brick(x, y, BRICK_WIDTH, BRICK_HEIGHT, color))return bricks

设计精髓

  • 自动计算居中位置,适应不同屏幕尺寸
  • 颜色循环分配,创造视觉层次感
  • 规则网格布局,确保间距一致

3. 核心游戏逻辑 (main.py)

挡板-小球碰撞算法

函数实现了智能的挡板反弹:

def check_ball_paddle_collision(ball: Ball, paddle: Paddle):if ball.rect.colliderect(paddle.rect):if ball.vy > 0:  # 只在向下运动时反弹# 根据击中位置调整反弹角度offset = (ball.rect.centerx - paddle.rect.centerx) / (paddle.rect.width / 2)offset = max(-1, min(1, offset))  # 限制在 [-1, 1] 范围speed = abs(ball.vx) + abs(ball.vy)  # 保持总速度ball.vx = speed * offsetball.vy = -abs(ball.vy)# 防止穿透ball.rect.bottom = paddle.rect.top - 1

算法亮点

  • 角度控制根据击中位置改变反弹方向,增加策略性
  • 防粘连机制只在小球向下时才反弹,避免卡住
  • 速度保持维持总速度不变,确保游戏节奏
  • 穿透修正强制调整位置防止物理穿透
方块碰撞与方向判断

函数处理复杂的方块碰撞:

def check_ball_bricks_collision(ball: Ball, bricks):score_gain = 0for brick in bricks:if brick.alive and ball.rect.colliderect(brick.rect):brick.alive = Falsescore_gain += SCORE_PER_BRICK# 智能碰撞方向判断dx_left = ball.rect.right - brick.rect.leftdx_right = brick.rect.right - ball.rect.leftdy_top = ball.rect.bottom - brick.rect.topdy_bottom = brick.rect.bottom - ball.rect.topmin_dx = min(dx_left, dx_right)min_dy = min(dy_top, dy_bottom)if min_dx < min_dy:ball.vx *= -1  # 水平反弹else:ball.vy *= -1  # 垂直反弹breakreturn score_gain

碰撞方向算法解析

  1. 计算小球与方块各边的重叠距离
  2. 比较水平和垂直方向的最小重叠
  3. 选择重叠更小的方向进行反弹
  4. 这样确保了物理上合理的反弹效果
主游戏循环架构

函数采用经典的游戏循环结构:

def main():# 初始化pygame.init()screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))clock = pygame.time.Clock()# 游戏对象paddle = Paddle()ball = Ball()bricks = create_bricks()while running:clock.tick(FPS)  # 控制帧率# 1. 处理输入for event in pygame.event.get():# 事件处理...# 2. 更新游戏状态ball.update()check_ball_paddle_collision(ball, paddle)score += check_ball_bricks_collision(ball, bricks)# 3. 渲染画面screen.fill(BLACK)paddle.draw(screen)ball.draw(screen)# ...pygame.display.flip()

游戏循环最佳实践

  • 固定时间步长使用 clock.tick(FPS) 确保稳定帧率
  • 清晰的阶段划分输入→更新→渲染,逻辑清晰
  • 状态管理生命值、分数、游戏状态统一管理

🎯 核心特性实现

1. 生命系统与游戏重置

if ball.rect.top > WINDOW_HEIGHT:lives -= 1if lives <= 0:# 游戏结束逻辑draw_text(screen, "Game Over - 按回车重新开始", 36, WHITE, ...)# 等待重新开始while wait_restart:# 事件监听...# 重置所有游戏状态paddle = Paddle()ball = Ball()bricks = create_bricks()score = 0lives = LIVESelse:ball.reset()  # 重置小球位置

2. 难度递增机制

# 通关检测
if all(not b.alive for b in bricks):bricks = create_bricks()  # 重新生成方块# 提升难度ball.vx *= 1.1ball.vy *= 1.1

简单而有效的难度提升:每通过一关,小球速度增加10%。

3. 用户界面与反馈

def draw_text(surface, text, size, color, center):font = pygame.font.SysFont(None, size)img = font.render(text, True, color)rect = img.get_rect(center=center)surface.blit(img, rect)# HUD 显示
draw_text(screen, f"Score: {score}", 28, WHITE, (80, 20))
draw_text(screen, f"Lives: {lives}", 28, WHITE, (WINDOW_WIDTH - 80, 20))

🚀 运行与安装

环境要求

  • Python 3.7+
  • pygame-ce(兼容新版本Python的pygame社区版)

快速开始

# 3. 安装依赖
pip install -r requirements.txt# 4. 运行游戏
python main.py

操作说明

  • 左右方向键:移动挡板
  • ESC:退出游戏
  • Enter:游戏结束后重新开始

完整代码

  • config.py

# 游戏配置文件
import pygame# 窗口设置
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
FPS = 60# 颜色定义 (RGB)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 165, 0)
PURPLE = (128, 0, 128)
CYAN = (0, 255, 255)
PINK = (255, 192, 203)
GRAY = (128, 128, 128)# 挡板设置
PADDLE_WIDTH = 100
PADDLE_HEIGHT = 15
PADDLE_SPEED = 8
PADDLE_COLOR = WHITE# 小球设置
BALL_RADIUS = 10
BALL_SPEED_X = 3
BALL_SPEED_Y = -3
BALL_COLOR = WHITE# 方块设置
BRICK_WIDTH = 75
BRICK_HEIGHT = 30
BRICK_PADDING = 5
BRICK_ROWS = 6
BRICK_COLS = 10
BRICK_TOP_MARGIN = 80# 方块颜色 (每行不同颜色)
BRICK_COLORS = [RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE]# 游戏设置
LIVES = 3
SCORE_PER_BRICK = 10
  • entities.py

import pygame
from pygame import Rect
from config import (WINDOW_WIDTH, WINDOW_HEIGHT,PADDLE_WIDTH, PADDLE_HEIGHT, PADDLE_SPEED, PADDLE_COLOR,BALL_RADIUS, BALL_SPEED_X, BALL_SPEED_Y, BALL_COLOR,BRICK_WIDTH, BRICK_HEIGHT, BRICK_PADDING, BRICK_ROWS, BRICK_COLS, BRICK_TOP_MARGIN, BRICK_COLORS
)class Paddle:def __init__(self):self.rect = Rect((WINDOW_WIDTH - PADDLE_WIDTH) // 2,WINDOW_HEIGHT - 40,PADDLE_WIDTH, PADDLE_HEIGHT)self.speed = PADDLE_SPEEDself.color = PADDLE_COLORdef move(self, dx):self.rect.x += dx * self.speedself.rect.x = max(0, min(self.rect.x, WINDOW_WIDTH - self.rect.width))def draw(self, surface):pygame.draw.rect(surface, self.color, self.rect)class Ball:def __init__(self):self.radius = BALL_RADIUSself.color = BALL_COLORself.reset()def reset(self):self.rect = Rect(WINDOW_WIDTH // 2 - self.radius,WINDOW_HEIGHT // 2 - self.radius,self.radius * 2, self.radius * 2)self.vx = BALL_SPEED_Xself.vy = BALL_SPEED_Ydef update(self):self.rect.x += self.vxself.rect.y += self.vy# 碰撞墙壁if self.rect.left <= 0 or self.rect.right >= WINDOW_WIDTH:self.vx *= -1if self.rect.top <= 0:self.vy *= -1def draw(self, surface):pygame.draw.ellipse(surface, self.color, self.rect)class Brick:def __init__(self, x, y, width=BRICK_WIDTH, height=BRICK_HEIGHT, color=(200, 200, 200)):self.rect = Rect(x, y, width, height)self.color = colorself.alive = Truedef draw(self, surface):if self.alive:pygame.draw.rect(surface, self.color, self.rect)# 描边pygame.draw.rect(surface, (50, 50, 50), self.rect, 2)def create_bricks():bricks = []total_width = BRICK_COLS * BRICK_WIDTH + (BRICK_COLS - 1) * BRICK_PADDINGstart_x = (WINDOW_WIDTH - total_width) // 2for row in range(BRICK_ROWS):color = BRICK_COLORS[row % len(BRICK_COLORS)]for col in range(BRICK_COLS):x = start_x + col * (BRICK_WIDTH + BRICK_PADDING)y = BRICK_TOP_MARGIN + row * (BRICK_HEIGHT + BRICK_PADDING)bricks.append(Brick(x, y, BRICK_WIDTH, BRICK_HEIGHT, color))return bricks
  • main.py

import sys
import pygame
from pygame.locals import QUIT, KEYDOWN, K_LEFT, K_RIGHTfrom config import (WINDOW_WIDTH, WINDOW_HEIGHT, FPS,BLACK, WHITE, RED,LIVES, SCORE_PER_BRICK
)
from entities import Paddle, Ball, create_bricksdef check_ball_paddle_collision(ball: Ball, paddle: Paddle):if ball.rect.colliderect(paddle.rect):# 只在小球向下运动时反弹,避免粘连if ball.vy > 0:offset = (ball.rect.centerx - paddle.rect.centerx) / (paddle.rect.width / 2)offset = max(-1, min(1, offset))speed = abs(ball.vx) + abs(ball.vy)ball.vx = speed * offsetball.vy = -abs(ball.vy)# 调整位置避免穿透ball.rect.bottom = paddle.rect.top - 1def check_ball_bricks_collision(ball: Ball, bricks):score_gain = 0for brick in bricks:if brick.alive and ball.rect.colliderect(brick.rect):brick.alive = Falsescore_gain += SCORE_PER_BRICK# 碰撞方向判断dx_left = ball.rect.right - brick.rect.leftdx_right = brick.rect.right - ball.rect.leftdy_top = ball.rect.bottom - brick.rect.topdy_bottom = brick.rect.bottom - ball.rect.topmin_dx = min(dx_left, dx_right)min_dy = min(dy_top, dy_bottom)if min_dx < min_dy:ball.vx *= -1else:ball.vy *= -1breakreturn score_gaindef draw_text(surface, text, size, color, center):font = pygame.font.SysFont(None, size)img = font.render(text, True, color)rect = img.get_rect(center=center)surface.blit(img, rect)def main():pygame.init()screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))pygame.display.set_caption("打方块小游戏")clock = pygame.time.Clock()paddle = Paddle()ball = Ball()bricks = create_bricks()score = 0lives = LIVESrunning = Truewhile running:clock.tick(FPS)# 事件处理for event in pygame.event.get():if event.type == QUIT:running = Falseelif event.type == KEYDOWN and event.key == pygame.K_ESCAPE:running = False# 键盘连续输入keys = pygame.key.get_pressed()dx = (keys[K_RIGHT] - keys[K_LEFT])if dx != 0:paddle.move(dx)# 更新小球ball.update()# 碰撞检测check_ball_paddle_collision(ball, paddle)score += check_ball_bricks_collision(ball, bricks)# 掉出底部if ball.rect.top > WINDOW_HEIGHT:lives -= 1if lives <= 0:# 游戏结束,重置draw_text(screen, "Game Over - 按回车重新开始", 36, WHITE, (WINDOW_WIDTH//2, WINDOW_HEIGHT//2))pygame.display.flip()wait_restart = Truewhile wait_restart:for event in pygame.event.get():if event.type == QUIT:pygame.quit()sys.exit()elif event.type == KEYDOWN and event.key == pygame.K_RETURN:wait_restart = False# 重置游戏paddle = Paddle()ball = Ball()bricks = create_bricks()score = 0lives = LIVESelse:ball.reset()# 全部方块清空,进入下一关(简单处理:重新生成方块,速度稍增)if all(not b.alive for b in bricks):bricks = create_bricks()# 提升难度ball.vx *= 1.1ball.vy *= 1.1# 绘制screen.fill(BLACK)paddle.draw(screen)ball.draw(screen)for brick in bricks:brick.draw(screen)# HUDdraw_text(screen, f"Score: {score}", 28, WHITE, (80, 20))draw_text(screen, f"Lives: {lives}", 28, WHITE, (WINDOW_WIDTH - 80, 20))pygame.display.flip()pygame.quit()if __name__ == "__main__":main()

🎨 扩展思路

这个基础版本为进一步扩展奠定了良好基础:

游戏性扩展

  • 道具系统加长挡板、多球、穿透球等
  • 特殊方块需要多次击打、爆炸方块、移动方块
  • 关卡编辑器自定义方块布局和颜色

技术优化

  • 粒子效果方块破碎、小球轨迹特效
  • 音效系统碰撞音效、背景音乐
  • 存档系统最高分记录、关卡进度保存

平台适配

  • 移动端适配触摸控制、屏幕适配
  • Web版本使用 Pygame Web 或 Panda3D
  • 多人模式本地或网络对战

📚 学习收获

通过这个项目,你将掌握:

  1. 游戏开发基础游戏循环、状态管理、碰撞检测
  2. 面向对象设计类的设计与交互、模块化编程
  3. 物理模拟简单的运动学、弹性碰撞
  4. 用户交互键盘输入处理、实时反馈
  5. 项目结构配置管理、代码组织、依赖管理

🏆 结语

这个打方块游戏虽然简单,但包含了游戏开发的核心要素。从配置管理到物理模拟,从碰撞检测到用户界面,每一个部分都值得深入研究。
更重要的是,这个项目展示了如何用清晰的架构和合理的设计模式来构建一个完整的应用程序。无论你是游戏开发新手还是想要回顾经典,这个项目都能给你带来启发。
现在就开始游戏,看看你能坚持多少关吧!🎮

  • 希望对初学者有帮助;致力于办公自动化的小小程序员一枚

  • 希望能得到大家的【❤️一个免费关注❤️】感谢!

  • 求个 🤞 关注 🤞 +❤️ 喜欢 ❤️ +👍 收藏 👍

  • 此外还有办公自动化专栏,欢迎大家订阅:Python办公自动化专栏

  • 此外还有爬虫专栏,欢迎大家订阅:Python爬虫基础专栏

  • 此外还有Python基础专栏,欢迎大家订阅:Python基础学习专栏

http://www.lryc.cn/news/626026.html

相关文章:

  • 数据结构:二叉树oj练习
  • Linux------《零基础到联网:CentOS 7 在 VMware Workstation 中的全流程安装与 NAT 网络配置实战》
  • Apache ShenYu网关与Nacos的关联及如何配合使用
  • AJAX (一)
  • C# DevExpress控件安装使用教程
  • 【学习】Linux 内核中的 cgroup freezer 子系统
  • 【自动化运维神器Ansible】Playbook调用Role详解:从入门到精通
  • 常用css
  • 【C++】C++ 的护身符:解锁 try-catch 异常处理
  • 用java语言完成手写mybatis框架(第2章)
  • 借助AI将infoNES移植到HarmonyOS平台的详细方案介绍
  • Linux操作系统编程——进程间的通信
  • 极海APM32F107V6 gpio模拟串口
  • 决策树算法学习总结
  • 【Vivado TCL 教程】从零开始掌握 Xilinx Vivado TCL 脚本编程(三)
  • UML常见图例
  • 一文精通 Swagger 在 .NET 中的全方位配置与应用
  • Java NIO 核心精讲(上):Channel、Buffer、Selector 详解与 ByteBuffer 完全指南
  • 【3-3】流量控制与差错控制
  • Linux资源管理
  • JUC之CompletableFuture【上】
  • Orbbec---setBoolProperty 快捷配置设备行为
  • 设备树下的LED驱动实验
  • 从数据表到退磁:Ansys Maxwell中N48磁体磁化指南
  • 谷歌为什么要将Android的页面大小(Page Size)从传统的4KB升级至16KB
  • Go 进阶学习路线
  • 测试 Next.js 应用:工具与策略
  • 仲裁器设计(三)-- Weighted Round Robin 权重轮询调度
  • ASP4644稳压器的特性分析与系统测试方法研究
  • GPT-4.1旗舰模型:复杂任务的最佳选择及API集成实践