用现代地牢游戏教孩子编程
摘要
一位家长创建了一款名为Canon的现代网页地牢游戏,用来教八岁的孩子编程,玩家可以使用简单的脚本语言构建和修改游戏世界。
暂无内容
查看缓存全文
缓存时间: 2026/08/18 12:58
# 佳能
来源:https://tau.dev/2026/08/07/canon
## 我八岁的女儿想做电子游戏
她对此痴迷不已。她也喜欢*玩*电子游戏,但那感觉不一样。体验世界,甚至是征服世界,太过被动。她想要*创造*世界。
因此我给她做了一个可以制作游戏的游戏。一个由文本、图像和一个微型新脚本语言构成的多人世界,在这里她可以把任何东西拆开,看看它是如何运作的。我最早学习编程是在“查看源代码”还是可靠教学工具的年代,我认为她也理应得到同样的体验。
这款游戏有很多限制。这个叫做`Cant`的语言并不是一门很好的语言,这是有意为之。
但它也出乎意料地有趣。我把它称为:
佳能用户界面。一个网页客户端,展示了一个支持基于文本的对话与交互的多人游戏历史,并包含可选的图像。在此示例中,两位玩家“天空船长法尔”和“大德鲁伊温迪·格罗夫”在雪山小屋外互相问候,并进行了一场友好的雪仗。(https://tau.dev/assets/canon/canon.webp)
佳能是对经典MUD (https://en.wikipedia.org/wiki/Multi-user_dungeon) 的现代化、基于网络的诠释。
对于不熟悉的人:在《魔兽世界》将MMORPG变成大型工作室制作的类型之前,我们有基于文本的MUD(以及MUCK (https://en.wikipedia.org/wiki/MUCK) 和MUSH (https://en.wikipedia.org/wiki/MUSH)),玩家可以在由纯文字构成的广阔领域中探险和社交。
我曾花无数时间探索这些想象之地。我想创造一个具有同样精神、但对现代观众来说感觉更熟悉的东西。
佳能对于什么构成了一个好的MU*以及一个好的学习环境,有着强烈的主张。佳能中的每一个房间、物品和交互都是玩家创建的,所有这些都可以被检查、复制和修改。
我女儿非常喜欢它。如果你是那种喜欢角色扮演或文字冒险游戏,或者对telnet和早期网络时代怀有某种怀旧情结的成年人,你可能也会喜欢它。
但首先,按照食谱博客的风格,让我告诉你我们是如何走到这一步的。
---
### 为思维的自行车装上辅助轮 (https://tau.dev/2026/08/07/canon#training-wheels-for-the-bicycle-for-the-mind)
你还记得HyperCard (https://en.wikipedia.org/wiki/HyperCard) 吗?如果不记得,你记得《神秘岛》(https://en.wikipedia.org/wiki/Myst) 吗?(如果都不记得,恭喜你如此年轻。请多包涵。)
比尔·阿特金森在1985年一次LSD旅行后构想出了HyperCard。我第一次接触它是在1989年,四年级的电脑实验室里,我的思想也得到了拓展。
HyperCard是这样运作的:这里有一些卡片。
迎接新HyperCard用户的默认堆栈。(https://tau.dev/assets/canon/hypercard.png)
我的意思是,基本上就是这样。这就是其精妙之处。这里有卡片,你可以在上面放置各种电脑元素。按钮、文本、图片和视频。卡片可以堆叠在一起。一个HyperCard*应用*被称为“堆栈”。明白了吗?
然后,所有这些按钮、图片和元素:你可以让它们可点击。并且你可以告诉它们在堆栈的卡片之间移动。这是一种以用户体验形式呈现的“选择你自己的冒险”书籍。
(如果这听起来有点像网站,嗯,是的。HyperCard是HyperMedia (https://en.wikipedia.org/wiki/Hypermedia) 最早真正可用的实例之一,并影响了蒂姆·伯纳斯-李对万维网的开发。)
``
on mouseUp
go to card id 123
end mouseUp
``
那是有效的HyperTalk (https://en.wikipedia.org/wiki/HyperTalk),HyperCard底层的编程语言。但对于最基本的交互——比如点击一个按钮跳转到一张卡片——你甚至不需要了解HyperTalk。你可以使用一个简单的图形用户界面编辑器来连接它们。
用于编辑按钮的HyperCard图形用户界面,包括将该按钮链接到另一张目标卡片的功能。(https://tau.dev/assets/canon/newbutton.png)
如果你会点击按钮,你就能使用HyperCard。而如果你能*使用*HyperCard,你就能*编程*HyperCard。
我可以就此写一整个系列的文章。但我现在想向你传达的两件事如下:
1. HyperCard 是**神奇的**。
2. HyperCard **很糟糕**。
---
### 它很神奇,但它也很糟糕 (https://tau.dev/2026/08/07/canon#it-was-magic-and-it-sucked)
在很多方面,HyperCard堆栈并不是好的应用 (https://daringfireball.net/2002/08/why_hypercard_failed)。它们被卡片的隐喻严重限制。它们使用了MacOS视觉语言中的输入元素,但它们无法,也不可能感觉像正常的原生MacOS应用程序。HyperTalk犯了后来被AppleScript (https://en.wikipedia.org/wiki/AppleScript) 重复的错误:试图让一种编程语言更像自然语言,结果两者都没做好。
对于任何真正的程序员来说,这都是一个令人沮丧且功能不足的环境。但正是这些缺陷和限制,让它神奇地变得易于访问,吸引了两群饥渴的群体:**非程序员**和**好奇的孩子**。
第一类人创造出了大量的东西。互联网档案馆收藏了数千个可游玩的堆栈合集 (https://archive.org/details/hypercardstacks)。如果你记得早期网络,仅仅浏览那些缩略图就能给你一种熟悉的感觉。游戏!杂志!同人圈!宣言!不知怎么还有色情内容!在互联网出现之前,拥有Mac且有些想法的人们通过软盘交换堆栈。
我属于第二类。九岁时,我在小学的Macintosh SE (https://en.wikipedia.org/wiki/Macintosh_SE) 上发现了HyperCard,并很快发现与大多数电脑程序不同,*HyperCard中的所有内容都是可编辑的*。我开始制作第一个想到的东西,一个《街头霸王》(https://en.wikipedia.org/wiki/Street_Fighter) 风格的格斗游戏,有两个画得很粗糙的玩家。
《无名格斗棍人》游戏的艺术家复原图。一个粗糙的人形火柴人对阵某种……恐龙?(https://tau.dev/assets/canon/fight.png)艺术家复原。唉,原始堆栈已湮没于历史长河。我指的是父母地下室里那盒报废的软盘。我对编程一无所知,更不用说*精灵图*之类高级的游戏开发概念了。但我知道我可以把按钮链接到卡片上。所以我这么做了。带着只有极度专注的孩子才能拥有的决心,我开始*为玩家每一个可能的动作和位置组合绘制单独的卡片*,并使用按钮作为在它们之间移动的“控制”。我发现了一把锤子,并且知道如何用钉子从无到有做出一个东西。
> 你在卡片154上。玩家1在第二象限,闲置。玩家2在第三象限,防御。如果玩家1按下“攻击”按钮,跳转到卡片...
这花了我*好几个星期*,每天放学后留到很晚。但它成功了。我*做出了一个游戏*。我可以用我自己的创作来玩。我整个职业生涯都在追逐那种快感。
但这仅仅是开始。比尔·阿特金森做的真正聪明的事情之一,是当你用图形界面编辑HyperCard的行为时,它会*自动为你写出相应的代码*。在我辛辛苦苦点击和链接项目进行到一半左右时,我注意到了编辑器中的`Script...`按钮,拼凑出了它的含义,并开始使用复制粘贴HyperTalk代码片段和为我数百张卡片制定的系统命名方案来加速开发。
接近尾声时,电脑老师(我相当确定我们只把这门课叫做“电脑课”)注意到了我在做什么,从一个抽屉里为我找出了*HyperCard参考手册*。这是我第一次从头到尾阅读一本技术手册。
---
### 多年以后…… (https://tau.dev/2026/08/07/canon#many-years-later)
我不会让我女儿学习HyperCard。我有点像个恶作剧老爸 (https://www.gocomics.com/calvinandhobbes),但没*那么*刻薄。
但我确实想重现那种让年轻时的尼克大开眼界的、创造性自由与机械限制的神奇组合。佳能需要:
- 即时满足。一旦你把一个东西放在屏幕上,它就已经是游戏的一部分了。
- 查看源代码。游戏中的一切都应该用游戏自身的工具构建,并且可以自由编辑/复制/拆解。
- 用于最简单交互的图形用户界面。
- 从图形界面到编写原始代码的平滑学习曲线。
- 代码中的力量要刚好足够构建各种有趣的游戏机制,并教授基本的程序员思维。
- 但又足够有限,让初学者能够理解整个原语集合。
---
### 即时满足 (https://tau.dev/2026/08/07/canon#instant-gratification)
基于文本的世界的美妙之处在于,你可以通过输入“这里有一个[东西]”来添加任何你想要的东西。你在*如何*构建上受到限制——没有花哨的3D可视化或令人印象深刻的逼真物理引擎——但在*能构建什么*上拥有无限的自由。
佳能由三样东西组成:
1. 玩家
2. 房间
3. 物品
**玩家**和**房间**都只是文本描述,以及可选的图像。要创建其中任何一个,你只需回答一个问题:*它看起来是什么样的?*
空间站货舱的房间描述:货舱巨大且大多空荡。一面墙消失了,大气被某种能量场禁锢着。它提供了下方星球的壮丽景色。(https://tau.dev/assets/canon/lookhere.webp)玩家“大德鲁伊温迪·格罗夫”的角色描述:温迪用一种昏昏欲睡、心不在焉的表情看待世界。你可能需要喊她几次才能把她的注意力拉回到当下。但别被表象骗了。在她脚下绽放的花朵,以及无论她走到哪里都簇拥而来的动物,都证明了她力量的深厚。(https://tau.dev/assets/canon/lookme.webp)
---
### 查看源代码 (https://tau.dev/2026/08/07/canon#view-source)
**物品**是*其他所有东西*。它们同样是文本描述和图像,所以你可以将任何物品塑造成你想要的样子:无生命的物体、宠物、NPC、法术效果、载具、门、任务标记、消息等等。
但除了文本和图像,物品还由`Cant`构成的*动作*和*状态*组成。它看起来像这样:
``
item "Hooded Lantern" {
describe "An iron lantern with a hinged hood."
on "light" {
narrate "{player}’s {item} swings open and warm light spills out."
}
}
```
这就足以创建一个玩家可以点燃的灯笼:
游戏中点燃灯笼的截图。(https://tau.dev/assets/canon/lantern.webp)
这是一个稍微复杂点的物品,一个魔法8号球:
``
item "Magic 8-Ball" {
describe "A prophetic billiard ball. Give it a shake?"
or "Give it a shake to see your future."
or "Dare you shake it?"
on "shake" {
say
"It is certain."
or "Outlook good."
or "Signs point to yes."
or "Don’t count on it."
or "My sources say no."
or "Reply hazy, try again."
or "Ask again later."
}
}
```
`or`关键字可以在任何接受文本字符串的Cant代码中使用。它在每次使用该字符串时随机选择一个变体:当玩家查看一个物品或触发一个动作时。我想把这个功能在最底层就融入佳能。
对于一个新程序员来说,有一个随机数生成器(RNG)特别令人愉悦。你告诉电脑做什么,它就做什么。但你也告诉它行使一点点自主权。这既出乎意料,又在情理之中。你编写了每一个回答,你知道它能说的所有东西,但你按下按键或点击按钮时,却不知道它确切会说什么。这就像突然能给自己挠痒痒一样。
游戏中摇动魔法8号球的截图。(https://tau.dev/assets/canon/8-ball.webp)
注意,除了`shake`,这个物品还有一个`clone`按钮。佳能中的每个物品都可以被克隆。你拥有的物品(包括你克隆的任何物品)都可以编辑。任何其他玩家制作的游戏、玩具或任务也是*教程*。
---
### 用于最简单交互的图形用户界面 (https://tau.dev/2026/08/07/canon#a-gui-for-the-simplest-interactions)
这个8号球是我为了吸引女儿而做的第一批玩具之一。我把它留在了起始区域。即使你对条件逻辑一无所知,即使你不看代码,玩几分钟这个球也很容易看出它是如何工作的。并且很容易想象你可以如何将其修改成抛硬币,或者一个讲随机笑话的NPC。
编辑魔法8号球:上述Cant示例在一个结构化的图形界面编辑器中。(https://tau.dev/assets/canon/8-ball-simple-edit.webp)编辑抛硬币:魔法8号球的一个副本,动作从“shake”重命名为“flip”,口头回应减少到两个:正面和反面。(https://tau.dev/assets/canon/flipping-coin.webp)
或者,比方说一个D20:
编辑D20:8号球的另一个变体,为从一到二十的每个数字都设置了一个单独的口头台词。(https://tau.dev/assets/canon/d20.webp)我是完全认真的。如果你是一名程序员,你可能会注意到这很糟糕。这是一种效率低下的写法,它显然可以用`randInt\(1,20\)`完成。但它非常*易于理解*。
Cant是一门在教育意义上被设计为“糟糕”的语言。它为易于理解而非编写速度进行了优化。它是DRY (https://en.wikipedia.org/wiki/Don't_repeat_yourself) 原则的反面。
---
### 从图形界面到代码的平滑过渡 (https://tau.dev/2026/08/07/canon#a-smooth-gradient-from-gui-to-code)
让我们把那个编辑器窗口稍微展开一点:
使用原始Cant编辑D20:say 1! or 2! or 3! or 4! or,依此类推。(https://tau.dev/assets/canon/d20-with-code.webp)
经验丰富的程序员会注意到这段代码本可以是一行搞定的。但初学者会注意到,代码已经比点击20个按钮和20个文本输入框轻松多了。
代码和结构化编辑器是同步的。其中任何一个的有效表达都会立即更新另一个。我想用这种方式吸引女儿,就像HyperCard的`Script...`按钮吸引我一样。
---
### 刚刚好够用 (https://tau.dev/2026/08/07/canon#just-enough-power)
好吧,说出随机字符串 (https://man.cat-v.org/unix_8th/6/fortune) 很有趣,但这构不成一个游戏。这东西还能做什么?
几个例子:
``
item "Dueling Wand" {
describe """
A hazel {item} wound with copper wire, humming faintly.
{when item vigor <= 0}Its light is out. A defeated duelist’s wand, until someone mends it.{end}
"""
borne "A hazel {item} {when item vigor <= 0}hangs dark and quiet{else}crackles with impatience{end} in {player}’s grip."
afield "A hazel {item} lies here, {when item vigor <= 0}its lights dimmed{else}crackling with magic potential{end}."
state {
vigor 30
}
on "fireball" {
when item vigor > 0 {
when target vigor > 0 {
subtract target vigor 1d20
narrate "{player}’s {item} roars! A ball of fire breaks over {target}."
when target vigor <= 0 {
narrate "{target}’s wand goes dark. {player} stands victorious."
}
}
otherwise {
narrate "{player}’s {item} finds no one standing to strike."
}
}
otherwise {
narrate "{player} attempts to cast but their {item} is dark until mended."
}
}
on "mend" {
when target vigor >= 30 {
narrate "{player}’s wand hums, finds nothing to mend on {target}, and declines to waste the charm."
}
otherwise {
add target vigor 1d10
narrate "Green light from {player}’s {item} knits itself over {target}."
when target vigor > 30 {
narrate "{target} sparkles briefly with excess power."
set target vigor 30
}
}
}
}
```
这是一个*玩家对战(PVP)*场景。两个或更多玩家可以拿起决斗魔杖互相战斗。这里需要注意的关键点是:
``
state {
vigor 30
}
``
佳能中的物品可以持有两种状态:**标记(marks)**和*
相似文章
MUDs在现代的意义
本文认为,MUDs(多用户维度)作为早期互联网时代的基于文本的虚拟世界,通过提供独特的社区驱动、模拟丰富的体验,与现代即时娱乐形成鲜明对比,至今仍具有重要意义。
教孩子们Forth编程
一位程序员分享了他们教初中和高中生Forth编程语言的经验,解释了为什么选择它而不是Python或Scratch,以及他们如何为12节课的课程设计教学大纲。
@gabriel1:有点难过,电脑使用对我们孩子来说将变成失传的艺术——本地搭建Minecraft服务器,一键搞定。各种设…
一条推文反思,AI让搭建Minecraft服务器或解决电脑问题等任务只需一条提示即可完成,可能会导致年轻一代失去基础的计算机技能。
自己造一门编程语言比你想象的简单(但也更难)
作者分享了为游戏模组系统构建自定义编程语言的经验,讨论了设计动机和技术挑战。这篇文章反思了在个人项目中实现一门非玩具级编程语言的可行性与复杂度。
童年计算机
Susam Pal 回顾了他童年时期使用早期计算机、LOGO 编程以及经典游戏(如 Moon Bugs 和 Digger)的经历。