游戏设计:原型与开发 19:U3D工位布置与性格说明书
- 一、先摆工位,再干活
- 二、换场:从"环境"到"语言"
- 三、标签一:编译型------为什么高投入的游戏都用它
-
- [编译型 vs 解释型](#编译型 vs 解释型)
- [回到 Unity:为什么三种脚本一样快](#回到 Unity:为什么三种脚本一样快)
- 四、标签二:托管代码------你终于不用管内存了
- [五、标签三:强类型------`int x = 5;` 背后的保护](#五、标签三:强类型——
int x = 5;背后的保护) - 六、标签四:基于函数------"帮我带瓶牛奶"
- 七、小结
一、先摆工位,再干活
上一篇我们把 Unity 装好了、把 AngryBots 玩了一遍、还编译出了网页版。这一篇的前半段,作者要做一件非常"手艺人"的事:整理工位。
顺序是这样的:
Layout菜单选 2 by 3;- 在 Project 面板的选项卡菜单里选 One Column Layout(一栏式布局),先让项目面板不那么挤;
- 拖动选项卡移动面板,拖动面板之间的边框调整大小;
Window > Console调出控制台,拖到 Hierarchy 下方;- 再挪动 Project,得到最终布局;
Save Layout...存为 " GameDev"。
最后那一步有个小巧思:文件名前故意留一个空格。因为菜单是按名字排序的,开头是空格,它就永远排在最上面。
这种细节属于"用过十年的人才会告诉你"的类型。省下的是每次找菜单的两秒钟,攒下的是不被打断的心流 🔧。
拖面板时的两种"幻影"
拖动选项卡时,新位置会显示一个虚化的面板轮廓 ,告诉你"放这儿会变成什么样";某些位置会触发停靠(dock),轮廓会变成实心预览。作者专门用截图对比了这两种状态。
最终工位:六个面板各管一摊
#mermaid-svg-V9umiMkLWhyy04Bw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-V9umiMkLWhyy04Bw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-V9umiMkLWhyy04Bw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-V9umiMkLWhyy04Bw .error-icon{fill:#552222;}#mermaid-svg-V9umiMkLWhyy04Bw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-V9umiMkLWhyy04Bw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-V9umiMkLWhyy04Bw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-V9umiMkLWhyy04Bw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-V9umiMkLWhyy04Bw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-V9umiMkLWhyy04Bw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-V9umiMkLWhyy04Bw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-V9umiMkLWhyy04Bw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-V9umiMkLWhyy04Bw .marker.cross{stroke:#333333;}#mermaid-svg-V9umiMkLWhyy04Bw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-V9umiMkLWhyy04Bw p{margin:0;}#mermaid-svg-V9umiMkLWhyy04Bw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-V9umiMkLWhyy04Bw .cluster-label text{fill:#333;}#mermaid-svg-V9umiMkLWhyy04Bw .cluster-label span{color:#333;}#mermaid-svg-V9umiMkLWhyy04Bw .cluster-label span p{background-color:transparent;}#mermaid-svg-V9umiMkLWhyy04Bw .label text,#mermaid-svg-V9umiMkLWhyy04Bw span{fill:#333;color:#333;}#mermaid-svg-V9umiMkLWhyy04Bw .node rect,#mermaid-svg-V9umiMkLWhyy04Bw .node circle,#mermaid-svg-V9umiMkLWhyy04Bw .node ellipse,#mermaid-svg-V9umiMkLWhyy04Bw .node polygon,#mermaid-svg-V9umiMkLWhyy04Bw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-V9umiMkLWhyy04Bw .rough-node .label text,#mermaid-svg-V9umiMkLWhyy04Bw .node .label text,#mermaid-svg-V9umiMkLWhyy04Bw .image-shape .label,#mermaid-svg-V9umiMkLWhyy04Bw .icon-shape .label{text-anchor:middle;}#mermaid-svg-V9umiMkLWhyy04Bw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-V9umiMkLWhyy04Bw .rough-node .label,#mermaid-svg-V9umiMkLWhyy04Bw .node .label,#mermaid-svg-V9umiMkLWhyy04Bw .image-shape .label,#mermaid-svg-V9umiMkLWhyy04Bw .icon-shape .label{text-align:center;}#mermaid-svg-V9umiMkLWhyy04Bw .node.clickable{cursor:pointer;}#mermaid-svg-V9umiMkLWhyy04Bw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-V9umiMkLWhyy04Bw .arrowheadPath{fill:#333333;}#mermaid-svg-V9umiMkLWhyy04Bw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-V9umiMkLWhyy04Bw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-V9umiMkLWhyy04Bw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V9umiMkLWhyy04Bw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-V9umiMkLWhyy04Bw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V9umiMkLWhyy04Bw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-V9umiMkLWhyy04Bw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-V9umiMkLWhyy04Bw .cluster text{fill:#333;}#mermaid-svg-V9umiMkLWhyy04Bw .cluster span{color:#333;}#mermaid-svg-V9umiMkLWhyy04Bw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-V9umiMkLWhyy04Bw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-V9umiMkLWhyy04Bw rect.text{fill:none;stroke-width:0;}#mermaid-svg-V9umiMkLWhyy04Bw .icon-shape,#mermaid-svg-V9umiMkLWhyy04Bw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V9umiMkLWhyy04Bw .icon-shape p,#mermaid-svg-V9umiMkLWhyy04Bw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-V9umiMkLWhyy04Bw .icon-shape .label rect,#mermaid-svg-V9umiMkLWhyy04Bw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V9umiMkLWhyy04Bw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-V9umiMkLWhyy04Bw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-V9umiMkLWhyy04Bw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 右侧:属性
中间:世界
左侧:资产与层级
拖入场景
选中
选中
播放
报错
Project 面板
硬盘 Assets 文件夹的映射
Hierarchy 面板
当前场景的所有 GameObject
Console 面板
错误 · 日志 · Debug.Log 输出
Scene 面板
三维空间的导航与编辑
Game 面板
运行时画面 / 主摄像机视图
Inspector 面板
选中对象的详情与编辑
图说 :这张图把"六个面板"翻译成了一条工作流的方向 :左边是"素材从哪来"(Project)和"场上有谁"(Hierarchy),中间是"世界长什么样"(Scene)与"玩家看到什么"(Game),右边是"这个对象到底有什么参数"(Inspector),下面兜底的 Console 负责在你搞砸时开口说话。箭头不是随便画的------
Project → Scene是拖拽,选中 → Inspector是点击,播放 → 报错是运行。记住方向,就记住了界面。
| 面板 | 一句话职责 | 新手最容易搞混的点 |
|---|---|---|
| Scene | 三维场景导航:选择、移动、旋转、缩放 | 它不是玩家看到的画面 |
| Game | 运行时实际画面,也显示主摄像机视图 | 不点播放时,它只是摄像机预览 |
| Hierarchy | 当前场景里的每个 GameObject | 只在当前场景,跨场景看不到 |
| Project | 项目所有资源(Assets) | 资源存在 ≠ 出现在场景里 |
| Inspector | 查看/编辑选中对象的信息 | 选中什么就显示什么,没选中就空着 |
| Console | 错误、Bug 消息、Debug.Log 输出 |
它是你未来最常看的面板 |
作者对 Console 的提醒值得提前记住:第 18 章和第 19 章会频繁 用到它。顺带一个冷知识------Unity 里 print() 和 Debug.Log() 都会把消息打到 Console 面板。
二、换场:从"环境"到"语言"
第 16 章到此结束,一句话总结:"Unity 的图形能力有多强,你看到了;但本书不教你怎么做漂亮的模型和着色器。"
第 17 章开门见山,给 C# 贴了五个标签:
- 是编译型语言
- 是托管代码
- 是强类型语言
- 基于函数
- 面向对象
下面逐个拆。别急,这五条不是术语轰炸,每一条都会在某天救你一次。
三、标签一:编译型------为什么高投入的游戏都用它
先补一个常识:每块芯片只懂自己那套"简单命令集",叫机器语言。它跑得极快,人类极难读。作者举了一行:
00000000001 000100011000000100000
这在某种芯片上确实有含义,对人来说就是天书。更早的年代,人们用穿孔卡编程:打孔 = 1,不打孔 = 0。
于是有了"编辑语言"(面向人类可读的编程语言)------它站在人和机器之间,一头让计算机容易编译,一头让程序员容易读懂。
编译型 vs 解释型
#mermaid-svg-dIHh4tVdO83Oowkc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dIHh4tVdO83Oowkc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dIHh4tVdO83Oowkc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dIHh4tVdO83Oowkc .error-icon{fill:#552222;}#mermaid-svg-dIHh4tVdO83Oowkc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dIHh4tVdO83Oowkc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dIHh4tVdO83Oowkc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dIHh4tVdO83Oowkc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dIHh4tVdO83Oowkc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dIHh4tVdO83Oowkc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dIHh4tVdO83Oowkc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dIHh4tVdO83Oowkc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dIHh4tVdO83Oowkc .marker.cross{stroke:#333333;}#mermaid-svg-dIHh4tVdO83Oowkc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dIHh4tVdO83Oowkc p{margin:0;}#mermaid-svg-dIHh4tVdO83Oowkc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dIHh4tVdO83Oowkc .cluster-label text{fill:#333;}#mermaid-svg-dIHh4tVdO83Oowkc .cluster-label span{color:#333;}#mermaid-svg-dIHh4tVdO83Oowkc .cluster-label span p{background-color:transparent;}#mermaid-svg-dIHh4tVdO83Oowkc .label text,#mermaid-svg-dIHh4tVdO83Oowkc span{fill:#333;color:#333;}#mermaid-svg-dIHh4tVdO83Oowkc .node rect,#mermaid-svg-dIHh4tVdO83Oowkc .node circle,#mermaid-svg-dIHh4tVdO83Oowkc .node ellipse,#mermaid-svg-dIHh4tVdO83Oowkc .node polygon,#mermaid-svg-dIHh4tVdO83Oowkc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dIHh4tVdO83Oowkc .rough-node .label text,#mermaid-svg-dIHh4tVdO83Oowkc .node .label text,#mermaid-svg-dIHh4tVdO83Oowkc .image-shape .label,#mermaid-svg-dIHh4tVdO83Oowkc .icon-shape .label{text-anchor:middle;}#mermaid-svg-dIHh4tVdO83Oowkc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dIHh4tVdO83Oowkc .rough-node .label,#mermaid-svg-dIHh4tVdO83Oowkc .node .label,#mermaid-svg-dIHh4tVdO83Oowkc .image-shape .label,#mermaid-svg-dIHh4tVdO83Oowkc .icon-shape .label{text-align:center;}#mermaid-svg-dIHh4tVdO83Oowkc .node.clickable{cursor:pointer;}#mermaid-svg-dIHh4tVdO83Oowkc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dIHh4tVdO83Oowkc .arrowheadPath{fill:#333333;}#mermaid-svg-dIHh4tVdO83Oowkc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dIHh4tVdO83Oowkc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dIHh4tVdO83Oowkc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dIHh4tVdO83Oowkc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dIHh4tVdO83Oowkc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dIHh4tVdO83Oowkc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dIHh4tVdO83Oowkc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dIHh4tVdO83Oowkc .cluster text{fill:#333;}#mermaid-svg-dIHh4tVdO83Oowkc .cluster span{color:#333;}#mermaid-svg-dIHh4tVdO83Oowkc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dIHh4tVdO83Oowkc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dIHh4tVdO83Oowkc rect.text{fill:none;stroke-width:0;}#mermaid-svg-dIHh4tVdO83Oowkc .icon-shape,#mermaid-svg-dIHh4tVdO83Oowkc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dIHh4tVdO83Oowkc .icon-shape p,#mermaid-svg-dIHh4tVdO83Oowkc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dIHh4tVdO83Oowkc .icon-shape .label rect,#mermaid-svg-dIHh4tVdO83Oowkc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dIHh4tVdO83Oowkc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dIHh4tVdO83Oowkc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dIHh4tVdO83Oowkc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 计算机编程语言
机器可读懂
人类可读懂的编辑语言
机器语言
编译型
解释型
非托管代码
BASIC · C++
托管代码
C# · Java
JavaScript · PHP · Python · Perl
图说 :这是原书图 17-1 的结构。请注意两个容易看漏的地方:第一,"托管/非托管"是挂在编译型下面的分支,跟"解释型"不是同一层;第二,C# 和 Java 都走"先编译成中间产物、再由运行时托管执行"的路子,所以它既不是纯机器码直出,也不像脚本那样每次现解释。这张分类图的价值,是让你以后听到"XX 是脚本语言"时,能立刻定位它在树上的位置。
两者的差别,作者讲得很干脆:
| 维度 | 解释型(JS / PHP / Python) | 编译型(C# / C++ / Java) |
|---|---|---|
| 执行方式 | 每次运行时现场翻译 | 先编译成可执行文件,再直接运行 |
| 移植性 | 强,几乎哪儿都能跑 | 要为每个平台各编译一次 |
| 速度 | 慢(翻译耗时 + 无法针对设备优化) | 快(编译期可做大量优化) |
| 游戏中的表现 | 三维游戏容易卡 | 更高帧率、更细致画面、更灵敏操作 |
关键那句是:"因为一段解释型代码要在所有设备上运行,所以无法针对某种运行设备做优化。" 这是"通用"的代价------想讨好所有人,就讨好不了任何一个人。
而编译型的优势,对游戏来说非常具体:更高的帧率、更细的画面、更跟手的操作。所以高投入的游戏基本都用编译型语言------代价是每个平台都得重新编译一次。
作者还举了两个"绑定平台"的例子:Objective-C 是苹果专属(OSX/iOS);XNA 是微软给 Windows PC 和 Xbox 360 准备的 C# 风格语言。
回到 Unity:为什么三种脚本一样快
这里又提了一次 CIL:C#、UnityScript、Boo 都会在额外的一次编译中变成通用中间语言,再针对 iOS、Android、Mac、Windows、Wii、Xbox 甚至 WebGL 编译。
"一次编写,到处编译"不是 Unity 首创,但 Unity 把它整合得比作者见过的任何软件都好。不过他也提醒:手机触屏和 PC 鼠标键盘的操作逻辑本身不同,代码在不同平台上通常会有细微差异。
四、标签二:托管代码------你终于不用管内存了
C++、Objective-C 这类传统编译型语言,需要程序员手动分配和释放内存。忘了释放?内存泄漏。泄漏到把机器吃满?崩溃。
C# 是托管代码 :内存的分配与释放自动完成。作者很诚实地补了一句:托管代码仍然可能泄漏,但"意外导致泄漏的情况会更难发生"。
这一条对新手意义重大:你可以先专心把逻辑写对,而不是在第三周就开始和指针搏斗。
五、标签三:强类型------int x = 5; 背后的保护
变量就是个有名字的容器。代数里写 x = 5,之后问 x + 2,你知道是 7。
但在 JavaScript 这类弱类型语言里,x 现在装数字 5,过会儿可以装一张图,再装一段音频。而 C# 要求创建变量时就声明类型:
csharp
int x = 5; // 只能装整数,编译器从此刻起盯着它
强类型让编程"更难"了一点,换来三样东西:
- 编译器能做更多优化;
- 编辑器(当年的 MonoDevelop)能实时语法检查,很像 Word 的拼写检查;
- 代码自动完成更准,按 Tab 接受建议,一分钟能省几百次按键。
csharp
// 强类型的日常:编译器在你还未运行时就拦住了错误
int score = 100;
score = "满分"; // ❌ 编译期报错:无法将 string 隐式转换为 int
这段代码在说明什么 :它展示的不是"报错",而是报错的时机 。弱类型语言可能让你跑到第三关才莫名其妙地崩;强类型语言在你按下保存的那一刻就把问题指出来了。错误越早暴露,修复成本越低------这条规律会贯穿整本书。
六、标签四:基于函数------"帮我带瓶牛奶"
早期程序就是一条条命令从头跑到尾,像给朋友指路:沿 Vermont 街向北、到 I-10 向西 7.5 英里、上 I-405 向南 2 英里、Venice 大道下、右转 Sawtelle......
后来有了循环和子过程。再后来,函数语言允许你给一段代码起名字,把一堆动作封装进去。
作者举的例子非常生活化:你让朋友顺路买牛奶,不需要教他"看到商店→停车→下车→进店→找牛奶→付款→回车上→继续上路",因为他早就会了。你只需要说:
"哥们,路上要是有商店,能帮我
BuySomeMilk()吗?"
csharp
// 函数把细节藏起来,只对外暴露意图
void BuySomeMilk()
{
FindStore();
StopCar();
EnterStore();
PayForMilk();
ReturnToCar();
}
这段代码在说明什么 :调用方只需要认识
BuySomeMilk()这个名字,不需要知道里面七步怎么走。这就是"封装"的日常形态------它不是架构术语,它就是"别让我重复交代"。
函数的第二个好处是复用:写一次,之后整个项目、甚至下一个项目都能用。本书就会写一个 Utils.cs,把常用函数攒起来。
七、小结
这一篇里,Unity 那边你学会的是摆放工作台:六个面板各管一摊,布局存成 " GameDev",从此不再手忙脚乱。
C# 这边你拿到的是性格说明书的前四条:
- 编译型 → 快,但要为平台各编译一次;
- 托管 → 内存自动管,少踩一半的坑;
- 强类型 → 错误提前暴露,编辑器还能帮你补全;
- 基于函数 → 给动作起名字,然后反复使用。

第五条"面向对象"还没展开,它会解释 Unity 里为什么一切都叫"对象"。下一篇继续。