第一次做3D跑酷,我用的是Scratch,屏幕上那条不断向下滚的跑道,其实是十几个克隆体在轮流换位演出来的。后来觉得不过瘾,想加真实的透视、想稳住60帧、想让画面有纵深明暗,我就用Python重写了一遍。两个版本并排放着跑,我才发现从Scratch到Python根本不是"换一门语言"这么轻松,而是整套坐标思维、渲染思路和调试方法的重建。这篇就聊聊我这两版3D跑酷是怎么落地的:Scratch版怎么用克隆体装出三维感,Python版怎么从零搭起一个能跑的游戏循环,两边的核心机制怎么互相迁移,以及那些文档里不会写、只有真跑过才知道的坑。不管你是刚学完Scratch顺序分支循环的新手,还是已经能折腾Python基础语法、正想找个项目练手的同学,应该都能从里面抠出点能直接抄的东西。
1. 为什么同一款3D跑酷,我要写两个版本
1.1 Scratch能做出的3D,本质是"算出来的假象"
很多人对Scratch的印象还停留在贪吃蛇、九九乘法表、冒泡排序这些二维小项目上,觉得它做不了3D。其实这个判断对一半。Scratch的舞台本身只有x和y两个坐标轴,没有真正的z轴和相机,所以它永远画不出真实的三维模型。但3D跑酷这种游戏有个特殊性:它的场景是高度规则的——一条直路,两侧是墙或者护栏,障碍物沿着路排布,镜头永远朝前。这种场景用"伪3D投影"就能骗过眼睛,而且骗得很好。
所谓伪3D,就是我在脑子里维护一套虚构的三维坐标(x左右、y上下、z前后),每一帧把这些三维点用公式换算成舞台上的二维屏幕坐标。近的东西放大、往屏幕下方和两侧推,远的东西缩小、往屏幕中心收,透视感就出来了。Scratch负责的只是最后那一步"把算出来的二维坐标画出来",真正的三维运算全靠变量和运算积木硬算。这也是为什么Scratch版的学习价值特别高:它逼着你把3D投影的数学亲手推一遍,而不是调个引擎函数就完事。等你以后真的用上三维引擎,会发现自己对相机、焦距、深度这些概念的理解,比直接上手引擎的人扎实得多。
1.2 Python补上的三块短板
转到Python之后,最直观的变化是三个:性能、渲染能力和工程化。性能上,Scratch每一帧的克隆体数量、运算复杂度都有隐形上限,跑道段一多、障碍物一密,帧率就往下掉,画面开始卡顿撕裂。Python这边配合pygame或者GPU渲染,几百个多边形、上千个粒子都能稳在60帧,跑酷的速度感才能拉满。
渲染能力上,Scratch只能画矢量精灵和简单图形,做不了实时的光照、雾效、动态阴影。Python里哪怕是用pygame这种偏向二维的库,也能靠手写多边形填充和透明度做出渐变雾效;如果换成基于Panda3D的Ursina引擎,那直接就是真三维,模型、材质、光照都是现成的。工程化上,Scratch项目一复杂就变成一堆积木缠在一起,改一个逻辑要翻半天;Python有模块、有类、有版本管理,代码可以拆成 camera.py、road.py、player.py,谁改哪儿一目了然。这三块补上之后,我才敢往游戏里加真正的玩法深度。
1.3 两条路线到底该怎么选
这里给一个我自己的判断标准,避免你纠结。如果你是想理解3D背后的原理、想用最低门槛快速出效果、想给小孩或者零基础的朋友演示,那Scratch版是更好的起点,它的反馈快、调试直观,积木拖错了马上能看见。如果你的目标是把游戏做成一个能持续迭代、能发布分发、能加复杂玩法的作品,或者你想借这个项目把Python的类、循环、事件、时间步进练熟,那就走Python路线。
需要说明的是,这两条路不是替代关系。我现在的习惯是先用Scratch把玩法和数值调爽,确认手感对了,再把逻辑一比一翻译到Python里。这样能省掉大量"在Python里反复改参数、反复重启"的时间,因为Scratch改一个变量的值只用点两下。下面第2章和第3章,我就分别拆解这两版的实现。
2. Scratch版3D跑酷:克隆体加伪3D投影
2.1 舞台坐标系与"假三维"的换算公式
先把基础坐标搞清楚。Scratch舞台宽480、高360,中心点是(0,0),x范围是-240到240,y范围是-180到180。我要虚构一套三维世界:物体有worldX(左右偏移)、worldY(离地高度)、worldZ(离相机的距离)。相机默认放在worldZ等于0的位置,朝worldZ增大的方向看。
核心换算只有三行。设焦距F是一个常数,比如300(你可以理解成镜头到画面的距离,值越大画面越平、越小透视越夸张)。对每个三维点,先算相对深度 dz = worldZ - camZ,如果dz小于一个很小的值就说明这个点在相机后面,直接不画。然后是缩放比 scale = F / dz。最后落到屏幕坐标:屏幕x = worldX × scale,屏幕y = worldY × scale 再加上一个地平线偏移。这套公式和Python版是一模一样的,只是写法不同,你在Scratch里用运算积木拼出来即可,把F、camZ、scale都设成全局变量,方便后面调。
提示:F这个值强烈建议边拖边看。F设小了,跑道近处会撑满屏幕、远处缩成一个点,透视很猛但容易晕;F设大了整个画面像压扁了,速度感全无。我最后稳定在300到360之间,配合跑道宽度用。
2.2 跑道分段与克隆体的滚动复用
Scratch里没法一次画一整条无限长的路,我的做法是把路切成若干段,用克隆体来表示每一段,跑过去的段就回收重用。具体来说,新建一个"跑道段"角色,造型就是一个横向的梯形或者矩形,给它一个私有变量myZ表示这段离相机多远。克隆体生成的时候,让myZ等于"序号 × 段长",比如段长取0.8,第0段myZ=0,第1段myZ=0.8,依次往后。
每一帧要做的是让所有段的myZ都减去"本帧前进的距离"。这里有个关键技巧:Scratch虽然不直接给你每帧时间,但可以用计时器积木做出时间步长。做法是新建变量上一帧时间和dt,循环开头先dt = 计时器 - 上一帧时间,再上一帧时间 = 计时器。这样dt就是这一帧真实过去的时间秒数,用速度 × dt去移动所有段,帧率高低游戏速度都一致,不会因为电脑卡一下玩家角色就瞬移。
每个克隆体更新画面时,先算出它相对相机的深度,跑一遍2.1里的缩放公式得到屏幕y和缩放比,然后将大小设为(基础大小 × scale)、移到x: 0 y: 算出来的屏幕y。当某段的myZ跑到相机后面(比如小于0.2),就把它重新放回最远处,形成无限循环的跑道。这样只要十几个克隆体,就能造出一条看起来永无止境的路。
2.3 障碍生成、图层排序与碰撞判定
障碍物我复用了同一套投影逻辑。每隔一段时间在远处的随机车道(左、中、右三条)生成一个障碍克隆体,给它myZ和车道x两个私有变量。每帧对它做投影,算出屏幕坐标和缩放比,同时根据缩放比调整大小,这样它从远处小点逐渐变大冲到眼前,视觉上就对了。
这里有个Scratch特有的难点:图层排序。Scratch没有"设置图层号"的积木,只有移到最前面和移到最后面。伪3D场景里,近的物体必须盖住远的物体,否则会出现远处障碍压在近处路面上这种穿帮。我的解决办法是每一帧先按myZ从大到小(也就是从远到近)把跑道段和障碍物排序,然后依次执行移到最前面。因为后执行的在更前面,所以最近的最后移到最前,图层自然正确。排序用简单的插入排序写在循环里就行,数量不多,开销可以接受。
碰撞判定我不建议直接用碰到角色积木,因为它是按精灵轮廓判定的,缩放之后误差很大,经常"看着没碰到却判定撞了"。更稳的做法是自己在三维空间里做矩形判定:玩家固定在某条车道上、在一个固定的worldZ位置,当某个障碍的myZ逼近这个位置、且车道相同、且玩家此时不在跳跃高度之上,就算碰撞。这种"自己算"的判定虽然要多写几行,但行为完全可控,不会有莫名其妙的判定。
2.4 用亮度特效应造出纵深和速度感
Scratch的外观积木里有个亮度特效,量程是-100到100,负值让角色变黑,正值变白。这个本来是用在角色明暗上的功能,被我拿来做了雾效:越远的跑道段和障碍物,亮度越接近-100(发黑),越近越接近0。具体可以设成亮度 = -100 × (myZ / 最大可视深度),再夹紧到-100到0之间。这样一来,远处的路自然溶进背景色里,画面就有了空气透视,纵深感比单纯靠缩放强得多。
速度感还靠另外两个小手段。一是让路面上的纹理或者车道线随速度滚动,因为跑道段本身就是滚动的,把段上的造型做成"一段路面加一道横向条纹",滚动起来视觉参考点就很明确。二是加一点点屏幕抖动或者相机的轻微上下浮动,高速时幅度大一点,但别过头,不然会晕。我试过给跑道两侧加"飞驰而过的灯柱"克隆体,那个奔跑的爽感提升非常明显,成本却很低。
3. Python版3D跑酷:从环境到渲染循环
3.1 Python安装与开发环境配置的完整流程
先说环境,这一块是新手最容易卡住的地方,我把整套流程写清楚。到Python官网下载安装包,注意安装界面底部那个"Add Python to PATH"一定要勾上,不勾的话后面在命令行里敲python会提示找不到命令。装完之后打开终端,输入python --version能打印出版本号就说明装好了。
接着是虚拟环境,这是很多人跳过、后面却吃大亏的一步。不同项目的依赖版本会打架,我习惯每个项目单独建一个。进入项目文件夹,执行下面几条命令:
# 创建虚拟环境,会生成一个 .venv 文件夹 python -m venv .venv # Windows 激活 .venv\Scripts\activate # macOS / Linux 激活 source .venv/bin/activate # 安装本项目的依赖 pip install pygame编辑器我用VSCode和PyCharm都试过。VSCode的话,装官方的Python扩展,然后按Ctrl+Shift+P搜"Python: Select Interpreter",选中刚才.venv里的解释器,这样它才知道用哪个环境跑代码。PyCharm则在新建项目时直接指定解释器为已有的虚拟环境,配好之后它会自动识别依赖。两边的坑都集中在"解释器选错了",表现是代码里import报红、运行报ModuleNotFoundError,排查时先看右下角或者设置里的解释器路径对不对。
注意:如果装完之后
pip命令用不了,可以改用python -m pip install pygame这种写法,能绕开绝大多数PATH问题。Linux上如果报权限错误,不要用sudo去装到系统里,建虚拟环境才是正路。
3.2 渲染方案选型:pygame还是Ursina
Python里做3D跑酷有两条明显不同的路,我把对比列出来,方便你按目标挑。
| 方案 | 本质 | 上手难度 | 画面上限 | 适合场景 |
|---|---|---|---|---|
| pygame | 二维库,手写伪3D投影 | 中等 | 中,靠多边形和雾效 | 想亲手搞懂3D原理、追求轻量 |
| Ursina | 封装Panda3D的真三维引擎 | 较低 | 高,支持模型光照 | 想快速出真3D效果、加复杂关卡 |
我这次的Python版选的是pygame。原因很直接:我前面在Scratch里已经把伪3D投影的公式推熟了,换成pygame其实是同一套公式换语言,能一比一迁移,学习连续性最好。而且pygame轻量,启动快,打包出来的体积也小。如果你完全没碰过投影、又想让画面直接是模型和光照,那Ursina更省事,几行代码就能加载模型、加相机、加灯光,但你会跳过三维投影这一课。两种都行,看你想要"理解"还是"快速出效果"。
3.3 相机模型与三维投影函数的实现
pygame版的核心就是我写的一个投影函数,它和Scratch里的缩放公式完全一致。先定义常量:
import pygame W, H = 960, 600 HALF_W, HALF_H = W // 2, H // 2 FOV = 500 # 焦距,越大透视越平缓 CAM_HEIGHT = 1.6 # 相机离地高度,世界单位 ROAD_W = 3.2 # 路面半宽 LANE_X = (-1.9, 0.0, 1.9) # 三条车道的中心x投影函数接收一个世界坐标点和相机,返回屏幕坐标和缩放比。这里我统一约定y轴向上为正、地面在y等于0:
def project(x, y, z, cam): dz = z - cam.z # 相对深度 if dz < 0.2: # 在相机后方或太近,不画 return None scale = FOV / dz # 透视缩放比 sx = HALF_W + (x - cam.x) * scale sy = HALF_H - (y - CAM_HEIGHT) * scale return sx, sy, scale跑道的画法是把路面切成若干纵向的段,每段用左右两条边界线投影出四个顶点,然后pygame.draw.polygon填充成一个四边形。为了让路面有纵深感,我按段离相机的远近给每段设置不同的亮度,远的暗、近的亮,用颜色数值插值实现,这就是pygame版的"雾效",对应Scratch里的亮度特效。
def draw_road(screen, cam, seg_len=1.2, seg_count=40): for i in range(seg_count): z_near = cam.z + i * seg_len z_far = z_near + seg_len # 每段四个角:左右 × 近远 corners = [] for z in (z_near, z_far): left = project(-ROAD_W, 0, z, cam) right = project(ROAD_W, 0, z, cam) if left is None or right is None: corners = [] break corners.append(left) corners.append(right) if len(corners) == 4: # 越远越暗,模拟空气透视 depth_ratio = min(i / seg_count, 1.0) shade = int(200 - 150 * depth_ratio) color = (shade, shade, shade + 20) poly = [(corners[0][0], corners[0][1]), (corners[1][0], corners[1][1]), (corners[3][0], corners[3][1]), (corners[2][0], corners[2][1])] pygame.draw.polygon(screen, color, poly)相机我是这样处理的:cam.z随玩家前进不断增大,cam.x平滑地追上玩家所在的x,做出跟车效果。这里必须用平滑跟随而不是硬跟随,硬跟随画面会随着切车道而剧烈横跳,很晕。我用的是一阶插值:cam.x += (target_x - cam.x) * 0.15,这个系数0.15是调出来的,太大会抖、太小会粘。
3.4 游戏主循环、障碍生成与跳跃手感
主循环是Python版的骨架,时间步进和Scratch版一个思路——用真实的时间差驱动一切。pygame里用clock.tick(60)来限制帧率,它返回距上一帧的毫秒数,除以1000就是秒:
import random, sys pygame.init() screen = pygame.display.set_mode((W, H)) clock = pygame.time.Clock() class Cam: def __init__(self): self.x = 0.0 self.z = 0.0 class Player: def __init__(self): self.lane = 1 # 初始在中间车道 self.y = 0.0 # 离地高度 self.vy = 0.0 self.alive = True class Obstacle: def __init__(self, z, lane): self.z = z self.lane = lane cam, player = Cam(), Player() obstacles = [] speed = 8.0 # 前进速度,世界单位每秒 gravity = -26.0 # 重力加速度 jump_v = 9.5 # 起跳初速度 spawn_timer = 0.0 running = True while running: dt = clock.tick(60) / 1000.0 for e in pygame.event.get(): if e.type == pygame.QUIT: running = False if e.type == pygame.KEYDOWN and player.alive: if e.key in (pygame.K_LEFT, pygame.K_a): player.lane = max(0, player.lane - 1) if e.key in (pygame.K_RIGHT, pygame.K_d): player.lane = min(2, player.lane + 1) if e.key in (pygame.K_SPACE, pygame.K_UP) and player.y <= 0.001: player.vy = jump_v # 前进 + 相机跟随 cam.z += speed * dt cam.x += (LANE_X[player.lane] - cam.x) * 0.15 # 跳跃物理 player.vy += gravity * dt player.y += player.vy * dt if player.y < 0: player.y = 0 player.vy = 0 # 障碍生成:时间越久越密 spawn_timer -= dt if spawn_timer <= 0: spawn_timer = max(0.45, 1.1 - cam.z * 0.002) obstacles.append(Obstacle(cam.z + 42.0, random.randint(0, 2))) # 障碍推进与回收 for ob in obstacles: pass # 碰撞:玩家在相机前方固定距离处 player_z = cam.z + 4.0 for ob in obstacles: if abs(ob.z - player_z) < 0.9 and ob.lane == player.lane and player.y < 1.2: player.alive = False obstacles = [ob for ob in obstacles if ob.z > cam.z] # 回收跑过去的 screen.fill((18, 18, 26)) draw_road(screen, cam) # 障碍与玩家绘制(略,逻辑同上投影) pygame.display.flip() pygame.quit() sys.exit()上面这段是能直接跑起来的骨架,障碍和玩家的绘制我省了,逻辑就是调project拿到屏幕坐标后画矩形或贴图。这里重点讲几个手感参数的来由。重力取-26、跳跃初速度取9.5,是我反复试出来的:跳跃总时长大约是2×9.5/26 ≈ 0.73秒,能跨过约0.73秒内前进的距离,配合障碍间距刚好够闪避。如果重力太小,角色会飘,手感发飘像在月球;重力太大则跳跃断得太快,玩家来不及反应。速度speed=8配合障碍生成间隔,前期1.1秒一个、后期最快0.45秒一个,难度曲线是随距离平滑上升的,这个公式max(0.45, 1.1 - cam.z * 0.002)比"每隔固定距离加难度"要顺滑。
提示:碰撞判定里我用
player.y < 1.2来判断"没跳过障碍高度"。这个1.2就是障碍物的高度,你调障碍模型高度时一定要同步改这个值,否则会出现"明明跳过去了却撞上"或者"贴着障碍穿过去"两种极端,这是新手最常见的bug。
3.5 帧率稳定、打包与分发
跑起来之后,第二步是让它"稳"。开放世界游戏最怕掉帧,跑酷这种高速游戏尤其明显。我做了两件事:一是所有运动都用dt驱动,绝不在循环里写"每帧移动固定距离",这样60帧和144帧的机器上速度一致;二是障碍物列表做了回收,跑过相机的即时删掉,避免列表无限增长导致越来越卡。这两条看着简单,但很多我见过的练手项目都栽在上面,跑五分钟就开始一顿一顿。
想把游戏发给别人玩,用PyInstaller打包最省事:
pip install pyinstaller pyinstaller -F -w game.py-F是打包成单个可执行文件,-w是运行时不弹命令行窗口。打完在dist文件夹里就是成品。要注意如果你用了外部图片、音效文件,得用--add-data把它们一起打进去,否则别人运行会报找不到资源。我第一版忘了这茬,发出去朋友一打开就黑屏,排查了半天才发现是打包没带资源。
4. 两版核心机制怎么互相迁移
4.1 Scratch与Python概念对照表
把Scratch版翻成Python版的时候,我整理了一张对照表,能省大量找对应关系的时间。核心思想是:两边其实都在做同一件事,只是工具不同。
| 功能 | Scratch做法 | Python做法 |
|---|---|---|
| 三维投影 | 变量+运算积木拼公式 | project()函数返回屏幕坐标 |
| 无限跑道 | 克隆体回收重用 | 按z分段绘制,越界即不画 |
| 图层排序 | 移到最前面按远近顺序执行 | 绘制顺序天然就是图层顺序 |
| 帧率无关运动 | 计时器差值算dt | clock.tick(60)返回毫秒 |
| 雾效/纵深 | 亮度特效调负值 | 颜色数值随深度插值变暗 |
| 碰撞检测 | 自己算矩形范围 | 世界坐标AABB判定 |
| 相机跟随 | 移动所有物体反向模拟 | cam.x平滑追逐玩家x |
看懂这张表你会发现,真正变的是"实现手段",不变的是"游戏逻辑本身"。跑酷的核心就三条:前进、变道、闪避,任何语言里都是这三件事。
4.2 手感调参:速度、加速度和跳跃曲线
不管哪个版本,跑酷好不好玩,七成看手感,三成看画面。我把调参经验集中说一下。第一是速度曲线,不要一上来就是最高速,玩家需要时间进入状态。我的做法是把速度随时间缓慢上升,Scratch里用速度 = 基础速度 + 已跑距离 × 系数,Python里同理,让玩家在不知不觉中越跑越快,刺激感就来了。
第二是变道的过渡,绝对不能瞬间横移。Scratch里是让x坐标在一两帧内插值过去,Python里就是前面说的cam.x平滑跟随再加玩家自身的插值。这里有个细节:玩家视觉上的横向位置其实可以固定,靠相机平移来制造"切车道"的感觉,这样画面更稳,因为动的是世界而不是角色,这也是很多赛车游戏的标准做法。
第三是跳跃曲线的形状。直线上升下降的跳跃是没灵魂的,要做出"跳起慢、下落快"的重力感,就得让竖直速度被重力持续削减。这套物理在Scratch里用变量vy和每帧vy = vy + 重力 × dt、y = y + vy × dt就能实现,和Python里一模一样。重力取负值,起跳时给vy一个正初速度,曲线自然就对了。
4.3 常见坑与排查速查表
下面这张表是我两版加起来踩过的坑,按现象和原因整理,遇到问题可以直接对号入座。
| 现象 | 大概率原因 | 解决方向 |
|---|---|---|
| 远处物体压住近处物体 | 图层/绘制顺序不对 | Scratch按远到近移到最前,Python调整绘制顺序 |
| 电脑一卡角色瞬移 | 没做帧率补偿 | 引入dt,所有位移乘dt |
| 碰撞判定忽灵忽不灵 | 用精灵轮廓判定 | 改自己算的矩形/世界坐标判定 |
| 跑一会儿变卡 | 克隆体/列表没回收 | 越界对象及时重置或删除 |
| 画面晕 | 相机硬跟随或透视过猛 | 相机平滑插值、调大焦距F |
| 打包后黑屏 | 资源文件没打包进去 | PyInstaller加--add-data |
| 跳跃感觉飘 | 重力太小 | 增大重力绝对值、同步调初速度 |
我在Scratch里还遇到过一个更隐蔽的问题:克隆体数量超过一定值后,某些克隆体的初始化脚本会延迟执行,表现为跑道偶尔缺一段。解决办法是别在"当作为克隆体启动时"里做复杂运算,只做最简单的变量赋值,把重活放到主循环里按状态处理。这个坑文档里不会写,纯粹是跑多了才发现的。
5. 常见问题与排查技巧实录
5.1 Scratch侧:克隆体的初始化顺序陷阱
Scratch的克隆体有个很容易被忽略的行为:当你一次性生成很多克隆体时,它们的"启动脚本"执行顺序是不确定的,而且如果在启动脚本里还去读取全局变量,很可能读到的是别的克隆体改过的值。我最早的跑道版本就因为这个,偶尔出现某一段跳到了错误的高度上,画面闪一下。
我的处理办法是把克隆体当成"笨工人":每个克隆体启动时只做两件事——把自己编号记下来、把自己放到初始位置,其他所有逻辑全部交给一个统一的主循环去遍历处理。主循环里按编号从小到大依次更新每段的位置,顺序完全确定,就不会有随机跳变。这个"把复杂的初始化踢给主循环"的思路,在Python里其实就是"先创建对象,再在update里统一驱动"的模式,两边是通的。另外提醒一句,Scratch里遍历克隆体最好用一个存编号的列表来管理,别指望当作为克隆体启动时能保证顺序。
5.2 Python侧:ModuleNotFoundError和解释器错位
Python新手最常见的报错就是ModuleNotFoundError: No module named 'pygame'。这个报错九成不是你没装,而是"装的解释器"和"跑的解释器"不是同一个。你系统里可能有好几个Python:官网装的那个、系统自带的那个、某个软件捆绑的那个。你在虚拟环境里pip装了pygame,但编辑器里用的是系统解释器,那自然找不到。
排查步骤很固定:在终端里执行python -c "import sys; print(sys.executable)",看它打印的路径是不是你项目里的.venv;再在编辑器里确认选的解释器路径和它一致。一致了还报错,就执行python -m pip list看pygame在不在列表里,不在就重装。这套流程我写成了习惯,基本三分钟能定位所有"环境类"问题。如果你把Python装在Linux上,记得别用系统级的pip去污染全局环境,虚拟环境永远是首选。
5.3 一个通用的调试套路,两版都适用
最后分享我调这类游戏的一个通用方法:把游戏拆成"输入、更新、渲染"三层,哪一层出问题就单独测哪一层。输入层就是键盘事件,我习惯在改逻辑前先在屏幕上把按键状态打出来看,确认按键被识别了。更新层是物理和逻辑,我会临时画一些调试线——比如在Scratch里用画笔画一条表示玩家碰撞范围的红线,在Python里用pygame.draw.rect画出玩家的碰撞盒,肉眼确认范围和位置对不对。渲染层出问题通常是投影公式写错,这时候把相机参数固定成一组已知值,拿笔在纸上算一遍某个点的屏幕坐标,和程序算出来的对比,差在哪儿一眼就看出来了。
这个调试套路的好处是,它和语言无关。Scratch里能用的"固定参数+手算校验",Python里照样能用,反过来Python里那套"打印中间变量"的做法,在Scratch里换成把变量显示在舞台上,效果一样。我从Scratch换到Python最省时间的地方,就是这套方法论可以直接搬。
两个版本我都留着,Scratch那版当教学demo,Python那版当持续迭代的主力。如果你手头正好也有个跑酷的点子,我建议先把Scratch版跑通,把跑道、障碍、跳跃这三件事的手感在一两天内调爽,再动手写Python。反过来一上来就啃Python和三维投影,很容易卡在环境配置或者某个投影公式上,热情一半就耗没了。真要给个最小起步点:Scratch先做出十个克隆体拼的滚动跑道,Python先把project函数写出来并画对一条路,这两步迈过去,剩下的都是水到渠成的事。