编程启蒙|Scratch 转 Python 系列第8天:节奏敲击机游戏实战(AI节奏谱生成实战)
摘要
本篇是 Scratch 转 Python 系列第 8 天,核心学习 time 模块的计时(time.time())和延时(time.sleep())功能。我们将 Scratch 的"计时器"和"等待秒数"积木与 Python 的 time 模块进行双向对照,串联 Day 3 的 while True 循环和 Day 5 的函数知识,最终完成一个"节奏敲击机"游戏实战——AI 生成节奏谱,玩家在限定时间内按下对应按键,反应越快得分越高,节奏越来越快!🎮
1. 本节课学习目标
- ⏱️ 掌握
time.time()获取当前时间戳,理解如何用两个时间点相减计算经过的时间 - 😴 掌握
time.sleep()实现程序延时,理解它与 Scratch"等待()秒"积木的对应关系 - 🔄 能够综合运用
while True循环(Day 3)、函数封装(Day 5)、时间计算,完成限时输入的反应时间测量 - 🤖 AI 应用场景:了解如何用
random模拟 AI 编曲生成节奏谱,并通过scratch代码学习如何对接真正的 AI 大模型生成游戏节奏
2. 专业名词通俗释义
| 名词 | 通俗解释 | 生活类比 |
|---|---|---|
time 模块 |
Python 自带的"时间工具箱",里面有很多跟时间有关的函数 | 就像你手机上的"时钟"App,里面有秒表、闹钟、世界时钟 |
time.time() |
返回从 1970 年 1 月 1 日到现在经过了多少秒 | 就像秒表上的数字,按下时记录"当前是第几秒" |
| 时间戳 | time.time() 返回的那个大数字(如 1700000000.5) |
就像快递单号——一个唯一的编号,标记某个特定时刻 |
time.sleep() |
让程序暂停指定的秒数,然后再继续执行 | 就像 Scratch 里的"等待 1 秒"积木,也像你妈喊你"等5分钟再吃蛋糕" |
| 毫秒 | 1 秒 = 1000 毫秒,是比秒更小的时间单位 | 就像 1 元 = 100 分,毫秒是时间的"零钱" |
| 事件驱动 | 程序的执行流程由"事件"触发(比如用户按下键盘) | 就像门铃——你不按,门铃不响;你一按,它就响。程序也是等用户"按门铃"才行动 |
| 主循环 | while True 让程序不断重复运行,等待用户操作 |
就像旋转木马——一圈又一圈地转,直到你说"停"才下来 |
| 反应时间 | 从看到提示到做出反应所花费的时间 | 就像赛跑时从听到枪响到迈出第一步的时间 |
3. 分模块双向对照知识点
💡 知识串联:本模块用到的
while True循环来自 Day 3,函数封装def来自 Day 5。
今天我们在它们的基础上加入"时间"这个新维度!
模块1:计时基础(time.time() 获取当前时间戳)
🔷 Scratch 积木逻辑
在 Scratch 中,我们用"计时器"积木来获取时间:
-
计时器积木:返回从绿旗点击后经过的秒数

-
重置计时器积木:将计时器归零

