说明:Godot的专用脚本语言
历史:总结一下就是由于其他语言的总总不适合Godot,最后GDScript就诞生了。此处省略一万字……想详细了解的可以看原文
示例
通过语法能够更好的学习,所以这里有一个简单的示例
1. #a file is a class! # 一个文件是一个类
2.
3. # inheritance # 继承
4. extends BaseClass
5.
6. # member variables # 成员变量
7.
8. var a=5
9. var s="Hello"
10. var arr=[1,2,3]
11. var dict={"key":"value", 2:3}
12.
13. # constants # 常量
14.
15. const answer=42
16. const thename="Charly"
17.
18. # built-in vector types # 内置vector类型
19.
20. var v2 = Vector2(1,2)
21. var v3 = Vector3(1,2,3)
22.
23. # function # 函数
24.
25. func some_function(param1,param2):
26. var local_var=5
27. if param1 < local_var:
28. print(param1)
29. elif param2 > 5:
30. print(param2)
31. else:
32. print("fail!")
33.
34. for i in range(20):
35. print(i)
36.
37. while(param2!=0):
38. param2-=1
39.
40. var local_var2 = param1+3
41. return local_var2
42.
43.
44. # subclass # 子类
45.
46. class Something:
47. var a=10
48.
49. # constructor # 构造器
50.
51. func _init():
52. print("constructed!")
53. var lv = Something.new()
54. print(lv.a)
55.
复制代码语言
标识符
标识符可以是一个包含任何字母、数字、下划线的字符串,但是不能以数字开头,并区分大小写。
关键字
下表列出了支持的关键字,由于关键字都是保留字,所以不能用来做标识符。
操作符
下表是支持的操作符和他们的优先级:
字面值
注释:用“#”来注释一行语句
- # This is a comment
复制代码内置类型基础内置类型
在GDScript中的一个内置变量可以被指定多种内置类型
null:空类型
bool:布尔类型,只有true或false
int:整型,可以包含正整数和负整数
float:浮点型,包含浮点值
String:unicode格式的字符序列,包含标准的C转义序列
矢量内置类型
Vector2/Size2
2D矢量类型,包含x和y字段,能够访问可读的宽和高字段,也能做为数组被访问。
Rect2
2D矩形类型,包含两个矢量字段,“pos”和“size”,另外还包含一个“pos+size”的“end”字段。
Vector3
3D矢量类型,包含x,y,z字段。也能被当做数组来访问。
Matrix32
用做2D转换的3x2矩阵。
Plane
标准化形式的3D平面,包含一个“标准”矢量字段和一个“d”标量距离。
Quat
四元数,用于代表一个3D旋转的数据类型,对于插值旋转很有用。
AABB/Box3
轴对齐包围盒(或可选的,3D盒)。包含2个矢量字段,“pos”和“size”。另外包含一个“pos+size”的“end”字段
Matrix3
用做3D旋转和缩放的3x3矩阵。包含3个矢量字段x,y,z,能做为数组或3D矢量被访问。
Transform
3D转换,包含一个类型是Matrix3的“basis”字段和Vector3类型的“origin”字段
引擎内置类型
Color
Color数据类型,包含r,g,b,a字段。也能为hue/saturation/value做为h,
s,v被访问。
Image
包含一个能够直接访问其像素的自定义格式图片。
NodePath
节点的编译路径,主要用于场景系统,可以很容易的从字符串指定或指定到字符串。
RID
资源ID(RID),服务器用通用的资源ID来引用不可见的数据。
Object
所有事物的基类,不是一个内置类型
InputEvent
InputEvent对象非常紧凑的包含了从输入设备获取的事件。他们能够从帧到帧被大量的接收,他们能够用自己的数据类型优化。
容器内置类型
Array
数组是对象序列,长度可变,索引从0开始。
1. var arr=[]
2. arr=[1,2,3]
3. arr[0]="Hi!"
复制代码数组在内存中以线性分配,所以很快,但是很大的数组(超过几万的元素)可能生成碎片。
对于一些内置数据类型,有专门的数组(如下),用更少的内存,但是他们运行会更慢,所以只适合处理很大的数据。
Dictionary
字典,关联式容器,其中包含了唯一的键对值的引用
1. var d={4:5, "a key":"a value", 28:[1,2,3]}
2. d["Hi!"]=0
复制代码同样支持lua样式的语法
1. var d= {
2. somekey=2,
3. otherkey=[2,3,4],
4. morekey="Hello"
5. }
复制代码ByteArray
字节数组,只能包含bytes(从0到255的整数)。
IntArray
整形数组,只能包含整数。
FloatArray
浮点型数组,只能包含浮点数。
StringArray
字符串型数组,只能包含字符串。
Vector2Array
Vector2型数组,只能包含2D矢量。
Vector3Array
Vector3型数组,只能包含3D矢量。
ColorArray
Color型数组,只能包含颜色。
数据
变量
变量的存在方式有类成员变量和方法中的局部变量。用“var”来创建变量,并可以在初始化时随意的赋值。
1. var a # datatype is null by default # 默认数据类型是null
2. var b = 5
3. var c = 3.8
4. var d = b+c # variables are always initialized in order # 变量通常按顺序初始化
复制代码常量
常量类似于变量,但是必须是常量或常量表达式,并且在初始化时应该被赋值
1. const a = 5
2. const b = Vector2(20,20)
3. const c = 10+20 # constant expression # 常量表达式
4. const d = Vector2(20,30).x # constant expression: 20 # 常量表达式:20
5. const e = [1,2,3,4][0] # constant expression: 1 # 常量表达式:1
6. const f = sin(20) # sin() can be used in constant expression # sin()会被常量表达式所使用
7. const g = x+20 # invalid, not a constant expression! # 无效的声明方式,没有常量表达式!
复制代码函数
函数总是属于一个类。变量的范围优先级查找顺序是:局部变量→类成员变量→全局变量。“self”被用来访问类成员,但是也不是永远需要如此(不必像Python中一样定义为第一个参数)。由于性能的原因,函数不被看作是类成员,所以他们不能直接被引用。函数可以在任何一点返回,默认返回值是null。
1. func myfunction(a,b):
2. print(a)
3. print(b)
4. return a+b # return is optional, otherwise null is returned # return是可选的,否则返回null
复制代码控制语句
“,”逗号可以做为分隔符
if/else/elif
这个不多说了
1. if [expression]:
2. statement(s)
3. elif [expression]:
4. statement(s)
5. else:
6. statement(s)
复制代码while
可以用break或continue
1. while [expression]:
2. statement(s)
复制代码for
范围迭代。
1. for i in [0,1,2]:
2. statement # loop iterates 3 times, i being 0,1 and 2 # 循环迭代三项,i的值变化是0,1,2
3.
4. var dict = {"a":0, "b":1, "c": 2}
5. for i in dict:
6. print(dict[i]) # loop iterates the keys, i being "a","b" and c". It prints 0, 1 and 2. # 循环迭代字典中的键,i值变化是 a,b,c,打印结果是0,1,2
7.
8. for i in range(3):
9. statement # similar to [0,1,2] but does not allocate an array # 类似[0,1,2],但是不分配数组
10.
11. for i in range(1,3):
12. statement # similar to [1,2] but does not allocate an array # 类似[1,2]但是不分配数组
13.
14. for i in range(2,8,2):
15. statement # similar to [2,4,6] but does not allocate an array # 类似[2,4,6]但是不分配数组
复制代码类
默认情况下,脚本的主体文件是一个未命名的类,只能做为外部资源或者文件被引用。类语法注定很紧凑,只能包含类成员变量或方法。类中允许有静态方法但是不允许有静态成员变量(基于线程安全的精神,因为脚本是可以在用户不知道的情况下在独立的纯种中被初始化)以同样的方式,成员变量(包括数组和字典)在实例被创建时初始化。
类文件示例
类文件示例,想像它已经以文件的形式被存储,类似于myclass.gd
1. var a=5
2.
3. func print_value_of_a():
4. print(a)
复制代码继承
一个类文件可以继续自全局类,另外一个文件或另外一个文件的子类。不允许多继承。用“extends”语法:
1. # extend from some class (global) # 继承自其他类(全局)
2. extends SomeClass
3.
4. # optionally, extend from another file # 可随意继承自其他文件
5. extends "somefile.gd"
6.
7. # extend from a subclass in another file # 继承自其他文件的子类
8. extends "somefile.gd".Subclass
复制代码继承测试
它可以检测一个实例是否继承自一个给定的类。这样,“extends”关键字可以被用来做为操作符:
1. [..]
2.
3. if ( entity extends enemy_class ):
4. entity.apply_damage()
复制代码构造函数
一个类有一个可靠的构造函数,一个名叫“_init”的函数,当类被实例化的时候被调用。
子类
一个类文件可以有子类,语法非常简单直接:
1. class SomeSubClass:
2. var a=5
3. func print_value_of_a():
4. print(a)
5.
6. func _init():
7. var sc = SomeSubClass.new() #instance by calling built-in new # 用内置的new关键字来实例化
8. sc.print_value_of_a()
复制代码类对象
可能需要在某个时候从文件加载一个类并且实例化它,由于全局范围不存在,类必须做为资源被加载。在类对象中调用“new”函数来完成实例化:
1. #load the class (loaded every time the script is instanced) # 加载类(每次加载完成脚本会被实例化)
2. var MyClass = load("myclass.gd")
3.
4. # alternatively, using the preload() function preloads the class at compile time # 或者在编译时用preload()方法预加载类
5. var MyClass2 = preload("myclass.gd")
6.
7. func _init():
8. var a = MyClass.new()
9. a.somefunction()
复制代码导出
类成员变量能被导出。这意味着他们的值和场景一起被保存。如果类成员有初始常量表达式,他们将在属性编辑器是可编辑。用export关键字完成导出:
1. extends Button
2.
3. export var data # value will be saved # 值将会被保存
4. export var number=5 # also available to the property editor # 对属性编辑器同样有效
复制代码导出成员变量的基本好处是在属性编辑器中可见。这样美术和策划就可以修改值影响后来的运行情况。对此,为更详细的导出变量提供了一个特别的导出语法:
1. #if the exported value assigns a constant or constant expression, the type will be infered and used in the editor # 如果导出的值是一个常量或常量表达式,该类型会被推测并在编辑器中使用
2.
3. export var number=5
4.
5. # export can take a basic datatype as argument, which will be used in the editor # export可以有一个基本数据类型做为参数,将被在编辑器在使用
6.
7. export(int) var number
8.
9. # export can also take a resource type as hint # export也能够有一个资源类型做为暗示
10.
11. export(Texture) var character_face
12.
13. # integers and strings hint enumerated values # 整形和字符串暗示的枚举值
14.
15. export(int,"Warrior","Magician","Thief") var character_class # (editor will set them as 0,1 and 2) # (编辑器将设置他们为0,1,2)
16. export(String,"Rebecca","Mary","Leah") var character_name
17.
18. # strings as paths # 做为路径的字符串
19.
20. export(String,FILE) var f # string is a path to a file # 字符串是文件路径
21. export(String,DIR) var f # string is a path to a directory # 字符串是目录
22. export(String,FILE,"*.txt") var f # string is a path to a file, custom filter provided as hint # 字符串是一个文件路径,自定义过滤器提示
23.
24. # integers and floats hint ranges # 整型和浮点型暗示的范围
25.
26. export(int,20) var i # 0 to 20 allowed # 允许0到20
27. export(int,-10,20) var j # -10 to 20 allowed 允许 -10到20
28. export(float,-10,20,0.2) var k # -10 to 20 allowed, with stepping of 0.2 # 允许-10到10,以0.2为步长增加
29.
30. # color can hint availability of alpha 颜色可以暗示透明度的可用性
31.
32. export(Color,RGB) var col # Color is RGB # Color是RGB
33. export(Color,RGBA) var col # Color is RGBA # Color是RGBA
复制代码必须说明一下,即使脚本在编辑器中没有被执行,被导出的属性依然可被编辑(查看正面的“tool”)
静态函数
一个函数能被定义为静态的,如果是静态函数,则不能用访问实例的成员变量或“self”。这主要是有益于编写库和helper函数。
1. static func sum2(a,b):
2. return a+b
复制代码工具模式
脚本在默认的情况下并不在编辑器中运行,并且只有导出的属性能被改变。有某些情况下期望他们可以这样做(只要他们不执行游戏代码或手动避免这样做),为此“tool”关键字出现了,并且必须放置在文件顶部。
1. tool
2. extends Button
3.
4. func _init():
5. print("Hello")
复制代码内存管理
如果一个类从Reference继承,当实例不再使用时应该被释放。没有垃圾回收器的存在,只是简单的引用计数器。默认情况下,所有的类没有定义从Reference继承。如果这样不理想,那么一个类必须手动继承Object并且必须调用instance.free()。为了避免这种不能被释放的环引用情况,提供了一个创建弱引用的函数weakref()
函数引用
函数不能被引用,因为他们不能被看做是类成员。这里有两个备选方案,分为是“call”函数和funcref()助手。
1. instance.call("funcname",args) # call a function by bane # 调用一个函数
2.
3. var fr = funcref(instance,"funcname") #create a function ref # 创建一个函数ref
4. fr.exec(args)
复制代码