跳转到内容

10. 写给完全没编过程的你

约 30 分钟 难度:新手 动手章

完全没接触过编程的人,看到「写脚本」三个字往往会有一秒的紧张反应。屏幕上密密麻麻的英文符号、看不懂的报错红字、需要记住的「语法规则」,这些印象大多来自影视作品和那些喜欢炫技的同学。

实际编程没有那么神秘。这一章不写代码,先把心里那几个问号拆开。

家里那本菜谱写糖醋里脊:先切肉,腌十分钟,开火,下油,炸两遍,调汁,倒进去翻炒,出锅。一行一行,前后顺序固定。换厨房、换灶台、换锅,按这步骤做出来的味道大致一样。

程序也是这种东西。一段段写下来的指令,让电脑按顺序一条一条执行。

跟人不同的地方有两个:

  • 电脑只会照字面办事。 菜谱写「翻炒至断生」,老厨师能凭经验判断什么叫断生;电脑读到「翻炒至断生」会原地卡住,因为它不知道怎么定义这件事。给程序的每一步都得是非常具体的动作。
  • 电脑不会跳过步骤,但也不会自己补漏。 菜谱漏写了「先开火」,人会下意识补上;电脑会真的不开火直接下油,然后告诉你它油已经下了,等下一步。

明白了这两点,编程里九成的「为什么没按预想跑」都能想通。

复杂的程序,归根到底由三种东西堆出来:记下一些东西、做判断、重复做。 名字以后会换,本质就这三件。

写菜谱时,「肉切成 200 克」是个很常见的写法。「200 克」就是一条信息。如果整本菜谱里反复用到这个数,作者通常会在开头写「主料:里脊 200 克」,后面正文里只说「主料」,不再每次重复 200。

程序里这种「先取个名字、后面用到时引用名字」的做法叫变量

血量 = 100
主灯颜色 = 暖黄
是否下雨 = 是

变量好处有三个:第一,名字让代码可读;第二,要改时只改一处;第三,程序运行过程中可以更新它的值。比如玩家被打了一下,「血量 = 90」,再被打一下,「血量 = 80」。

VRChat 世界里玩家进来一下、走出去一下,这种「变化的状态」全用变量表达。

菜谱常常会出现「如果……就……」。

「如果肉腌过夜,盐少放一点。」
「如果汁太稠,加点水。」

程序里这叫条件判断,常用形式是 if

如果 血量 == 0:
主角倒下,弹出复活按钮

只有满足条件,缩进里那段才会执行;不满足就跳过。if 还可以接一个 else,表示「否则就这样」。

如果 是否下雨:
打开屋檐下的灯
否则:
关掉屋檐下的灯

VRChat 世界里几乎每一种「按情况反应」的逻辑,最底层都是 if。门锁着才打不开、按钮还在冷却时按了没反应、玩家在区域里才播放音乐,全是判断。

菜谱写「翻炒一分钟」是个简化说法,真正的动作是把锅铲来回挥几十下。「重复某个动作 N 次」这件事程序里太常见,干脆造了一个专门的语法叫循环

重复 20 次:
在场景里复制一个发光球

循环可以是「重复固定次数」,也可以是「重复直到某个条件满足为止」。前一种叫 for,后一种叫 while。VRChat 里有时要给十个出生位置依次分配玩家、有时要在一组按钮里挨个找哪个被按下,循环就是干这个用的。

写菜谱时如果有一组动作反复出现,作者会专门起个名字。「调料汁:醋两勺、糖三勺、生抽一勺,搅匀。」后面正文里只说「调好料汁」,不重新列三遍配方。

程序里这种「把一段动作打包起来,后面通过名字调用」的东西叫函数,也叫方法

函数 调料汁():
取醋两勺
取糖三勺
取生抽一勺
搅匀
主流程:
切肉
调料汁()
炸两遍
倒入料汁
翻炒

函数可以接受一些参数,类似菜谱里写「这道菜按 N 人份做」时,N 是变化的输入。函数也可以返回一个结果给调用者,比如「测一下油温」会返回一个温度数字。

VRChat 脚本里随处可见的 Start()Update()Interact() 都是函数。它们是 VRChat 客户端在特定时刻替作者调用的,作者要做的是写好「被调用时执行什么」。

零基础读者很容易把程序想成「从第一行一直读到最后一行」。有些程序确实接近这样,比如命令行小工具。但 VRChat 世界里的脚本更像一张值班表:平时挂在物体上等着,事件发生时才执行对应函数。

世界加载完成 → 调 Start()
每一帧刷新 → 调 Update()
玩家按 Use 键 → 调 Interact()
有玩家进入房间实例 → 调 OnPlayerJoined(player)

所以写 VRChat 脚本时,常问的问题是:「这段代码应该挂在哪个事件下面」。按钮逻辑放 Interact(),一次性初始化放 Start(),持续移动放 Update()。这个分法比背语法更早用上。

到这里已经能描述大部分简单逻辑了。但项目稍微大一点会出现新问题:变量和函数太多,互相之间没有组织。

回到厨房比喻。一个职业厨房里不会把所有刀、所有锅、所有调料堆一桌;会按用途分区。砧板区放刀和砧板,灶台区放锅和勺,调料台放罐和瓶。每个区域里只放跟这个事有关的东西,找起来快,互相不打架。

程序里类似的分区单位叫。一个类把相关的变量和函数归到一起。

类 玩家:
数据:
血量 = 100
位置 = (0, 0, 0)
动作:
受伤(伤害):
血量 = 血量 - 伤害
移动到(目标位置):
位置 = 目标位置

类是 C# 这门语言里最重要的组织单位,也是 UdonSharp 写脚本的基本单位。第 11 章会落到具体语法,这里先认识到「类」就是「相关变量和函数的归类袋子」。

报错是程序唯一可靠的反馈方式。它代表程序在某一步发现「按字面办事」做不下去了,把现场信息抄给作者看。

报错信息里通常包含三件事:

错误类型:哪类问题
错误位置:哪个文件第几行
现场信息:当时变量长什么样

读懂这三件事的能力,比写得一手漂亮代码重要得多。第 12 章和第 40 章会再碰这件事,这里先把心理预期摆好:写代码的人每天都在跟报错打交道,老手只是看一眼就知道大概问题在哪,不是不报错。

你不需要先成为程序员才能开始

Section titled “你不需要先成为程序员才能开始”

VRChat 世界的脚本,绝大多数是几十行的小段。控制一盏灯的开关、计一个分、记录玩家上次站在哪个区域。它们不需要算法竞赛级别的能力,更接近「写一份具体的工作流程」。

读到这里能听懂的话,已经具备了开始读真正 C# 语法的心智准备。语法是用来表达上面这些朴素思路的工具(变量、判断、循环、函数、类),只是要换成机器认得的写法。

下一章把这些朴素思路落到 C# 的具体写法上。落到代码之后,会发现一直在做的事,比想象中近得多。