典型用法:记录一个起始时间 → 执行某些操作 → 再读取一次计时器 → 两次相减 = 经过的秒数。
🐍 Python 源码
import time
# 【Scratch积木】点击绿旗时(程序开始)
print("👉 程序开始!")
# 【Scratch积木】将 [start_time] 设为 (计时器)
start_time = time.time()
print(f"📌 开始时间戳:{start_time:.2f}")
# 【Scratch积木】等待 (1) 秒
print("⏳ 等待1秒中...")
time.sleep(1)
# 【Scratch积木】将 [end_time] 设为 (计时器)
end_time = time.time()
print(f"📌 结束时间戳:{end_time:.2f}")
# 【Scratch积木】将 [elapsed] 设为 ([end_time] - [start_time])
elapsed = end_time - start_time
print(f"\n✅ 经过的时间 = {end_time:.2f} - {start_time:.2f} = {elapsed:.2f} 秒")
📺 运行结果
👉 程序开始!
📌 开始时间戳:1700000000.00
⏳ 等待1秒中...
📌 结束时间戳:1700000001.00
✅ 经过的时间 = 1700000001.00 - 1700000000.00 = 1.00 秒
⚠️ 核心易错说明
- 时间戳很大是正常的:
time.time()返回的是从 1970 年 1 月 1 日到现在的秒数,数字可能像1700000000.5,不要害怕! - Scratch 计时器 vs Python
time.time():Scratch 的计时器从绿旗点击开始算,Python 从 1970 年开始算,但相减求差值的思路完全一样。 - 保留小数:用
:.2f可以只显示两位小数,否则数字会很长很难读。
模块2:延时控制(time.sleep() 暂停程序)
🔷 Scratch 积木逻辑
Scratch 中的"等待()秒"积木,让程序暂停指定时间:
- 等待 (1) 秒:程序暂停 1 秒后继续执行下面的积木


🐍 Python 源码
import time
# 模拟红绿灯🚦
# 【Scratch积木】说 [红灯亮了!] 持续 (1) 秒
print("🔴 红灯亮了!")
# 【Scratch积木】等待 (2) 秒
time.sleep(2)
# 【Scratch积木】说 [黄灯亮了!] 持续 (1) 秒
print("🟡 黄灯亮了!")
# 【Scratch积木】等待 (1) 秒
time.sleep(1)
# 【Scratch积木】说 [绿灯亮了!] 持续 (1) 秒
print("🟢 绿灯亮了!可以通行!")
# 倒计时小演示
# 【Scratch积木】重复执行 [3] 次
for i in range(3, 0, -1):
# 【Scratch积木】说 (连接 [倒计时:] 和 (i))
print(f" ⏰ {i}...")
# 【Scratch积木】等待 (1) 秒
time.sleep(1)
print(" 🎉 时间到!")
📺 运行结果
🔴 红灯亮了!
(等待2秒)
🟡 黄灯亮了!
(等待1秒)
🟢 绿灯亮了!可以通行!
再来一个倒计时小演示:
⏰ 3...
(等待1秒)
⏰ 2...
(等待1秒)
⏰ 1...
(等待1秒)
🎉 时间到!
⚠️ 核心易错说明
- 秒数可以是小数:
time.sleep(0.5)表示暂停 0.5 秒,不一定是整数。 - 完全对应:
time.sleep(秒数)和 Scratch 的"等待()秒"积木是一对一的映射关系,是最容易理解的对照。 - sleep 期间程序什么也不做:就像 Scratch 等待时角色也不会动一样,Python 在 sleep 期间也不会执行任何代码。
模块3:限时输入(计算反应时间)
🔷 Scratch 积木逻辑
在 Scratch 中实现"限时输入"需要组合多个积木:
-
询问()并等待:等待用户输入回答

-
计时器:同时记录经过的时间

-
如果 <计时器 > 3> 那么:判断是否超时

