创建第一个脚本¶
在本课中,你将用GDScript编写第一个脚本,使Godot图标转圈。正如我们 在介绍 中提到的,我们假设你有编程基础。

参见
要了解更多关于GDScript、其关键字和语法的信息,请前往 GDScript 参考。
项目设置¶
请从头开始创建一个新项目。您的项目应该包含一张图片:Godot 图标,我们经常在社区中使用它来制作原型。
我们需要创建一个 Sprite 节点来在游戏中显示它。在“场景”面板中,点击“其他节点”按钮。

在搜索栏中输入“Sprite”来过滤节点,双击 Sprite 来创建节点。

你的“场景”选项卡现在应该只有一个 Sprite 节点。

Sprite 节点需要用于显示的纹理。在右边的“检查器”中,你可以看到 Texture(纹理)属性写着“[空]”。要显示 Godot 图标,请点击“文件系统”面板中的 icon.png
文件并将其拖到 Texture 插槽上。

注解
您可以通过将图像拖放到视窗上来自动创建 Sprite 节点。

然后,点击并拖动视窗中的图标,使其在游戏视图中居中。

新建脚本¶
在场景面板的 Sprite 上点击右键并选择“附加脚本”,来将一个新的脚本附加到我们的节点上。

弹出“附加节点脚本”窗口。你可以选择脚本的语言和文件路径,以及其他选项。
把模板从默认改为空Empty,得到一个干净的脚本。其他选项保持默认,然后点击创建按钮来生成脚本。

此时将显示“脚本”工作区,并打开新文件并显示以下代码行:
extends Sprite
每个 GDScript 文件都是一个隐含的类。extends
关键字定义了这个脚本所继承或扩展的类。这里它是 Sprite
,意味着我们的脚本将获得 Sprite 节点的所有属性和函数,包括它继承的 Node2D
、CanvasItem
、Node
等类。
注解
在GDScript中,如果你省略了带有 extends
关键字的一行,你的类将隐式扩展 Reference,Godot使用它来管理你的应用程序的内存。
继承的属性包括您可以在“检查器”面板中看到的属性,例如节点的 texture
。
注解
“检查器”默认使用“Title Case”形式展示节点的属性,将单词的首字母大写、用空格分隔。在 GDScript 代码中,这些属性使用的是“snake_case”,全小写、单词之间使用下划线分隔。
你可以在检查器中悬停任何属性的名称,查看描述和代码中的标识符。
你好,世界!¶
我们的脚本目前没有做任何事情。让我们开始打印文本“Hello, world!”到底部输出面板。
往脚本中添加以下代码:
func _init():
print("Hello, world!")
让我们把它分解一下。 func
关键字定义了一个名为 _init
的新函数。这是类构造函数的一个特殊名称。如果你定义了这个函数,引擎会在内存中创建每个对象或节点时调用 _init()
。
注解
GDScript 是一种基于缩进的语言。行首的制表符是 print()
代码工作的必要条件。如果你省略了它或者没有正确缩进一行,编辑器将以红色高亮显示,并显示以下错误信息:“Unexpected indentation.”(意外的缩进。)
如果你还没有保存场景,请保存,然后按 F6 来运行它。看一下底部展开的“输出”面板。它应该显示“Hello, world!”

将 _init()
函数删除,这样你就只有一行 extends Sprite
了。
四处旋转¶
是时候让我们的节点移动和旋转了。为此,我们将向脚本中添加两个成员变量:以像素每秒为单位的移动速度和以弧度每秒为单位的角速度。
extends Sprite
var speed = 400
var angular_speed = PI
成员变量位于脚本的顶部,在函数之前。附加了此脚本的每个节点实例都将具有自己的 speed
和 angular_speed
属性副本。
注解
与其他一些引擎一样,Godot 中的角度默认以弧度为单位工作,但如果您更喜欢以度为单位计算角度,则可以使用内置函数和属性。
为了移动我们的图标,我们需要在游戏循环中每一帧更新其位置和旋转。我们可以使用 Node
类中的虚函数 _process()
。如果你在任何扩展自 Node 类的类中定义它,如 Sprite,Godot将在每一帧调用该函数,并传递给它一个名为 delta
的参数,即从上一帧开始经过的时间。
注解
游戏的工作方式是每秒钟渲染许多图像,每幅图像称为一帧,而且是循环进行的。我们用每秒帧数(FPS)来衡量一个游戏产生图像的速度。大多数游戏的目标是60FPS,尽管你可能会发现在较慢的移动设备上的数字是30FPS,或者是虚拟现实游戏的90至240。
引擎和游戏开发者尽最大努力以恒定的时间间隔更新游戏世界和渲染图像,但在帧的渲染时间上总是存在着微小的变化。这就是为什么引擎为我们提供了这个delta时间值,使我们的运动与我们的帧速率无关。
在脚本的底部,定义该函数:
func _process(delta):
rotation += angular_speed * delta
func
关键字定义了一个新函数。在它之后,我们必须在括号里写上函数的名称和它所接受的参数。冒号结束定义,后面的缩进块是函数的内容或指令。
注解
请注意 _process()
和 _init()
一样都是以下划线开头的。按照约定,这是 Godot 的虚函数,也就是你可以覆盖的与引擎通信的内置函数。
函数内部的那一行 rotation += angular_speed * delta
每一帧都会增加我们的精灵的旋转量。这里 rotation
是从 Sprite
所扩展的 Node2D
类继承的属性。它可以控制我们节点的旋转,以弧度为单位。
小技巧
在代码编辑器中,你可以在任何内置的属性或函数上点击ctrl,如 position
, rotation
,或 _process
以在新标签中打开相应的文档。
运行该场景,可以看到 Godot 的图标在原地转动。

前进¶
现在我们来让节点移动。在 _process()
函数中添加下面两行代码,确保每一行都和前一行的缩进保持一致。
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
正如我们所看到的,var
关键字可以定义新变量。如果你把它放在脚本顶部,定义的就是类的属性。在函数内部,定义的则是局部变量:只在函数的作用域中存在。
我们定义一个叫 velocity
的局部变量,它是 2D 向量,表示方向和速度。要让节点向前移动,我们可以从 Vector2 类的常量 Vector2.UP 开始,这是个朝上的向量,调用它的 Vector2.rotated()
方法去进行旋转。表达式 Vector2.UP.rotated(rotation)
是指向我们的图标上方的向量。与我们的 speed
属性相乘后,得到的就是可以用来将节点向前移动的速度。
我们在节点的 position
里加上 velocity * delta
来实现移动。位置本身是 Vector2 类型的,是 Godot 用于表示 2D 向量的内置类型。
运行场景就可以看到 Godot 头像在绕圈圈。

注解
使用这样的方法不会考虑与墙壁和地面的碰撞。在 您的第一个 2D 游戏 中,你会学到另一种移动对象的方法,可以检测碰撞。
我们的节点目前是自行移动的。在下一部分中,我们会让玩家的输入来控制它。