开源游戏3D引擎之Godot的专用脚本语言

来源:互联网 发布:c语言学生成绩管理删除 编辑:程序博客网 时间:2024/05/25 21:35





原文http://www.godotengine.org/wiki/doku.php?id=gdscript
说明Godot的专用脚本语言
历史总结一下就是由于其他语言的总总不适合Godot,最后GDScript就诞生了。此处省略一万字……想详细了解的可以看原文

示例
通过语法能够更好的学习,所以这里有一个简单的示例

  1. #a file is a class! # 一个文件是一个类

  2. # inheritance # 继承
  3. extends BaseClass

  4. # member variables # 成员变量

  5. var a=5 
  6. var s="Hello"
  7. var arr=[1,2,3]
  8. var dict={"key":"value", 2:3}

  9. # constants # 常量

  10. const answer=42
  11. const thename="Charly"

  12. # built-in vector types # 内置vector类型

  13. var v2 = Vector2(1,2)
  14. var v3 = Vector3(1,2,3)

  15. # function # 函数

  16. func some_function(param1,param2):
  17.     var local_var=5
  18.    if param1 < local_var:
  19.         print(param1)
  20.     elif param2 > 5:
  21.         print(param2)
  22.     else:
  23.         print("fail!")

  24.     for i in range(20):
  25.         print(i)

  26.     while(param2!=0):
  27.         param2-=1

  28.     var local_var2 = param1+3
  29.     return local_var2


  30. # subclass # 子类

  31. class Something:
  32.     var a=10

  33. # constructor # 构造器

  34. func _init():
  35.     print("constructed!")
  36.     var lv = Something.new()
  37.     print(lv.a)

复制代码
语言
标识符
         标识符可以是一个包含任何字母、数字、下划线的字符串,但是不能以数字开头,并区分大小写。
关键字
        下表列出了支持的关键字,由于关键字都是保留字,所以不能用来做标识符。

操作符
下表是支持的操作符和他们的优先级:



字面值


注释:用“#”来注释一行语句
  1. # 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. var dict = {"a":0, "b":1, "c": 2}
  4. for i in dict:
  5.     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

  6. for i in range(3):
  7.     statement # similar to [0,1,2] but does not allocate an array # 类似[0,1,2],但是不分配数组

  8. for i in range(1,3):
  9.     statement # similar to [1,2] but does not allocate an array # 类似[1,2]但是不分配数组

  10. for i in range(2,8,2):
  11.     statement # similar to [2,4,6] but does not allocate an array # 类似[2,4,6]但是不分配数组
复制代码

默认情况下,脚本的主体文件是一个未命名的类,只能做为外部资源或者文件被引用。类语法注定很紧凑,只能包含类成员变量或方法。类中允许有静态方法但是不允许有静态成员变量(基于线程安全的精神,因为脚本是可以在用户不知道的情况下在独立的纯种中被初始化)以同样的方式,成员变量(包括数组和字典)在实例被创建时初始化。

类文件示例
类文件示例,想像它已经以文件的形式被存储,类似于myclass.gd
  1. var a=5

  2. func print_value_of_a():
  3.     print(a)
复制代码
继承
一个类文件可以继续自全局类,另外一个文件或另外一个文件的子类。不允许多继承。用“extends”语法:
  1. # extend from some class (global) # 继承自其他类(全局)
  2. extends SomeClass 

  3. # optionally, extend from another file # 可随意继承自其他文件
  4. extends "somefile.gd" 

  5. # extend from a subclass in another file # 继承自其他文件的子类
  6. extends "somefile.gd".Subclass 
复制代码
继承测试
它可以检测一个实例是否继承自一个给定的类。这样,“extends”关键字可以被用来做为操作符:
  1. static var enemy_class = preload("enemy.gd") # cache the enemy class # 缓存enemy类
  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. func _init():
  6.     var sc = SomeSubClass.new() #instance by calling built-in new # 用内置的new关键字来实例化
  7.     sc.print_value_of_a()
复制代码
类对象
可能需要在某个时候从文件加载一个类并且实例化它,由于全局范围不存在,类必须做为资源被加载。在类对象中调用“new”函数来完成实例化:
  1. #load the class (loaded every time the script is instanced) # 加载类(每次加载完成脚本会被实例化)
  2. var MyClass = load("myclass.gd")

  3. # alternatively, using the preload() function preloads the class at compile time # 或者在编译时用preload()方法预加载类
  4. var MyClass2 = preload("myclass.gd")

  5. func _init():
  6.     var a = MyClass.new()
  7.     a.somefunction()
复制代码
导出
类成员变量能被导出。这意味着他们的值和场景一起被保存。如果类成员有初始常量表达式,他们将在属性编辑器是可编辑。用export关键字完成导出:
  1. extends Button

  2. export var data # value will be saved # 值将会被保存
  3. 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. export var number=5

  3. # export can take a basic datatype as argument, which will be used in the editor # export可以有一个基本数据类型做为参数,将被在编辑器在使用

  4. export(int) var number

  5. # export can also take a resource type as hint # export也能够有一个资源类型做为暗示

  6. export(Texture) var character_face

  7. # integers and strings hint enumerated values # 整形和字符串暗示的枚举值

  8. export(int,"Warrior","Magician","Thief") var character_class # (editor will set them as 0,1 and 2)  # (编辑器将设置他们为0,1,2)
  9. export(String,"Rebecca","Mary","Leah") var character_name 

  10. # strings as paths # 做为路径的字符串

  11. export(String,FILE) var f # string is a path to a file # 字符串是文件路径
  12. export(String,DIR) var f # string is a path to a directory # 字符串是目录
  13. export(String,FILE,"*.txt") var f # string is a path to a file, custom filter provided as hint # 字符串是一个文件路径,自定义过滤器提示

  14. # integers and floats hint ranges # 整型和浮点型暗示的范围

  15. export(int,20) var i # 0 to 20 allowed # 允许0到20
  16. export(int,-10,20) var j # -10 to 20 allowed 允许 -10到20
  17. export(float,-10,20,0.2) var k # -10 to 20 allowed, with stepping of 0.2 # 允许-10到10,以0.2为步长增加

  18. # color can hint availability of alpha 颜色可以暗示透明度的可用性

  19. export(Color,RGB) var col # Color is RGB # Color是RGB
  20. 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. func _init():
  4.     print("Hello")
复制代码
内存管理
如果一个类从Reference继承,当实例不再使用时应该被释放。没有垃圾回收器的存在,只是简单的引用计数器。默认情况下,所有的类没有定义从Reference继承。如果这样不理想,那么一个类必须手动继承Object并且必须调用instance.free()。为了避免这种不能被释放的环引用情况,提供了一个创建弱引用的函数weakref()

函数引用
函数不能被引用,因为他们不能被看做是类成员。这里有两个备选方案,分为是“call”函数和funcref()助手。
  1. instance.call("funcname",args) # call a function by bane # 调用一个函数

  2. var fr = funcref(instance,"funcname") #create a function ref # 创建一个函数ref
  3. fr.exec(args)
复制代码


0 0