🐍 Python 源码
import time
# 【Scratch积木】等待 (2) 秒
print("3秒后开始...")
time.sleep(1)
print("2...")
time.sleep(1)
print("1...")
time.sleep(1)
# 【Scratch积木】将 [target] 设为 [g]
target = "g"
# 【Scratch积木】说 (连接 [请快速输入:] 和 [target])
print(f"\n👉 请快速输入字母:{target}")
# 【Scratch积木】将 [start_time] 设为 (计时器)
start_time = time.time()
# 【Scratch积木】询问 (请输入) 并等待
answer = input("请输入:").strip().lower()
# 【Scratch积木】将 [end_time] 设为 (计时器)
end_time = time.time()
# 【Scratch积木】将 [reaction] 设为 ([end_time] - [start_time])
reaction = end_time - start_time
print(f"\n📊 你的反应时间:{reaction:.2f} 秒")
# 【Scratch积木】如果 <(回答) = [target]> 那么
if answer == target:
# 【Scratch积木】如果 <[reaction] < [1]> 那么
if reaction < 1.0:
print("🚀 闪电手!反应超快!")
# 【Scratch积木】否则
else:
print("👍 不错!继续练习会更快!")
# 【Scratch积木】否则
else:
print(f"😅 输入错了,应该是 '{target}'")
📺 运行结果
3秒后开始...
2...
1...
👉 请快速输入字母:g
请输入:g
📊 你的反应时间:0.45 秒
🚀 闪电手!反应超快!
⚠️ 核心易错说明
- input() 会阻塞程序:
input()和 Scratch 的"询问()并等待"一样,程序会停在这里等用户输入,这就是"事件驱动"的体现。 - 计时要在 input 前后:
start_time必须在input()之前记录,end_time必须在input()之后记录,顺序不能错! - strip() 和 lower() 很重要:
strip()去掉首尾空格,lower()转小写,这样用户输入 "G " 或 “g” 都能正确匹配。 - 串联 Day 3:这里用
if/else判断和嵌套条件,跟 Day 3 学的条件判断完全一致!
4. 综合实战项目:节奏敲击机完整游戏
🎯 把模块 1-3 的知识全部串起来,加上 Day 3 的
while True循环和 Day 5 的函数封装,做一个完整的游戏!
🎮 游戏设计
| 要素 | 说明 |
|---|---|
| 按键 | W / A / S / D 四个键 |
| AI 编曲 | 用 random.choice() 随机生成按键(模拟 AI 生成节奏谱) |
| 限时 | 第 1 轮 3.0 秒,之后每轮减少 0.2 秒,最低 1.0 秒 |
| 计分 | 基础分 10 + 速度奖励(剩余时间 × 10)+ 连击奖励(连击数 × 2) |
| 连击 | 连续答对累积,答错或超时清零 |
| 退出 | 输入 q 随时退出 |
scratch积木代码


