AI脑洞板
完整教案
自学课件
第 9 课 · 共 35 课

点一下就回应

你好呀,我是吴老师。

到这里,你的板子已经会亮灯、会画画了。

但它一直有个毛病:它不听你的。

你画了那么多漂亮的东西,可你想让画面变一变 —— 只能改代码、重新装一遍。

今天我教它最后一件事:听你说话。

跟它说话不用嘴,只用一根手指。

读完之后,你应该能:读出手指现在按在屏幕的哪个位置;说清楚"抬手之后坐标会清零"这个坑,并知道怎么绕过它;解释板子怎么分辨"点一下"和"划一下";做出一个能按的按钮;用 gesture 认出手势。

用时:约 60 分钟。准备:板子、数据线。

看不懂的地方,整段复制给 AI,加一句"请一次只解释一个概念,讲完问我一个小问题"。


一、先问它:手指在哪儿

跟板子要手指的位置,一行就够:

touched, x, y = touch.state()

它一次给你三样东西:

拿到什么意思
touched现在有没有手指按在屏幕上(True / False)
x、y手指按在哪 —— 就是上一课学的那个坐标

💡 为什么一次问三个,不分成三次问? 因为它只读一次硬件。你要是分成三次问,万一手指正好在两次之间抬起来, 后面那次就问了个空。一次拿全,最保险。

现在试着做一个「点哪画哪」:

请帮我做一个「点哪画哪」:
手指按在屏幕上时,用一个 ______ 色、半径 ____ 的空心圈跟着手指走;
手指一抬,就在那个位置留下一个 ______ 色、半径 ____ 的实心圆。
屏幕上显示已经画了几个。请用中文注释。

自己把颜色和半径填上。 圈要多大才好看?留下的圆呢?

填不出来?点这里看一个参考(这不是标准答案)
请帮我做一个「点哪画哪」:
手指按在屏幕上时,用一个白色、半径 18 的空心圈跟着手指走;
手指一抬,就在那个位置留下一个黄色、半径 12 的实心圆。
屏幕上显示已经画了几个。请用中文注释。

跑起来是这样(这是点了三下的样子):

点哪画哪

二、⚠️ 抬手之后,坐标会清零

现在讲这一课最重要的一件事。很多同学在这儿卡了整整一节课。

假设你想"手指抬起来的时候,在刚才那个位置画一个圆"。

你很自然会这么写:

touched, x, y = touch.state()
if not touched:              # 手指抬起来了
    screen.fill_circle(x, y, R, 颜色)     # ❌ 错!

跑一下 —— 不管点哪儿,圆都画在屏幕左上角。

为什么?

⭐ 因为手指一抬起来,touch.state() 给的坐标就变成 (0, 0) 了。

抬手之后坐标会清零

不是"记着刚才的位置",是清零 —— 回到原点。

💡 它为什么这么做? 因为"没手指按着"的时候,"手指在哪"这个问题本来就没有答案。 板子很诚实:没有就是没有,给你 (0, 0)。

麻烦的是它不报错。你的代码语法是对的、逻辑看着也对, 就是画错地方 —— 这类错误最难查。

正确的做法

在手指还按着的时候,自己把位置记下来。

if touched:
    hold = (x, y)            # ⭐ 按着的时候记下来
elif pressing:
    marks.append(hold)       # ⭐ 抬手时用"记下来的那个"

给一个变量专门记着"手指最后待过的地方",抬手时用它。

⭐ 一句话记法: 抬手之后再去问坐标,问到的永远是左上角。 要用,就得在按着的时候先存下来。

三、点一下和划一下,怎么分

现在有第二个问题:手指按下去又抬起来,是"点了一下",还是"划了一下"?

你觉得这还用问吗?对你来说当然一眼就分得出来。但板子不行 —— 它只知道什么时候按下、什么时候抬起、手指经过了哪儿。

板子的办法是:同时看两件事。

点一下和划一下

看什么怎么看
按了多久按下到抬起,不超过 0.6 秒
走了多远手指几乎没挪 —— 位移不到 40 个像素

两个都满足 → 是"点一下"。 位移超过 40 像素 → 是"划一下"。

💡 为什么要两个一起看?

只看时间:你按住不动停一会儿再抬 —— 时间超了,被当成"划"。可你明明没划。

只看距离:你手抖了一下,手指挪出去几像素 —— 被当成"划"。可你明明只想点。

两个一起看,才分得准。

⚠️ 所以滑的时候要按住再划。 手指刚碰到屏幕就"啪"地弹开的那种划, 板子会当成点一下。这是很多新同学第一次做翻页时会卡的坑(第一课我们提过一次)。

还有双击和长按

板子也帮你想好了:

