你好,我是吴老师。
前面的课,我们画的东西都很听话,也很安静——安静到一动不动。
今天给它们加一样东西:动起来。
先给你打个预防针:今天真正拦住你的,不是"画",是擦。你马上就会看到。
读完之后,你应该能:说出"只画不擦"为什么会拖出一条线;用"先盖掉旧的、再画新的"做出干净的动画;解释"一帧"是什么;独立做出一个撞墙会反弹的弹球。
用时:约 60 分钟。准备:板子、数据线、电脑上装好 Python 和 pyserial。
看不懂的地方,整段复制给 AI,加一句"请一次只解释一个概念,讲完问我一个小问题"。
一、先做一个"会失败"的实验
我们要做一件听起来很简单的事:让一个方块从屏幕左边跑到右边。
你会怎么做?我猜大多数同学会这么说:"每隔一小会儿,把它往右画一点点。"
很好,我们就照这个做。
请帮我做一个屏幕动画实验:
在屏幕上画一个边长 14 的黄色方块,
每一小段时间把它的横坐标加 2,然后在新的位置再画一个同样的方块。
从屏幕最左边一直画到最右边。
请用中文注释,别动原来的文件。
改完让 AI 帮你装上板子 —— 它会自己打开,你不用去桌面上找它。
现在请你老实回答我一个问题:
你看到的是一个方块在移动,还是一整条黄色的粗线?
如果你的程序做对了,你看到的是一条线。
先别改。把这个画面记住,它是今天最值钱的一幕。
二、为什么会拖出一条尾巴
我们停下来想一想。
你让板子在第 10 列画了个方块,下一小会儿又让它到第 11 列画一个。那第 10 列那个呢?
答案是:它还好好地在那儿。
屏幕不会自己清除任何东西。 你画上去的点就待在那里,直到你用别的颜色把它盖掉。屏幕里既没有"橡皮擦"这个零件,也没有"上一帧"这种记忆——它只记得每个点现在是什么颜色。
所以你画了一百次,屏幕上就留下一百个方块,连成一条线。
这像什么呢?像你拿印章在纸上盖了一个,手往右挪一点再盖一个,再挪一点再盖一个——纸上留下的是一排印章,不是一个会走路的印章。
也像蜗牛爬过留下的痕迹:它确实在移动,但痕迹不会自己消失。
三、屏幕上没有橡皮擦,只有"盖住"
既然没有橡皮擦,那怎么擦?
先想想教室里的黑板:白粉笔写字,黑板擦一抹就没了。
屏幕不是黑板。它没有黑板擦。 你要擦掉一个白点,唯一的办法是——用黑笔把那个点重新描一遍。
看起来方块消失了,其实它是被黑色盖住了。
所以请记住今天最要紧的这句话:
屏幕上没有擦除,只有覆盖。
现在把程序修好:
请修改刚才的程序:
在画新位置的方块之前,先用背景色把旧位置的方块盖一遍。
也就是说,每一小段时间里做两件事:先盖掉旧的,再画上新的。
其余不变,别动原来的文件。
这次你应该看到一个干干净净的方块在移动了。
再给你留个小问题
把速度调快(每次加 8 而不是加 2),尾巴会回来吗?
如果回来了,想想为什么:两步之间隔得太远,"盖掉旧的"这一步可能盖不准。 擦和画必须成对出现,中间不能漏。
四、一帧,就是翻页动画里的一页
先问一个很根本的问题
我们做的这些,说到底就是:画一张、盖掉、再画一张、再盖掉。每一张都是静止的。 那你为什么觉得它在动?
动的是画面吗?不是。
动的是你的眼睛和大脑。
一个画面从眼前消失以后,它不会立刻从你的感觉里消失,还会在你脑子里多留一小会儿。 科学家叫它视觉暂留。
你可以自己试两件事:
- 盯着电风扇的叶片看——明明是分开的三片,转快了就看成一整片模糊的圆。
- 快速翻动课本页角——每页都是静止的小人,翻快了小人就动起来。
电影也是这个道理:电影每秒只放 24 张静止的照片,你的大脑自动把它们连成了连续动作。
所以动画真正的原理是:屏幕负责一帧一帧画静止的画,你的大脑负责把它们连成动作。
- 一帧 = 一次完整的画面(盖掉旧的 + 画上新的),就是翻页动画里的一页
- 帧率 = 一秒钟能画多少帧,就是一秒钟翻多少页
翻得太慢,你看到的是一张张静止的画;翻得够快,眼睛就把它连成了动作。
想好了再点开:为什么是 24?
这不是硬性规定,是一个"刚好够用"的数字。
- 低于 10 帧/秒:小球开始"一蹦一蹦",你能数出它跳了几下;
- 24 帧/秒:电影用的就是这个数——大脑已经能把前后两帧连起来了;
- 30 帧/秒:动画的常见门槛,比电影更顺一点;
- 60 帧/秒:很顺,但板子要画的帧数翻倍。
帧率越高画面越顺,但板子每一帧能用的时间就越少。 下一节我们就来看看,怎么让板子把这一帧画得又快又干净。
程序里的"歇一下"
程序里那个"每一小段时间",我们是用这一行做的:
time.sleep_ms(16) # 歇 16 毫秒 —— 一秒大约 60 帧
改这个数字,动画的快慢就变了。数字越大越慢,越小越快。
但别调得太小。 板子画一帧是要花时间的,你让它歇得太少,它来不及画完就又该画下一帧了。 它不会报错,只是画面变卡——安安静静地做不好,又是一个这样的例子。
五、算一笔账:为什么"整屏重画"不划算
上一节说"每一帧要盖掉旧的"。那有同学会想:干脆每一帧把整块屏幕都涂黑,再画新的,多省事。
效果一样吗?我们数一数。
| 做法 | 像什么 | 每帧要处理的点 |
|---|---|---|
| 只盖掉旧位置那一小块 | 用橡皮擦掉写错的一个字 | 200 个左右 |
| 整屏涂黑重画 | 把整页作业撕了重写 | 76,800 个 |
差了快 400 倍。
打个比方:你要用一根吸管喝掉一小口水,和用同一根吸管喝掉一桶水。 吸管就那么粗,水就那么多,做得到和做不到,是明摆着的。
所以动画有一条规矩:只改该改的地方,别整屏重画。
⭐ 好在这件事不用你操心。 我们用的
screen.fill_rect/screen.fill_circle都是只画那一块;screen.flush()负责把画好的推上屏幕。 你要做的只有一件事:记得擦掉旧的。
六、弹球:撞的是肚子,不是中心点
终于可以做弹球了。先把规则说清楚。
弹球要记住四样东西,你可以把它想成"小球脑子里的小本子":
| 记什么 | 现在是多少 | 干什么用 |
|---|---|---|
位置 x、y | 一开始在屏幕中间 | 现在在哪儿 |
速度 dx、dy | 每帧挪 2 和 3 | 下一帧往哪儿跑 |
| 撞左右边 | dx 变号 | 原来往右跑,改成往左跑 |
| 撞上下边 | dy 变号 | 原来往下掉,改成往上飞 |
写成中文步骤就是:
启动时:
小球位置 x = 120,y = 160
小球每一帧挪动 dx = 2,dy = 3
每一帧:
用背景色在 (x, y) 画一个小球 ← 盖掉旧的
x = x + dx
y = y + dy
如果碰到了左右边:dx = -dx ← 往回走
如果碰到了上下边:dy = -dy
用小球颜色在 (x, y) 画一个小球 ← 画上新的
推上屏幕,再等一小会儿
请你找一找:哪一步是"擦",哪一步是"画"? 如果把它们的顺序调换会怎么样?
💡 这个顺序有个坑,我先不告诉你 —— 你先照着写,跑起来看看有没有留下莫名其妙的小点。 想不出来,就点下面「弹球」卡片上的「查看源码」,看开头那段注释。
一个几乎人人都会踩的坑
我们的坐标指的是小球的圆心。可小球是有大小的,还有半径。
所以判断"撞到右边"的时候,不能只看 x > 239——那时候球已经有一半跑到屏幕外面去了。
打个比方:你闭着眼睛往后退,撞到墙的是你的肚子,不是你身体中心那个点。
正确的做法是留出身位:x + 半径 > 239 就算撞上了。
这就是编程里常说的边界条件。今天是你第一次遇到它,以后会经常见。
还有一件事
"撞到边界就往回走"——板子是真的知道墙在哪里吗?
不。它只是比较了两个数的大小。它眼里没有墙,只有数字。
回头看看:其实你早就会做动画了
第 3 课我们点亮过板子上那颗灯,让它慢慢变亮、再慢慢变暗。
那时候我们说的是"改颜色"。今天换个角度看——它也是动画。
| 动画在改什么 | 例子 | 你哪节课做过 |
|---|---|---|
| 改位置 | 弹球在屏幕上跑 | 今天 |
| 改大小 | 一个圆由小变大,像心跳 | 今天就可以做 |
| 改颜色 | 呼吸灯由暗到亮 | 第 3 课 |
你看,动画不只是"东西在移动"。只要有一个东西在随着时间变,它就是动画。
所以动画可以写成一个很简单的公式:
动画 = 一个会变的东西 + 时间
弹球会变的是位置,呼吸灯会变的是颜色,心跳会变的是大小。 变的东西不一样,做法却是一模一样的:每隔一小会儿,把那个东西改一点点,然后重新画一次。
七、动手做
请帮我做一个弹球:
黑色背景上有一个半径 8 的黄色小球,从屏幕中间出发,
每一帧横向挪 2 个像素、纵向挪 3 个像素。
碰到屏幕四个边就反弹。
每一帧都要先用背景色盖掉旧位置,再画新位置。
点一下屏幕可以暂停和继续。
请用中文注释,别动原来的文件。
改完装上板子(它同样会自己打开),请你检查四件事:
- 小球后面有没有尾巴?
- 撞到下边和右边时,是正好贴着边反弹,还是有一半跑到屏幕外面去了?
- 把速度改成 5 和 7,动画变快了还是变卡了?
- 一直盯着看十秒钟,小球会自己乱跑或者卡住吗?
只改一个条件
挑一个来改,先说出你的预测,再动手:
| 我改的条件 | 我预测会怎样 | 实际怎样 |
|---|---|---|
| 把半径从 8 改成 24 | ||
| 把速度从 2、3 改成 8、12 | ||
| 把每帧等待从 16 改成 100 | ||
只让小球横着跑(dy = 0) |
改完请回答:小球变大了以后,"擦"这一下要处理的点变多了还是变少了?动画有没有变慢?
八、自检小测
九、还想玩点什么
| 方向 | 可以描述给 AI 的效果 | 值得继续想 |
|---|---|---|
| 流星雨 | 几十个小点从上往下掉,掉到底再回到顶上 | 每个点都要单独记住自己的位置吗? |
| 心跳 | 一个圆由小变大、再变回小 | 变大变小的时候,"擦"那一下要擦多大? |
| 跑马灯 | 几个方块轮流亮起来,像在跑 | 它和"一个方块移动"是同一件事吗? |
| 贪吃蛇 | 蛇头往前走,身体跟着头走 | 蛇尾那一格,应该怎么擦? |
| 打砖块 | 顶部一排砖块,被撞到就消失 | 砖块消失后,那里要不要再画一次背景? |
倒数第二行那道题我留给你慢慢想。看起来只是"多画几节身体",真正难的地方还是那个字:擦。
这一课的作品,就在上面那几张卡片里 —— 点「装到板子上」,用 USB 线或者蓝牙选你的板子,几秒就装好了。 装完板子会自己打开它,不用按任何按键,也不用去桌面上翻页找。
想看它是怎么写出来的,点卡片上的「查看源码」。