🐍 完整可运行代码
import time
import random
def rhythm_tap_machine():
"""🎵 节奏敲击机完整游戏 🎵"""
print("=" * 50)
print(" 🎵 节奏敲击机 Rhythm Tap Machine 🎵")
print("=" * 50)
print("📖 游戏规则:")
print(" · 屏幕会显示一个字母(W/A/S/D)")
print(" · 你需要尽快输入对应的字母")
print(" · 反应越快,得分越高!")
print(" · 随着轮次增加,时间会越来越短!")
print(" · 输入 'q' 可以随时退出")
print("=" * 50)
# 【Scratch积木】将 [score] 设为 [0]
score = 0
# 【Scratch积木】将 [round_num] 设为 [0]
round_num = 0
# 【Scratch积木】将 [combo] 设为 [0]
combo = 0
# 【Scratch积木】将 [best_combo] 设为 [0]
best_combo = 0
# 可选按键列表
keys = ['w', 'a', 's', 'd']
# 准备阶段
input("\n按回车键开始游戏...")
print("\n🎮 游戏开始!\n")
# 【Scratch积木】重复执行直到 <回答 = "q">
while True:
# 【Scratch积木】将 [round_num] 增加 (1)
round_num += 1
# AI生成节奏谱(用random模拟AI编曲)
# 【Scratch积木】将 [target_key] 设为 (在 [keys] 中取随机一个)
target_key = random.choice(keys)
# 时间限制随轮次减少(节奏越来越快)
# 【Scratch积木】将 [time_limit] 设为 ([3.0] - (([round_num] - [1]) * [0.2]))
time_limit = max(1.0, 3.0 - (round_num - 1) * 0.2)
# 【Scratch积木】说 (连接 [第] 和 ([round_num]) 和 [轮])
print(f"━━━ 第 {round_num} 轮 ━━━")
print(f"⏱️ 时间限制:{time_limit:.1f} 秒")
print(f"👉 请按:【 {target_key.upper()} 】")
# 记录开始时间
# 【Scratch积木】将 [start_time] 设为 (计时器)
start_time = time.time()
# 【Scratch积木】询问 (请输入) 并等待
answer = input(">>> ").strip().lower()
# 记录结束时间
# 【Scratch积木】将 [end_time] 设为 (计时器)
end_time = time.time()
# 计算反应时间
# 【Scratch积木】将 [reaction] 设为 ([end_time] - [start_time])
reaction = end_time - start_time
# 退出游戏
# 【Scratch积木】如果 <(回答) = [q]> 那么 停止该脚本
if answer == 'q':
break
# 判断是否超时
# 【Scratch积木】如果 <[reaction] > [time_limit]> 那么
if reaction > time_limit:
print(f"⏰ 超时!反应时间 {reaction:.2f}s > 限制 {time_limit:.1f}s")
print("❌ 本轮不得分,连击中断!")
# 【Scratch积木】将 [combo] 设为 [0]
combo = 0
# 判断是否按对
# 【Scratch积木】如果 <(回答) 不 = [target_key]> 那么
elif answer != target_key:
print(f"❌ 按错了!应该是 {target_key.upper()}")
print("❌ 本轮不得分,连击中断!")
# 【Scratch积木】将 [combo] 设为 [0]
combo = 0
# 答对且未超时
# 【Scratch积木】否则
else:
# 计算得分:越快得分越高
# 【Scratch积木】将 [speed_bonus] 设为 (取整 ([time_limit] - [reaction]) * [10])
speed_bonus = int((time_limit - reaction) * 10)
# 基础分10分
base_score = 10
# 【Scratch积木】将 [combo] 增加 (1)
combo += 1
# 连击奖励:每连击+2分
# 【Scratch积木】将 [combo_bonus] 设为 ([combo] * [2])
combo_bonus = combo * 2
# 本轮总分
# 【Scratch积木】将 [total] 设为 ([base_score] + [speed_bonus] + [combo_bonus])
total = base_score + speed_bonus + combo_bonus
# 【Scratch积木】将 [score] 增加 [total]
score += total
# 更新最高连击
# 【Scratch积木】如果 <[combo] > [best_combo]> 那么
if combo > best_combo:
# 【Scratch积木】将 [best_combo] 设为 [combo]
best_combo = combo
print(f"✅ 正确!反应时间 {reaction:.2f}s")
print(f"🎯 得分:+{total}(基础{base_score} + 速度{speed_bonus} + 连击{combo_bonus})")
print(f"🔥 连击:{combo} | 🏆 总分:{score}")
# 短暂停顿
# 【Scratch积木】等待 (0.5) 秒
time.sleep(0.5)
print()
# 游戏结束统计
print("=" * 50)
print("🎮 游戏结束!")
print(f"📊 完成轮数:{round_num - 1}")
print(f"🏆 总得分:{score}")
print(f"🔥 最高连击:{best_combo}")
print("=" * 50)
# 启动游戏
rhythm_tap_machine()
🧩 游戏代码拆解
| 代码区块 | 对应知识点 | 串联来源 |
|---|---|---|
while True 主循环 |
无限循环 + break 退出 |
Day 3 循环 |
def rhythm_tap_machine() |
函数封装游戏逻辑 | Day 5 函数 |
time.time() 计时 |
获取时间戳,计算反应时间 | Day 8 新知识 |
time.sleep(0.5) 延时 |
轮次间短暂停顿 | Day 8 新知识 |
random.choice(keys) |
AI 模拟生成节奏 | Day 8 AI 实战 |
if/elif/else |
条件判断超时/按错/按对 | Day 3 条件判断 |
input() |
事件驱动,等待用户输入 | Day 1 输入输出 |
5. 高频易错点总结
❌ 易错点1:计时顺序搞反
# ❌ 错误:先 input 再记开始时间,反应时间永远是 0
answer = input("请输入:")
start_time = time.time() # 错!
end_time = time.time()
reaction = end_time - start_time # 永远约等于 0
# ✅ 正确:先记开始时间,再 input,最后记结束时间
start_time = time.time()
answer = input("请输入:")
end_time = time.time()
reaction = end_time - start_time # 这才是真实反应时间
❌ 易错点2:忘记 import time
# ❌ 错误:直接用 time.time() 但没有导入
start = time.time() # 报错:NameError: name 'time' is not defined
# ✅ 正确:文件开头先导入
import time
start = time.time() # 正常运行
❌ 易错点3:time.sleep() 的参数单位搞混
# ❌ 错误:以为参数是毫秒
time.sleep(1000) # 实际暂停 1000 秒(约16分钟)!
# ✅ 正确:参数是秒,1秒就写 1
time.sleep(1) # 暂停 1 秒
time.sleep(0.5) # 暂停 0.5 秒(500毫秒)
❌ 易错点4:忘记 strip() 和 lower() 导致匹配失败
# ❌ 错误:用户输入 "W "(带空格大写),无法匹配 "w"
answer = input("请输入:")
if answer == "w": # "W " != "w",匹配失败!
# ✅ 正确:strip() 去空格 + lower() 转小写
answer = input("请输入:").strip().lower()
if answer == "w": # "W " → "w",匹配成功!
❌ 易错点5:while True 忘记写退出条件
# ❌ 错误:没有 break,死循环永远停不下来
while True:
answer = input("请输入:")
print(answer)
# 只能按 Ctrl+C 强制停止,很不友好
# ✅ 正确:加上退出条件
while True:
answer = input("请输入:")
if answer == "q":
break # 输入 q 就退出
print(answer)
6. 💡 学习提示
💡 学习提示
为鼓励大家动手练习、吃透编程逻辑,本篇不提供Scratch成品源码,请对照截图亲手搭建积木完成复刻!
配套Python代码可直接复制运行学习。
7. 往期历史笔记
-
编程启蒙|Scratch 转 Python 系列第 3 天:循环重复积木双向对照(AI 批量循环处理,已收录 AI Agent 技术社区)
-
编程启蒙|Scratch 转 Python 系列第 5 天:自定义积木 / 函数双向对照(AI 工具封装、重复指令简化实战)
-
编程启蒙|Scratch 转 Python 系列第 6 天:列表、数组积木双向对照(AI 底层语法 / AI 批量数据处理实战)
-
编程启蒙|Scratch 转 Python 系列第 7 天:猜数字大挑战·升级版实战(AI 出题 + 二分查找最优解 + 完整命令行游戏)
📌 知识串联提醒:
- 本篇的
while True主循环来自 Day 3 的循环结构,游戏中用break退出- 本篇的
def rhythm_tap_machine()函数封装来自 Day 5 的函数知识,把整个游戏逻辑打包成一个函数- 建议如果对循环或函数还不熟练的同学,先回顾 Day 3 和 Day 5 再来看本篇!
9. 下一章预告
📅 Day 9:字典/哈希表积木双向对照,AI大模型参数配置表实战
明天我们将学习 Python 中非常重要的数据结构——字典(
dict)!
- 🔑 字典就像"标签收纳盒",用键(
key)找值(value)- 🔄 对照 Scratch 中的列表和变量组合使用
- 🤖 AI 实战:用字典管理 AI 大模型的参数配置表(模型名称、温度、最大token数等)
- 🎮 动手做一个"AI 模型参数调试器"
敬请期待!🎉
10. 原创声明
本文为 梅雅达编程笔记 原创内容,系列课程持续更新中。
📢 禁止搬运:本文所有文字、代码、图片均为原创,未经授权禁止转载、复制、摘编或以其他方式使用。
📧 如需授权,请联系作者。
© 梅雅达编程笔记 · Scratch 转 Python 系列 · Day 8
每节课都配套课后练习题与完整源码。代码报错、看不懂知识点,可在评论区粘贴问题,逐一解答!
欢迎关注梅雅达编程笔记,持续分享Python零基础学习内容
更多推荐



所有评论(0)