语句和控制流

语句是标准的,可以是赋值、函数调用、控制流结构等(见下文)。;作为语句分隔符是完全可选的。

if/else/elif

简单的条件,通过创建ifelse/elif语法。条件周围的括号是允许的,但不是必需的。鉴于基于制表符的缩进的性质,elif可以用来代替 else/if来保持一定程度的缩进。

if [expression]:
    statement(s)
elif [expression]:
    statement(s)
else:
    statement(s)

短语句可以与条件写在同一行:

if 1 + 1 == 2: return 2 + 2
else:
    var x = 3 + 3
    return x

有时,您可能希望根据布尔表达式分配不同的初始值。在这种情况下,三元 if 表达式就派上用场了:

var x = [value] if [expression] else [value]
y += 3 if y < 10 else -1

While

使用while语法创建简单循环。循环可以使用break或继续使用continue

while [expression]:
    statement(s)

For

要遍历一个范围,例如数组或表,请使用for循环。迭代数组时,当前数组元素存储在循环变量中。迭代字典时,存储在循环变量中。

for x in [5, 7, 11]:
    statement # Loop iterates 3 times with 'x' as 5, then 7 and finally 11.

var dict = {"a": 0, "b": 1, "c": 2}
for i in dict:
    print(dict[i]) # Prints 0, then 1, then 2.

for i in range(3):
    statement # Similar to [0, 1, 2] but does not allocate an array.

for i in range(1, 3):
    statement # Similar to [1, 2] but does not allocate an array.

for i in range(2, 8, 2):
    statement # Similar to [2, 4, 6] but does not allocate an array.

for c in "Hello":
    print(c) # Iterate through all characters in a String, print every letter on new line.

for i in 3:
    statement # Similar to range(3)

for i in 2.2:
    statement # Similar to range(ceil(2.2))

Match(Switch)

一个match语句用于程序的分支执行。它相当于switch许多其他语言中的语句,但提供了一些附加功能。

基本语法:

match [expression]:
    [pattern](s):
        [block]
    [pattern](s):
        [block]
    [pattern](s):
        [block]

熟悉 switch 语句的人的速成课程

  1. 替换switchmatch
  2. 删除case
  3. 删除任何breaks。如果您不想在break默认情况下使用,您可以使用continuefor fallthrough。
  4. 更改default为单个下划线。

控制流程

图案从上到下匹配。如果模式匹配,将执行第一个相应的块。之后,在match语句下方继续执行。您可以使用continue停止当前块中的执行并检查其下方模式中的其他匹配项。

Class

默认情况下,所有脚本文件都是未命名的类。在这种情况下,您只能使用文件的路径(使用相对路径或绝对路径)来引用它们。例如,如果您命名一个脚本文件character.gd

# Inherit from 'Character.gd'.

extends "res://path/to/character.gd"

# Load character.gd and create a new node instance from it.

var Character = load("res://path/to/character.gd")
var character_node = Character.new()

您可以为您的类命名,以便在 Godot 的编辑器中将其注册为新类型。为此,您使用class_name关键字。您可以添加一个可选的逗号,后跟图像的路径,以将其用作图标。然后,您的类将在编辑器中显示其新图标:

# Item.gd

extends Node
class_name Item, "res://interface/icons/item.png"

../../../_images/class_name_editor_register_example.png

警告

如果脚本位于res://addons/目录中,并且脚本是启用的编辑器插件的一部分,class_name 则只会导致节点显示在“创建新节点”对话框中。有关 更多信息,请参阅制作插件

这是一个类文件示例:

# Saved as a file named 'character.gd'.

class_name Character


var health = 5


func print_health():
    print(health)


func print_this_script_three_times():
    print(get_script())
    print(ResourceLoader.load("res://character.gd"))
    print(Character)

笔记

Godot 的类语法很紧凑:它只能包含成员变量或函数。您可以使用静态函数,但不能使用静态成员变量。同样,引擎每次创建实例时都会初始化变量,这包括数组和字典。这是本着线程安全的精神,因为脚本可以在用户不知情的情况下在单独的线程中初始化。

继承

一个类(存储为文件)可以继承自:

  • 一个全局类。
  • 另一个类文件。
  • 另一个类文件中的内部类。

不允许多重继承。

继承使用extends关键字:

# Inherit/extend a globally available class.
extends SomeClass

# Inherit/extend a named class file.
extends "somefile.gd"

# Inherit/extend an inner class in another file.
extends "somefile.gd".SomeInnerClass

要检查给定实例是否继承自给定类,is可以使用关键字:

# Cache the enemy class.
const Enemy = preload("enemy.gd")

# [...]

# Use 'is' to check inheritance.
if entity is Enemy:
    entity.apply_damage()

要调用父类中的函数(即extend当前类中的一个),.请在函数名前加上:

.base_func(args)

这特别有用,因为扩展类中的函数替换了父类中同名的函数。如果您仍想调用它们,可以使用前缀.(如super其他语言中的关键字):

func some_func(x):
    .some_func(x) # Calls the same function on the parent class.

笔记

在所有父类中自动调用_init诸如 、_enter_tree_exit_tree_process_physics_process、 等大多数通知的 默认函数 。重载它们时无需显式调用它们。

类构造函数

在类实例化时调用的类构造函数名为_init。如前所述,继承类时会自动调用父类的构造函数。所以,通常不需要._init() 显式调用。

与常规函数的调用不同,就像上面的例子中的 .some_func,如果继承类的构造函数接受参数,它们会像这样传递:

func _init(args).(parent_args):
   pass

通过示例可以更好地解释这一点。考虑这个场景:

# State.gd (inherited class) 父类
var entity = null
var message = null


func _init(e=null):
    entity = e


func enter(m):
    message = m


# Idle.gd (inheriting class) 子类
extends "State.gd"


func _init(e=null, m=null).(e):
    # Do something with 'e'.
    message = m
  1. 如果父类( State.gd) 定义了一个接受参数e的构造函数_init,那么子类 ( Idle.gd) 也必须 定义_init,并将适当的参数传递给_init
  2. Idle.gd可以有与父类不同数量的参数
  3. 在上面的示例中,e传递给State.gd构造函数与e传递给Idle.gd.
  4. 如果Idle.gd_init构造函数接受 0 个参数,它仍然需要将一些值传递给State.gd父类,即使它什么都不做。这让我们认识到,您也可以在基本构造函数中传递文字,而不仅仅是变量。例如。:
# Idle.gd

func _init().(5):
    pass