手势怎么算
单击快按快抬,很快就松手
双击两下之间隔得不超过 0.26 秒
长按一直按住,超过 0.8 秒
滑动手指走超过 40 像素,再分四个方向

💡 单击为什么要等一小会儿才出来? 因为它得等一等,看看你会不会点第二下。 不然你每双击一次,会先冒出一个单击 —— 那就乱了。

四、做个能按的按钮

懂了原理,来做实用的东西:三个按钮。

三个按钮

按钮的做法特别朴素:

给每个按钮记住一块矩形范围,手指落下的位置落在哪块里,就算按到了它。

代码里就是一句话的事:看手指的 x、y 有没有落进那个按钮的范围 —— 左边、右边、上边、下边,四个数一比就知道了。

你上一课刚学过 fill_rect(x, y, w, h, 颜色) —— 按钮的范围,就是那块矩形的范围。 画在哪儿、判在哪儿,是同一组数字。

⚠️ 注意判定要写在"刚按下"的那一帧。 不然你手指按着不动,它每一帧都会重新判一次,等于一直重复按。 代码里那个 not was_pressing 就是干这个的。

五、手势:不用自己算

看到这儿你可能在想:双击、长按、四方向滑动……这些都要自己算吗?

不用。板子把它们做好了:

import gesture

while True:
    gesture.update()              # ⭐ 每帧调一次,识别就发生在这里
    if gesture.tap():             # 这一帧有单击吗?

手势识别

一句话就能问它:"刚才有单击吗?""刚才往哪边滑了?"

想问什么怎么写
单击gesture.tap()
双击gesture.double()
长按gesture.long_press()
滑动gesture.swipe() → 'left' / 'right' / 'up' / 'down'
还要按着吗gesture.pressing()
按了多久gesture.held_ms()

⚠️ 两件事必须记住:

① 每帧都要调 gesture.update()。 识别就发生在那一下,不调它,什么都不会发生。

② 事件只在发生的那一帧为真。 这一帧问到了 True,下一帧再问就是 False 了 —— 看到就得立刻用掉,别存起来留着以后用。

那我该用哪个?

你要做的用哪个
"点在这块区域里吗"(按钮、棋盘格)touch.state() —— 你自己比坐标
"他做的是什么手势"(单击、双击、长按、滑动)gesture —— 现成的

💡 一个偷懒的规律: 你能用一块矩形描述清楚"点在哪儿算数" → 用 touch.state(); 你要的是动作本身(他划了一下)→ 用 gesture。

六、动手做

动手之前,先回答一个预测题:

如果把手势那个程序里的 gesture.update() 那一行删掉,会发生什么?

想好了再点开

什么手势都认不出来。

屏幕会一直停在你刚打开时的样子 —— 不管你单击、双击、滑来滑去,它都没反应。

因为手势的识别本身就发生在 gesture.update() 里面。 不调它,gesture.tap() 永远返回 False。

⚠️ 而且它不报错 —— 程序跑得好好的,就是不理你。 如果你自己碰到了这种情况,先检查这一行还在不在。

只改一个条件

挑一个来改,先说出你的预测,再动手:

✏️ 可以直接在表格里填写
我改的条件我预测会怎样实际怎样
把「点哪画哪」里的 R = 12 改成 R = 30
按钮那个程序,把 not was_pressing 去掉
把按钮的 BTN_H = 56 改成 BTN_H = 20
把 gesture 的 LONG_MS 从 800 改成 300
「点哪画哪」里,把 hold 换成抬手时的 x, y

最后一行是今天的重点考题。 它改的就是第二节讲的那个坑 —— 改完试试看,圆会画到哪儿去。

七、自检小测

正在加载本课自检小测…

八、还想玩点什么

方向可以描述给 AI 的效果值得继续想
颜色开关点一下屏幕,背景换一种颜色怎么让它"轮流"换,而不是乱换?
四方向摇杆上滑加速、下滑减速、左右转方向怎么把"手势"变成"一直持续的状态"?
涂鸦板手指划过去,留下一串点上一课学的"只擦改过的地方"在这儿用得上吗?
你画我猜一个人画,另一个人猜画的东西怎么传给对方的板子?

最后一行的题我留给你慢慢想 —— 它牵着一个很大的问题: 两块板子,怎么互相说话?


这一课的作品,就在上面那几张卡片里 —— 点「装到板子上」,用 USB 线或者蓝牙选你的板子,几秒就装好了。 装完板子会自己打开它,不用按任何按键,也不用去桌面上翻页找。

想看它是怎么写出来的,点卡片上的「查看源码」。

本节演示

点哪画哪

点哪画哪

手指按着有圈跟着走,抬手就留下一个圆

三个按钮

三个按钮

点哪个按钮,上面就变哪个颜色

手势识别

手势识别

单击、双击、长按、四个方向的滑动