最近在补 Pygame 游戏开发的入门实践,想到《Simon's Cat》里那只总在饿肚子边缘疯狂试探的黑白猫,手感特别适合做成一个 2D 跑酷小游戏。于是动手写了一个叫“猫咪狂奔记”的横版跳跃项目:猫咪持续向右奔跑,玩家用空格键控制起跳,躲避栅栏、纸箱这类障碍物,同时尽量吃到飞在空中的小鱼来加分。
本文会从游戏设计思路讲起,完整拆解用 Python + Pygame 实现这个游戏的全过程。所有代码都放在一个main.py里,方便直接复制运行,适合刚学完 Python 基础、想通过小项目巩固面向对象和事件循环的读者,也适合想快速做一个课设样例的开发者。代码虽然简单,但游戏循环、重力模拟、碰撞检测、随机生成这些核心概念都会覆盖到。
为什么用 Simon's Cat 这个题材
Simon's Cat 是英国动画师西蒙·托菲尔德(Simon Tofield)创作的系列动画短片,主角是一只黑白相间、表情丰富的小猫。它的动作夸张,经常为了吃的做出各种捣蛋行为,非常适合用来做跑酷游戏的主角。
用这个题材做游戏,主要出于三个考虑:
- 角色辨识度高。黑白猫形象简单,即使不用美术素材,用 Pygame 的基础绘图函数也能画出一个“神似”的猫咪。
- 动画风格天然适配跑酷玩法。猫咪奔跑、扑食、被绊倒的肢体语言,转换成游戏动画和碰撞反馈都很自然。
- 开发成本低。这个项目完全可以不依赖外部图片,所有角色、障碍物、食物都用几何图形绘制,代码自包含,新手也能跑起来。
1. 背景与核心概念
1.1 2D 跑酷游戏的基本构成
“猫咪狂奔记”本质上是一个横版跑酷游戏。这一类游戏的核心逻辑可以归纳成下面几条:
- 人物自动向右侧移动,或者在原地奔跑、场景向左移动。
- 玩家需要控制跳跃和落地时机,躲避障碍物。
- 场景中随机出现加分道具,鼓励玩家主动冒险。
- 随着时间推移,游戏难度逐渐提升,玩家最终会因为一次失误而结束游戏。
本文采用的实现方案是“人物原地奔跑,场景物体向左移动”。这样做的好处是猫咪的坐标变化简单,只需要维护一个垂直方向的 y 坐标,地面和跳跃逻辑好算,也不容易出坐标漂移的 bug。
1.2 Pygame 在其中的作用
Pygame 是 Python 非常经典的 2D 游戏开发库,它封装了窗口创建、键盘鼠标事件、图形绘制、字体渲染和音频播放等能力。你不需要关心底层 OpenGL 或者窗口系统,只需要把注意力放在游戏逻辑上。
这个项目会用到的 Pygame 核心模块包括:
| 模块 | 作用 |
|---|---|
pygame.display | 创建游戏窗口,刷新画面 |
pygame.event | 接收键盘、退出等事件 |
pygame.draw | 绘制矩形、圆形、多边形等基础图形 |
pygame.Rect | 表示矩形区域,用于碰撞检测 |
pygame.time.Clock | 控制游戏帧率 |
pygame.font | 在画面上绘制文字 |
理解这些模块,就能理解一个 Pygame 项目的大部分结构。
1.3 这个项目的学习收益
完成这个项目,你会掌握:
- 游戏循环的基本写法:事件处理、状态更新、画面渲染。
- 基于帧的物理模拟:重力、跳跃、落地。
- 基于矩形区域的碰撞检测。
- 面向对象思想在游戏中的实际应用。
- 随机生成关卡元素和难度递增机制。
这些知识点可以平移到很多 2D 游戏项目中,哪怕是以后去接触 Unity、Godot,这一套游戏循环思想也是通用的。
2. 环境准备与项目结构
2.1 Python 与 Pygame 安装
本文代码基于 Python 3.8 及以上版本,Pygame 使用 2.x 系列。如果你电脑里还没有 Python,可以先去官网下载安装包。装好之后,在命令行里确认版本:
python --version然后安装 Pygame:
pip install pygame如果下载速度慢,可以使用国内镜像源:
pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后可以验证:
python -c "import pygame; print(pygame.version.ver)"能看到版本号就说明环境没问题。
2.2 版本兼容性说明
本文示例代码使用pygame.Rect的border_radius参数来画圆角矩形,这是 Pygame 2.0 之后才支持的特性。如果你安装的是 Pygame 1.9.x,运行代码可能会报got an unexpected keyword argument 'border_radius'之类的错误。
解决办法要么是升级 Pygame:
pip install --upgrade pygame要么把手动把代码里的border_radius=xx参数删掉。本文下面的代码以 Pygame 2.x 为准。
2.3 项目结构设计
为了让新手更容易上手,这个项目采用单文件结构。所有游戏代码都写在main.py中。如果你后面想扩展,可以按职责拆分成多个文件,比如:
cat_run/ ├── main.py # 游戏入口与主循环 ├── config.py # 常量配置 ├── cat.py # 猫咪角色类 ├── obstacle.py # 障碍物类 ├── food.py # 食物类 └── utils.py # 通用工具函数本文先以单文件为主,在文章后面会给出拆分建议。
3. 游戏核心机制拆解
3.1 游戏循环的三大步骤
几乎所有 Pygame 程序都遵循同一个循环结构:
- 处理事件:判断用户是否点击关闭窗口、是否按键。
- 更新状态:根据当前输入和时间,更新角色位置、障碍物位置、分数等变量。
- 绘制画面:把当前状态画到窗口上,然后刷新显示。
这个循环每秒会执行多次,具体次数由clock.tick(FPS)控制。本文设定FPS = 60,也就是每秒循环 60 次,这样可以保证在不同性能的电脑上,游戏速度基本一致。
3.2 帧率、速度与坐标系统
Pygame 的窗口坐标系以左上角为原点,x 轴向右增大,y 轴向下增大。在这个项目中:
- 猫咪的 x 坐标固定不变,保持在窗口左侧。
- 障碍物和食物的 x 坐标从窗口右侧不断减小,实现“向左移动”的视觉效果。
- 地面是一条水平线,草地位于窗口底部。
速度单位是“像素/帧”。比如障碍物每帧移动 5 像素,在 60 帧每秒的情况下,就是每秒移动 300 像素。速度的数值会影响游戏手感,这是后续调整难度时需要重点关注的参数。
3.3 跳跃、重力与碰撞检测
跳跃是最容易做崩的部分。一个简单的实现方式是:
- 给猫咪一个垂直速度变量
vy。 - 每次更新时,给
vy加上一个重力加速度gravity,然后让y坐标加上vy。 - 当
y到达地面高度时,把y拉回地面,并将vy归零。 - 玩家按下空格键时,如果猫咪在地面,就给
vy设置一个向上的初速度。
用物理的语言说,这就是每一帧做一次数值积分。代码里可以这样理解:
vy += gravity # 速度受重力影响 y += vy # 位置受速度影响跳跃初速度jump_power和重力gravity的比值,决定了跳跃高度和手感。初速度绝对值越大,跳得越高;重力越大,起跳和落地越快,手感越“重”。
碰撞检测使用pygame.Rect.colliderect(),本质是判断两个矩形是否有交集。每次更新后,把猫咪的矩形区域和所有障碍物的矩形区域做一次相交判断,如果相交,就触发游戏结束。
3.4 随机生成与难度递增
为了让每一局都不同,障碍物和食物的出现位置需要随机。本文用random.random()控制生成概率:有 70% 的概率生成障碍物,30% 的概率生成奖励食物。
难度递增通过“每隔一段时间加速”来实现。注意这里的速度不能无限增加,否则游戏会很快变得不可玩,所以我在代码里加了最大速度限制。
4. 完整实战:从零写一个可运行的猫咪狂奔小游戏
4.1 创建项目文件
新建一个文件夹cat_run,在里面创建main.py。完整代码如下,我会按功能模块拆分讲解。
4.2 初始化窗口与常量
这一部分负责导入依赖、定义窗口尺寸、颜色、字体等全局配置。
# 文件路径:cat_run/main.py import pygame import random import sys # 初始化 Pygame pygame.init() # 窗口尺寸 SCREEN_WIDTH = 800 SCREEN_HEIGHT = 400 GRASS_HEIGHT = 80 # 颜色常量(RGB) SKY_BLUE = (135, 206, 235) GRASS_GREEN = (124, 252, 0) DARK_GREEN = (34, 139, 34) BODY_WHITE = (240, 240, 240) EAR_BLACK = (30, 30, 30) EYE_BLACK = (20, 20, 20) NOSE_PINK = (255, 182, 193) OBSTACLE_RED = (178, 34, 34) FOOD_GOLD = (255, 215, 0) WHITE = (255, 255, 255) # 游戏帧率 FPS = 60 # 创建窗口和时钟 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("猫咪狂奔记 - Simon's Cat 风格跑酷") clock = pygame.time.Clock() # 字体,先尝试使用中文字体,找不到就退回默认字体 try: font = pygame.font.SysFont("simhei", 28, bold=True) except Exception: font = pygame.font.Font(None, 28)这段代码里有一个细节:pygame.font.SysFont("simhei", ...)在不同系统上可能找不到对应字体,所以用try-except做了一个回退。这样代码在 Windows、macOS、Linux 上都能正常运行。
4.3 实现猫咪角色类
Cat类负责猫咪的绘制、跳跃和地面检测。
class Cat: """猫咪角色:负责绘制、跳跃和地面检测。""" def __init__(self, x, y, width=60, height=50): self.x = x self.y = y self.width = width self.height = height self.vy = 0 self.on_ground = True self.jump_power = -14 self.gravity = 0.8 def jump(self): """在地面上时触发跳跃,给一个向上的初速度。""" if self.on_ground: self.vy = self.jump_power self.on_ground = False def update(self): """更新猫咪的垂直位置,并处理落地逻辑。""" self.vy += self.gravity self.y += self.vy ground_level = SCREEN_HEIGHT - GRASS_HEIGHT - self.height if self.y >= ground_level: self.y = ground_level self.vy = 0 self.on_ground = True def get_rect(self): """返回猫咪的矩形区域,用于碰撞检测。""" return pygame.Rect(self.x, self.y, self.width, self.height) def draw(self, surface): """在画面上绘制一只简化版猫咪。""" head_x = self.x + 10 head_y = self.y - 10 # 尾巴左右摆动 tail_sway = pygame.time.get_ticks() // 100 % 2 if tail_sway == 0: tail_points = [ (self.x + 55, self.y + 5), (self.x + 75, self.y - 5), (self.x + 80, self.y + 10), ] else: tail_points = [ (self.x + 55, self.y + 5), (self.x + 75, self.y + 15), (self.x + 80, self.y + 2), ] pygame.draw.lines(surface, EAR_BLACK, False, tail_points, 4) # 身体 body_rect = pygame.Rect(self.x, self.y, 52, 38) pygame.draw.rect(surface, BODY_WHITE, body_rect, border_radius=12) # 头 pygame.draw.circle(surface, BODY_WHITE, (head_x, head_y), 18) # 耳朵(两个黑色三角形) left_ear = [ (head_x - 16, head_y - 6), (head_x - 10, head_y - 22), (head_x - 2, head_y - 12), ] right_ear = [ (head_x + 2, head_y - 12), (head_x + 10, head_y - 22), (head_x + 16, head_y - 6), ] pygame.draw.polygon(surface, EAR_BLACK, left_ear) pygame.draw.polygon(surface, EAR_BLACK, right_ear) # 眼睛和鼻子 pygame.draw.circle(surface, EYE_BLACK, (head_x - 7, head_y - 2), 3) pygame.draw.circle(surface, EYE_BLACK, (head_x + 7, head_y - 2), 3) pygame.draw.circle(surface, NOSE_PINK, (head_x, head_y + 5), 3) # 胡须 pygame.draw.line(surface, EAR_BLACK, (head_x - 10, head_y + 4), (head_x - 22, head_y + 1), 1) pygame.draw.line(surface, EAR_BLACK, (head_x - 10, head_y + 6), (head_x - 22, head_y + 8), 1) pygame.draw.line(surface, EAR_BLACK, (head_x + 10, head_y + 4), (head_x + 22, head_y + 1), 1) pygame.draw.line(surface, EAR_BLACK, (head_x + 10, head_y + 6), (head_x + 22, head_y + 8), 1)jump_power为负数是因为 Pygame 的 y 轴向下,减小 y 坐标意味着向上移动。gravity为 0.8 表示每帧速度增加 0.8 像素/帧,配合 -14 的初速度,跳跃最高点大约为:
最高跳跃高度 = jump_power² / (2 * gravity) ≈ 14² / 1.6 ≈ 122 像素这个高度足够跳过 50 像素高的障碍物,同时也能吃到设置在高处的食物。
4.4 实现障碍物与食物
障碍物Obstacle类只有两个核心职责:向左移动和绘制自身。
class Obstacle: """障碍物,从右侧向左移动,形状类似栅栏或纸箱。""" def __init__(self, x, y, width=32, height=40, speed=5): self.rect = pygame.Rect(x, y, width, height) self.speed = speed self.max_speed = 15 self.passed = False def update(self): """向左移动障碍物。""" self.rect.x -= self.speed def draw(self, surface): """绘制障碍物,并添加白色条纹装饰。""" pygame.draw.rect(surface, OBSTACLE_RED, self.rect, border_radius=4) stripe1 = pygame.Rect(self.rect.x + 6, self.rect.y + 8, 5, self.rect.height - 16) stripe2 = pygame.Rect(self.rect.x + 20, self.rect.y + 8, 5, self.rect.height - 16) pygame.draw.rect(surface, WHITE, stripe1, border_radius=2) pygame.draw.rect(surface, WHITE, stripe2, border_radius=2)食物Food类画成一条金色小鱼。鱼的 x 坐标同样向左移动,玩家碰到后加分。
class Food: """食物(小鱼),拾取后加分。""" def __init__(self, x, y, radius=10, speed=5): self.radius = radius self.rect = pygame.Rect(x, y, radius * 2, radius * 2) self.speed = speed self.max_speed = 15 self.collected = False def update(self): """向左移动食物。""" self.rect.x -= self.speed def draw(self, surface): """绘制一条简化版小鱼。""" center_x = self.rect.x + self.radius center_y = self.rect.y + self.radius # 鱼身体 fish_body = pygame.Rect(center_x - 8, center_y - 5, 12, 10) pygame.draw.ellipse(surface, FOOD_GOLD, fish_body) # 鱼尾巴 tail = [ (center_x + 4, center_y), (center_x + 10, center_y - 6), (center_x + 10, center_y + 6), ] pygame.draw.polygon(surface, FOOD_GOLD, tail) # 鱼眼睛 pygame.draw.circle(surface, EYE_BLACK, (center_x - 4, center_y - 2), 2)这里需要注意,两个类的更新逻辑都是rect.x -= self.speed,即向左移动。passed字段接下来会在主循环中用来标记“已经越过的障碍物”,方便以后扩展得分逻辑。
4.5 绘制背景
为了让画面不那么单调,我用简洁的几何图形绘制了蓝天、草地和云朵。
def draw_background(surface): """绘制天空、草地和装饰性云朵。""" surface.fill(SKY_BLUE) # 三朵云 clouds = [(120, 60), (400, 100), (650, 50)] for cloud_x, cloud_y in clouds: pygame.draw.circle(surface, WHITE, (cloud_x, cloud_y), 20) pygame.draw.circle(surface, WHITE, (cloud_x + 22, cloud_y - 8), 16) pygame.draw.circle(surface, WHITE, (cloud_x + 44, cloud_y), 18) pygame.draw.rect(surface, WHITE, (cloud_x + 8, cloud_y - 8, 36, 18)) # 草地 grass_rect = pygame.Rect(0, SCREEN_HEIGHT - GRASS_HEIGHT, SCREEN_WIDTH, GRASS_HEIGHT) pygame.draw.rect(surface, GRASS_GREEN, grass_rect) # 小草装饰 for i in range(0, SCREEN_WIDTH, 40): blade_y = SCREEN_HEIGHT - GRASS_HEIGHT pygame.draw.line(surface, DARK_GREEN, (i, blade_y), (i + 4, blade_y - 10), 2)这段代码每次填充整个窗口再绘制,对 800x400 的小窗口来说性能完全没问题。如果以后窗口做得很大,再考虑只刷新发生变化的部分。
4.6 主循环与游戏逻辑
主函数把前面的模块串起来,处理事件、生成物体、检测碰撞、绘制画面。
def main(): cat = Cat(80, SCREEN_HEIGHT - GRASS_HEIGHT - 50) obstacles = [] foods = [] score = 0 game_over = False spawn_timer = 0 speedup_timer = 0 running = True while running: clock.tick(FPS) # 1. 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: if game_over: # 重新开始 cat = Cat(80, SCREEN_HEIGHT - GRASS_HEIGHT - 50) obstacles.clear() foods.clear() score = 0 game_over = False else: cat.jump() if not game_over: # 2. 更新状态 cat.update() # 按一定节奏生成障碍物或食物 spawn_timer += 1 if spawn_timer > 70: spawn_timer = 0 if random.random() < 0.7: obstacle_h = random.choice([36, 44, 52]) obstacle_y = SCREEN_HEIGHT - GRASS_HEIGHT - obstacle_h obstacles.append( Obstacle(SCREEN_WIDTH + 20, obstacle_y, 32, obstacle_h) ) else: # 食物放在高处,需要跳跃才能吃到 food_y = SCREEN_HEIGHT - GRASS_HEIGHT - 100 foods.append(Food(SCREEN_WIDTH + 20, food_y, 10)) # 更新障碍物并移出屏幕 for obstacle in obstacles[:]: obstacle.update() if obstacle.rect.right < 0: obstacles.remove(obstacle) elif not obstacle.passed and obstacle.rect.right < cat.x: obstacle.passed = True # 更新食物并检测拾取 for food in foods[:]: food.update() if food.rect.right < 0: foods.remove(food) elif cat.get_rect().colliderect(food.rect): foods.remove(food) score += 10 # 碰撞检测 cat_rect = cat.get_rect() for obstacle in obstacles: if cat_rect.colliderect(obstacle.rect): game_over = True break # 难度递增,限制最大速度 speedup_timer += 1 if speedup_timer > 120: speedup_timer = 0 for obstacle in obstacles: if obstacle.speed < obstacle.max_speed: obstacle.speed += 1 for food in foods: if food.speed < food.max_speed: food.speed += 1 # 3. 绘制画面 draw_background(screen) for obstacle in obstacles: obstacle.draw(screen) for food in foods: food.draw(screen) cat.draw(screen) score_surface = font.render(f"得分: {score}", True, EYE_BLACK) screen.blit(score_surface, (10, 10)) if game_over: over_surface = font.render("游戏结束!按空格键重新开始", True, OBSTACLE_RED) over_rect = over_surface.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)) screen.blit(over_surface, over_rect) pygame.display.flip() pygame.quit() sys.exit() if __name__ == "__main__": main()主循环中值得注意的几个点:
for obstacle in obstacles[:]这种写法是遍历列表的副本,这样可以在循环过程中安全地执行remove。- 食物生成在
SCREEN_HEIGHT - GRASS_HEIGHT - 100这个高度,也就是猫咪跳跃后才能碰到,避免玩家在地面上白捡分。 - 碰撞检测是在所有物体更新完成之后进行的,保证每一帧用的是最新位置。
- 重新开始功能只重置角色、障碍物、食物和分数这几个关键变量,窗口和字体不用重建。
4.7 运行与验证
运行完整代码:
python main.py预期效果:
- 窗口标题显示“猫咪狂奔记 - Simon's Cat 风格跑酷”。
- 背景是蓝天、白云、草地。
- 一只白色身体、黑色耳朵和尾巴的小猫站在窗口左侧。
- 障碍物从右侧不断出现并向左移动。
- 按下空格键猫咪起跳,落到草地上。
- 碰到小鱼得分加 10 分,碰到障碍物游戏结束并显示提示文字。
- 等待几秒后,障碍物移动速度明显变快。
如果你能顺利看到这些表现,说明整个游戏的核心逻辑已经跑通了。
5. 常见问题与排查思路
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
pip install pygame失败 | 网络原因或 Python 版本不兼容 | 使用国内镜像源安装;确认 Python 版本为 3.8+ |
报错unexpected keyword argument 'border_radius' | Pygame 版本低于 2.0 | 升级 Pygame 到 2.x,或删除所有border_radius参数 |
| 窗口闪退 | 代码缩进错误或事件循环没有正确运行 | 检查缩进;确认在while running中处理了pygame.QUIT事件 |
| 猫咪落到窗口底部以下 | 地面检测逻辑没触发 | 检查ground_level的计算公式,确保y >= ground_level时重置位置 |
| 跳跃没有反应 | 键盘事件没有捕获,或on_ground一直是 False | 在事件循环中确认打印event.key;确认落地后on_ground被设为 True |
| 中文文字显示为方块 | 系统找不到指定中文字体simhei | 改用pygame.font.Font(None, 28),或传入本地字体文件路径 |
| 游戏速度在不同电脑上差别大 | 没有控制帧率 | 确保主循环第一行执行clock.tick(FPS) |
| 性能低,画面卡顿 | 每帧创建过多 Surface 对象 | 把静态文字和背景提前渲染好,避免每帧重建 |
如果遇到“游戏结束后按空格无法重新开始”,多半是事件处理里把game_over和普通跳跃判断写在了同一个分支之外。建议在事件处理里先用if event.key == pygame.K_SPACE:统一捕获空格键,再根据game_over决定是重置游戏还是触发跳跃。
6. 最佳实践与工程建议
6.1 代码组织与命名规范
单文件示例适合学习,但真实项目建议拆分模块。一个比较清晰的拆分方式如下:
config.py:保存窗口尺寸、颜色、速度等常量。sprites.py:统一管理所有游戏物体的类。main.py:只负责游戏循环和事件分发。
命名方面,类名使用大驼峰,如Cat、Obstacle;函数和变量使用小写下划线,如draw_background、game_over。颜色常量统一用大写字母加下划线,方便复用。
6.2 性能优化建议
这个项目体量很小,一般来说不会遇到性能瓶颈,但以下几个习惯值得养成:
- 不要在
draw()方法里重复调用pygame.font.Font(...),字体对象最好只创建一次。 - 背景如果不是动态变化的,可以提前渲染到一个
Surface,每帧直接blit上去。 - 删除对象时优先使用
remove而不是del,避免遍历过程中修改列表导致的迭代异常。 - 如果游戏物体数量很大,可以把障碍物和食物分到两个列表,避免每帧遍历所有对象做无用的碰撞检测。
6.3 玩法与交互优化
从“能玩”到“好玩”之间,可以优化几个点:
- 跳跃手感。调整
jump_power和gravity的数值,让跳跃更轻盈或更沉重。 - 蓄力跳跃。长按空格时跳得更高,增加操作深度。
- 双段跳。给猫咪额外一次空中跳跃的机会,降低新手门槛。
- 碰撞宽容度。把碰撞盒略微缩小,不要用整个猫咪矩形做检测,让玩家感觉更公平。
6.4 后续扩展方向
完成基础版本之后,可以按下面的方向继续加功能:
- 引入图片素材。把几何绘制改为加载 PNG 序列帧,提升画面表现力。
- 添加音效。用
pygame.mixer播放跳跃、得分、撞击音效。 - 制作开始界面。增加标题、操作说明和最高分展示。
- 增加多场景。随分数切换草地、夜晚、雨天等不同背景。
- 数据持久化。把最高分写入本地文件或 SQLite,方便后续做排行榜。
- 控制方式扩展。支持鼠标点击跳跃、手机触屏虚拟按键等。
每加一个功能之前,先想清楚它到底是让游戏更有趣,还是让玩家更容易疲惫。跑酷游戏的本质是节奏感,新增功能最好服务于节奏而不是堆砌内容。
7. 总结与学习路线
到这里,“猫咪狂奔记”小游戏已经完整落地了。回顾一下,我们从 Simon's Cat 这个题材出发,梳理了 2D 跑酷游戏的核心机制,然后用 Pygame 实现了窗口、绘制、键盘事件、重力跳跃、碰撞检测、随机生成和难度递增。整个流程虽然代码量不大,但覆盖了游戏开发最常见的链路。
建议你接下来不要急着继续加功能,而是先做三件小事:
- 把
jump_power改成 -16、-18,感受跳跃高度变化对游戏难度的影响。 - 把障碍物生成概率从 0.7 改成 0.5,看看得分难度如何变化。
- 把猫咪的颜色从白色改成灰色,再自己加一副眼镜或领结,锻炼绘制坐标的感觉。
拿着这份代码多改几轮,你对 Pygame 事件、碰撞和物理模拟的理解就会明显比“照着敲一遍”更深一层。跑酷游戏看似简单,但想把跳跃手感打磨舒服,里面可以研究的细节其实非常多。希望这篇教程能给你一个不错的起点。