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