处理语言终极指南第一部分:基础
已发表: 2022-03-11您正在与无聊作斗争,并渴望使用您的创造力。 你想建造一些东西,一些视觉上令人印象深刻的东西,一些艺术的东西。 或者,也许您想学习编程并尽快做出令人印象深刻的事情。 如果是这样,那么处理语言就是要走的路。
到目前为止,在我使用过的所有编程语言中,Processing 无疑是最有趣的语言之一。 它是一门简单的语言 - 易于学习、理解和使用,但功能非常强大。 这几乎就像您正在使用代码行在空白画布上绘画。 没有任何严格的规则或准则可以限制您的创造力,唯一的限制是您的想象力。
在大学里,我是一个项目的助教,该项目聚集了高中生并教他们处理。 他们中的大多数没有很强的编程背景,有的甚至没有写过一行代码。 只需五天,他们就可以学习语言并制作自己的简单游戏。 成功率几乎是百分之一百,我们很少遇到失败。 在本文中,这正是我们要做的。 我将整个程序缩减为两部分。 第一部分,我将谈论语言。 我将给出一个基本的概述,一个处理过程的演练,我将给出一些提示和技巧。 然后在下一部分,我们将一步一步构建一个简单的游戏,每一步都会详细解释。 我还将使用 p5js 将游戏的代码转换为 JavaScript,以便我们的游戏可以在 Web 浏览器中运行。
你应该已经知道的
要理解并轻松阅读这些文章,您应该具备编程的基本知识,因为我不会谈论编程基础知识。 不过,我基本上不会触及任何高级编程概念,因此只需要表面上的理解即可。 有些部分我会谈到一些低级的想法和概念,例如面向对象编程 (OOP),但它们并不重要。 这些是为对语言结构感兴趣的好奇读者准备的。 如果你不想知道,你可以跳过这些部分。 除此之外,您唯一应该拥有的就是学习这种令人敬畏的语言的雄心和创建自己的游戏的热情!
如何关注
我总是赞成通过尝试和实验来学习编程。 您越早投入到自己的游戏中,您就会越快适应 Processing。 所以这将是我的第一个建议,在你自己的环境中尝试每一步。 Processing 有一个简单易用的 IDE(即代码编辑器),它是您唯一需要下载和安装的东西。 你可以在这里下载。
所以让我们开始吧!
什么是处理语言?
本节包括该语言的简要技术概述、其结构以及有关编译和执行过程的一些说明。 详细信息将包括有关编程和 Java 环境的一些高级知识。 如果您暂时不介意细节并且迫不及待地想学习和编写自己的游戏,您可以跳到“处理基础”部分。
Processing 是一种可视化编程语言,可以这么说,它允许您使用代码进行草图绘制。 然而,它本身并不完全是一种编程语言,它是他们所谓的“Java-esque”编程语言,这意味着该语言构建在 Java 平台之上,但本身并不完全是 Java。 它基于 Java,当您点击运行按钮时,您的所有代码都会被预处理并直接转换为 Java 代码。 Java 的 PApplet 类是所有处理草图的基类。 举个例子,让我们看几个基本的处理代码块:
public void setup() { // setup codes goes here } public void draw() { // draw codes goes here }
这些代码块将被转换成这样的东西:
public class ExampleFrame extends Frame { public ExampleFrame() { super("Embedded PApplet"); setLayout(new BorderLayout()); PApplet embed = new Embedded(); add(embed, BorderLayout.CENTER); embed.init(); } } public class Embedded extends PApplet { public void setup() { // setup codes goes here } public void draw() { // draw codes goes here } }
您可以看到处理代码块是用一个从 Java 的 PApplet 扩展而来的类包装的。 因此,您在处理代码中定义的所有类(如果有)都将被视为内部类。
Processing 基于 Java 的事实给了我们很多优势,尤其是如果您是 Java 开发人员。 不仅语法熟悉,而且还使您能够执行诸如在草图中嵌入 Java 代码、库、JAR 文件、直接在 Java 应用程序中使用处理小程序、定义类和使用标准数据类型(如 int)等操作、浮点数、字符等。 如果您想花一些时间进行设置,您甚至可以直接从 Eclipse 编写处理代码。 您不能做的一件事是在处理草图中使用 AWT 或 Swing 组件,因为它们与处理的循环性质相冲突。 但请放心,我们不会在本文中做任何花哨的事情。
加工基础
处理代码由两个主要部分组成,设置和绘制块。 设置块在代码执行时运行一次,绘制块连续运行。 Processing 背后的主要思想是,您在绘图块中编写的内容将每秒从上到下执行 60 次,直到您的程序终止。 我们将利用这个想法来构建一切。 我们将让我们的物体移动,保持我们的分数,检测碰撞,实施重力,并使用这个功能做几乎所有其他事情。 这个刷新循环是我们项目的心跳。 我将在后面的部分解释如何使用这个心跳来让你的代码栩栩如生。 首先,让我向您介绍Processing IDE。
处理IDE
如果您已经阅读到此为止,但仍未下载 Processing IDE,请继续下载。 在整篇文章中,我将概述一些简单的任务供您自己尝试,只有在您启动并运行 IDE 的情况下才能练习。 这里简单介绍一下处理IDE。 它非常简单且不言自明,所以我会保持简短。
如您所料,运行和停止按钮会按照它们的建议进行操作。 当您单击运行按钮时,您的代码将被编译并执行。 从本质上讲,处理程序永远不会终止,它们会永远运行,直到它们受到干扰。 您可以通过编程方式终止它,但如果您不这样做,您可以使用停止按钮。
运行和停止右侧看起来像蝴蝶的按钮是调试器。 使用调试器需要另外一篇专门介绍它的文章。 它超出了本文的范围,因此您现在可以忽略它。 调试器按钮旁边的下拉菜单是您添加/设置模组的地方。 Mods为您提供一些特定的功能,允许您为 Android 编写代码,允许您使用 Python 编写代码,等等。 Mods 也超出了范围,因此您可以将其保持在默认 Java 模式并忽略它。
代码编辑器上的窗口是您的草图通常运行的地方。 在图像中它是空白的,因为我们没有设置任何属性,如大小或背景颜色,或者我们没有绘制任何东西。
代码编辑器没什么好说的,它只是你编写代码的地方。 有行号(!)旧版本的处理没有,你无法想象当我第一次看到它们时我是多么高兴。
下面的黑框是控制台。 我们将使用它来打印内容以进行快速调试。 控制台旁边的错误选项卡是您的错误将出现的地方。 这也是 Processing 3.0 附带的一个新的有用功能。 在旧版本中,错误被打印到控制台,很难跟踪它们。
设置块
如前所述,设置块在程序启动时执行一次。 您可以使用它来进行配置以及只希望运行一次的事情,例如加载图像或声音。 这是一个示例设置块。 在您自己的环境中运行此代码并亲自查看结果。
public void setup() { // Size of our sketch will be 800x600, // and use the P2D rendering engine. size(800, 600, P2D); // We could have used this function instead of size() // fullScreen(P2D); // The background color of our sketch will be black // by default, unless specified otherwise background(0); // We could have used this to set a background image. // Note that size of our sketch should be the same as the image. // background(loadImage("test.jpg")); // Shapes and objects will be filled with red by default, // unless specified otherwise. fill(255,0,0); // Shaped and objects will have a white border by default, // unless specified otherwise. stroke(255); }
与样式(背景、填充、描边)相关的方法将在属性和设置部分进行说明。 现在,您需要知道的是我们在此处设置的设置和配置如何影响我们的整个草图。 此处编写的代码用于设置适用于整个草图的一些基本规则集。 您还应该在本节中了解以下列出的方法:
size() - 顾名思义,这个函数用于配置我们草图的大小。 它必须在设置代码块的第一行。 它可以以下列形式使用:
- 尺寸(宽度,高度);
- 尺寸(宽度、高度、渲染器);
宽度和高度值可以以像素为单位。 Size 函数接受第三个参数,renderer,用于设置我们的草图将使用哪个渲染引擎。 默认情况下,渲染器设置为 P2D。 可用的渲染器有 P2D(处理 2D)、P3D(处理 3D,如果您的草图将包含 3D 图形,则应使用)和 PDF(2D 图形直接绘制到 Acrobat PDF 文件中。可以在此处找到更多信息)。 P2D 和 P3D 渲染器使用 OpenGL 兼容的图形硬件。
fullScreen() - 从 Processing 3.0 开始,现在可以使用 fullScreen 函数代替 size() 函数。 就像 size() 函数一样,它也应该在设置块的第一行。 用法如下:
- 全屏();
- 全屏(显示);
- 全屏(渲染器);
- 全屏(显示,渲染器);
如果您在没有任何参数的情况下使用它,您的处理草图将简单地以全屏运行,并将在您的主显示器上运行。 'display' 参数用于设置你的草图将在哪个显示器上运行。 例如,如果您将外部显示器连接到您的计算机,您可以将显示变量设置为 2(或 3、4 等),然后您的草图将在那里运行。 'renderer' 参数如上面 size() 部分所述。
设置块
这是新版 Processing 中引入的另一个功能。 它是一个代码块,就像 setup 和 draw 一样。 当您想要使用可变参数定义 size() 或 fullScreen() 方法时,它很有用。 如果您使用的环境不是 Processing 自己的 IDE,例如 Eclipse,则还需要在此代码块中定义 size() 和其他样式属性,例如 smooth()。 但在大多数情况下,您将不需要它,在本文中绝对不会。
绘制块
没有什么特别的东西可以谈论拉块,但它的一切都是特别的。 绘制块是所有魔术发生的地方。 它是您程序的核心,每秒跳动 60 次。 此代码块包含您的所有代码逻辑。 你所有的形状、物体等都会写在这里。
我们将在本文中讨论的大部分代码都来自绘图块,因此清楚地了解该代码块的工作原理非常重要。 为了给您演示,您可以尝试以下方法。 首先请注意,我们可以使用print()或println()方法将任何内容打印到控制台。 打印方法仅打印到控制台,但 println 打印并在末尾附加一个换行符,因此每个 println() 将打印在单独的行中。
所以,看看下面的代码块。 首先,尝试猜测它将在控制台中打印什么。 然后,继续尝试一下:
void setup(){ } void draw(){ int x = 0; x += 1; print(x+" "); }
如果您猜到“1 2 3 4……”,我就知道了! 这是处理中的困惑之一。 还记得这个块反复被执行吗? 当您在这里定义一个变量时,它会在每个循环中一遍又一遍地定义。 在每次迭代中,x 设置为 0,递增 1 并打印到控制台。 因此我们得到结果“1 1 1 1…”。 这个例子有点明显,但当事情变得有点复杂时,它可能会令人困惑。
我们不希望 x 被覆盖,那么我们如何实现这一点并获得结果“1 2 3 4...”? 通过使用全局变量。 这没什么花哨的,我们只在绘图块之外定义变量,所以它不会在每次迭代时重新定义。 此外,变量的范围在整个草图中都可以访问。 请看下面的代码:
int x = 0; void setup(){ } void draw(){ x += 1; print(x+" "); }
您可能会问自己,在我们的块之外定义的变量如何工作? 为什么我们不使用 setup() 块,因为它在开始时执行一次? 答案与面向对象编程和作用域有关,不熟悉的可以跳过这一段。 请参阅我解释处理代码如何转换为 Java 的部分。 还记得它们是如何被 Java 类包裹起来的吗? 我们在 setup() 和 draw() 块之外编写的变量也会被包装,因此它们被视为包装我们代码的外部类的字段。 使用 x+=1 与使用 this.x+=1 相同。 在我们的例子中,它的功能也是一样的,在 draw() 的范围内没有定义名为 x 的变量,并且搜索了一个外部范围,即this的范围。 为什么我们不在 setup() 部分定义变量 x 呢? 如果我们这样做了,定义 x 的范围将是 setup 函数的范围,并且无法从 draw() 块中访问它。
绘制形状和文本
现在我们知道如何使用设置块配置我们的草图,并且我们知道绘图块的作用。 因此,是时候获得一点视觉效果并了解处理过程中有趣的部分:如何绘制形状。
在开始之前,您应该了解坐标系。 在处理中,您确定在屏幕上绘制的每个对象的坐标。 坐标系以像素为单位。 原点(即起点)是左上角,您应该给出相对于该点的坐标。 您应该知道的另一件事是,每个形状都有不同的参考点。 例如,rect() 将其左上角作为参考点。 对于 ellipse(),它是中心。 这些参考点可以通过 rectMode() 和 ellipseMode() 等方法进行更改,我将在属性和设置部分进行说明。 提供了一个示例图,以帮助您更好地理解。
本文是处理的基本概述,因此我们不会涉及任何复杂的形状,如顶点或 3D 形状。 基本的 2D 形状实际上足以让我们创建自己的游戏。 在图中,您可以看到如何绘制形状的示例。 每个形状都有自己要创建的语法,但基本思想是给出它的坐标或大小或两者兼而有之。 以下是您应该熟悉的一些形状(对于下面给出的所有值,“x”和“y”表示以像素为单位的 x 和 y 坐标,“w”和“h”也表示以像素为单位的宽度和高度值):
point() - 简单点,只需要一个坐标。 用法:
- 点(x,y)
- point(x, y, z) - 如果您使用 3 维。
line() - 用于创建一条线。 您可以创建一条只有起点和终点的线。 用法:

- 线(x1,y1,x2,y2)
- line(x1, y1, z1, x2, y2, z2) - 如果您使用 3 维。
triangle() - 用于创建三角形。 用法:三角形(x1,y1,x2,y2,x3,y3)
quad() - 用于创建四边形。 用法:四边形(x1,y1,x2,y2,x3,y3,x4,y4)
rect() - 用于创建一个矩形。 参考点默认为左上角(见图)。 这是用法:
- 矩形(x,y,w,h)
- rect(x, y, w, h, r) - 'r' 表示圆角的像素半径。
- rect(x, y, w, h, tl, tr, br, bl) - 分别为左上角、右上角、右下角、左下角的半径。 这也以像素为单位。
ellipse() - 用于创建椭圆形状。 这也用于创建一个圆形,应给出相同的宽度和高度值。 此形状的参考点默认为中心(见图)。 这是用法:
- 椭圆(x,y,w,h)
arc() - 画一条弧线。 用法:
- arc(x, y, w, h, start, stop) - 'start' 和 'stop' 用于确定开始和停止绘制圆弧的角度。 值以弧度为单位。 可以使用诸如“PI、HALF_PI、QUARTER_PI 和 TWO_PI”之类的常数。
- arc(x, y, w, h, start, stop, mode) - 'mode' 变量用于确定弧(字符串)的渲染风格。 可用选项为“OPEN、CHORD、PIE”。 OPEN 将使未绘制的部分保持无边界。 CHORD 将用边框完成未绘制的部分。 PIE 将使您的弧看起来像一个饼图。
在屏幕上显示文本类似于显示形状,基本思想是您确定要显示文本的坐标。 然而,处理文本还有更多内容。 在属性和设置部分之后,您将可以更好地控制文本,您将在其中学习如何将设置和属性应用于对象。 现在,我将展示显示文本的基础知识。 有很多方法可以做到,我只会展示要领。
text() - 显示文本。 用法:
- text(c, x, y) - 'c' 表示字符,将显示任何字母数字字符。
- text(c, x, y, z) - 如果您使用 3 个维度。
- text(str, x, y) - 'str' 是要显示的字符串。
- text(str, x, y, z) - 如果您使用 3 个维度。
- text(num, x, y) - 'num' 是要显示的数值。
- text(num, x, y, z) - 如果您使用 3 个维度。
属性和设置
本节首先要解释的是设置对象属性背后的逻辑。 填充颜色、背景颜色、边框、边框宽度、边框颜色、形状对齐、边框样式等可能是这些属性的一些示例。
当你设置一个属性时,你必须记住代码是从上到下执行的。 假设您将“填充”属性设置为红色,在该线下方绘制的所有对象都将被填充为红色,直到它被另一个填充属性覆盖。 同样的事情也适用于其他属性,但请注意,并非所有属性都会相互覆盖。 例如,“stroke”属性不会覆盖“fill”属性,而是它们一起工作。 这是您理解逻辑的可视化表示:
正如您在图像中看到的,第一行将填充颜色设置为红色,第二行将描边颜色设置为蓝色。 我们现在有两个活动设置:填充红色和蓝色笔触。 如您所料,无论我们的对象在下一行是什么,它都将被红色填充并带有蓝色笔划(如果适用)。 你可以这样继续检查图像,你就会掌握逻辑。
以下是一些常用的基本属性和设置:
样式设置
fill() - 设置对象的填充颜色。 此设置还用于为文本着色。 目前,我们只需要知道以下用法:
- fill(r, g, b) - 红色、绿色和蓝色值作为整数
- fill(r, g, b, a) - 附加 alpha 值,最大值为 255
noFill() - 将填充颜色设置为透明。
stroke() - 设置对象的笔触颜色。 Stroke 属性适用于对象周围的线条和边框。 目前,我们只需要知道以下用法:
- stroke(r, g, b) - 红色、绿色和蓝色值作为整数。
- stroke(r, g, b, a) - 附加 alpha 值,最大值为 255
noStroke() - 删除笔画。
strokeWeight() - 设置描边的宽度。 用法:
- strokeWeight(x) - x 是一个整数,表示笔画的宽度(以像素为单位)。
background() - 设置背景颜色。 目前,我们只需要知道以下用法:
- background(r, g, b) - 红色、绿色和蓝色值作为整数。
- background(r, g, b, a) - 附加 alpha 值,最大值为 255
对齐设置
ellipseMode() - 设置作为参考点对齐椭圆的位置。 用法:
- ellipseMode(mode) - 'mode' 是参数,这里是可用的参数:
- CENTER(默认):以中心为参考点。
- RADIUS:这也将中心作为参考点,但在此模式下,您指定的 w 和 h 值被视为一半(即半径而不是直径)
- CORNER:以左上角为参考点。
- CORNERS:将前两个参数(x 和 y)设置为椭圆左上角的位置,后两个参数(w 和 h)设置为椭圆左下角的位置。 所以这个模式,“宽度”和“高度”是无关紧要的。 在这种情况下,将其视为 ellipse(x_tl,y_tl,x_br,y_br) 更有意义。
rectMode() - 设置作为参考点对齐矩形的位置。 用法:
- rectMode(mode) - 'mode' 是参数,这里是可用的参数:
- CENTER:以中心为参考点。
- RADIUS:这也将中心作为参考点,但在这种模式下,您指定的 w 和 h 值被视为一半
- CORNER(默认):以左上角为参考点。
- CORNERS:将前两个参数(x 和 y)设置为椭圆左上角的位置,后两个参数(w 和 h)设置为椭圆左下角的位置。 所以这个模式,“宽度”和“高度”是无关紧要的。 在这种情况下,将其视为 rect(x_tl,y_tl,x_br,y_br) 更有意义。
文本相关设置
textSize() - 设置文本的字体大小。 用法:
- textSize(size) - 所需大小的整数值。
textLeading() - 设置文本的行高。 用法:
- textLeading(lineheight) - 行间距的像素值。
textAlign() - 设置作为参考点对齐文本的位置。 用法。
- textAlign(alignX) - 'alignX' 用于水平对齐。 可用:左、中、右
- textAlign(alignX, alignY) - 'alignY' 用于垂直对齐。 可用:顶部、底部、中心、基线。
动画
到目前为止,我们学习了如何绘制对象和文本。 但它们的问题在于它们是静态的。 现在我们如何让它们移动? 很简单,我们不是将坐标作为整数给出,而是使用变量来增加/减少它们。 有道理? 看看下面的代码:
// initialize x and y as 0 int x=0; int y=0; void setup(){ size(800,600); background(255); // set background color to white } void draw(){ fill(255,0,0); // fill color red stroke(0,0,255); // stroke color blue ellipseMode(CENTER); // ref. point to ellipse is its center ellipse(x, y, 20, 20); // draw the ellipse // increment x and y x+=5; y+=5; }
你看到我们是如何管理动画的吗? 我们将 x 和 y 设置为全局变量,并将它们的初始值设置为 0。在绘制循环中,我们创建了椭圆,将填充颜色设置为红色,描边颜色设置为蓝色,并将坐标设置为 x 和 y。 当我们增加 x 和 y 时,球只是改变了它的位置。 但是这段代码有一个问题,你注意到了吗? 作为对自己的一项简单挑战,请尝试找出问题所在,并进行测试。 结果如下:
我让这种情况发生的目的是让你意识到处理的循环性质是如何工作的。 参考“Draw Block”部分的例子,你还记得为什么我们得到“1 1 1…”而不是“1 2 3…”吗? 球留下痕迹的原因相同。 每次绘制块迭代时,x 和 y 都会增加 5,因此球会被重绘为向下和向右 5 个像素。 但是,从先前的迭代中绘制的球仍保留在视图中。 我们如何让它们消失? 有什么猜测吗?
为了消除球留下的痕迹,我们只需从设置块中删除背景(255),并将其粘贴到绘图块的第一行。 当我们的背景代码在设置块中时,它在开始时运行一次,使我们的背景变成白色。 但这还不够,我们需要将每个循环的背景设置为白色,以覆盖从前一个循环中绘制的球。 背景是第一行意味着它首先运行,它成为基础层。 在每个循环中,我们的画布被涂成白色,新元素被绘制在白色背景之上。 所以我们没有标记。
这就是在处理中为事物设置动画的想法,以编程方式操纵对象的坐标以改变它们的位置。 但是我们将如何做一些花哨的事情,比如让球保持在屏幕上? 或者也许实施重力? 我将在本文的下一部分教如何做这些事情。 我们将通过尝试和构建来学习。 我们将学习如何做到这一点并立即将它们应用到我们的游戏中。 最后,我们将拥有一款完整、可玩且充满乐趣的游戏。
键盘和鼠标交互
Processing中的键盘和鼠标交互非常简单直接。 您可以为每个事件调用一些方法,并且您在其中编写的内容将在事件发生时执行一次。 还有一些全局变量,例如 mousePressed 和 keyPressed,您可以在绘图块中使用以利用循环。 以下是一些带有解释的方法:
void setup() { size(500, 500); } void draw() { if (mousePressed) { // Codes here will be executed as long as the mouse // button is pressed if (mouseButton == LEFT){ // This lines will be executed as long as // the clicked mouse button is the left mouse // button. } } if (keyPressed) { // Codes here will be executed as long as a key // on the keyboard is pressed if (key == CODED) { // This if statement checks if the pressed key // is recognised by Processing. if (keyCode == ENTER) { // This lines will be executed if the pressed key // is the enter key. } } else{ // This lines will be executed if the pressed key // is not recognised by processing. } } } void mousePressed() { // These codes will be executed once, when mouse // is clicked. Note that mouseButton variable is // also be used here. } void keyPressed() { // These codes will be executed once, when a key // is pressed. Note that key and keyCode variables // are also usable here. }
如您所见,很容易检查是否单击了鼠标或按下了哪个键。 然而,mousePressed 和 keyCode 变量有更多选项可用。 mousePressed的可用选项是 LEFT、RIGHT 和 CENTER。 keyCode还有很多可用的; 上、下、左、右、ALT、控制、SHIFT、退格、TAB、ENTER、返回、ESC 和删除。
关于鼠标变量需要了解的一件事,我们会经常用到它,那就是如何获取鼠标的坐标。 要获得光标的准确坐标,我们可以直接在 draw() 块中使用mouseX和mouseY变量。 最后但并非最不重要的一点是,您应该查看许多其他有用的方法。 它们都记录在处理参考中。
结论
您现在应该已经熟悉了 Processing。 然而,如果你停在这里,所有这些知识都会飞走。 我强烈建议你继续练习,玩弄你所学的东西。 为了帮助您练习,我将为您提供两个练习。 你应该尽量自己做。 如果您遇到困难,Google 和 Processing Reference 应该是您最好的朋友。 我将为第一个提供代码,但查看它们应该是您做的最后一件事。
推荐练习 1
你应该制作4 个不同颜色的球,从屏幕的4 个角开始,以不同的速度穿过中心。 当您单击并按住鼠标按钮时,球应该会冻结。 当你放开鼠标时,球可以回到初始位置并继续移动。 所以,我正在寻找这样的东西。
在您自己尝试练习后,您可以在此处查看代码。
推荐练习 2
还记得著名的 DVD 屏幕保护程序,它的 DVD 标志在屏幕上跳来跳去,我们都拼命地等待它出现在角落里吗? 我希望你复制那个屏幕保护程序,但只使用一个矩形而不是 DVD 徽标。 当您启动应用程序时,屏幕应该是黑色的,并且矩形应该从随机位置开始。 每次矩形碰到角落时,它都应该改变它的颜色(当然还有方向)。 当您移动鼠标时,矩形应该消失并且背景颜色应该变成白色(它是一个屏幕保护程序,不是吗?)。 我不会在本文中给出这个练习的代码。 您应该尽力实现它,代码将在本文的第二部分提供。
Processing 终极指南的第二部分,一个构建简单游戏的分步教程,已经发布。
进一步阅读 Toptal 工程博客:
- 如何从头开始编写解释器