GDScript 学习

https://docs.godotengine.org/zh_CN/latest/getting_started/scripting/gdscript/gdscript_basics.html

获取对象

get_node("Button")
//or
$Button

按钮点击:

1.可以使用节点/信号/行为来进行连接,也最简单呐
2.可以使用代码来执行行为,更灵活多变

get_node("Button").connect("pressed", self, "_on_Button_pressed")

加参数
get_node("Button").connect("pressed", self, "_on_Button_pressed",['test'])


获取帧数

func _process(delta):
    print(1/delta)

获得物理引擎帧数

func _physics_process(delta):
    print(1/delta)

物理引擎帧数是固定的,游戏帧数是非固定的


创建和删除节点

s = Sprite.new() # Create a new sprite!
add_child(s) 
//删除
s.free()
//安全的删除节点
s.queue_free()

实例化场景

加载场景

var scene = load("res://myscene.tscn")

预加载

var scene = preload("res://myscene.tscn")

创建场景的根结点

var node = scene.instance()
add_child(node)

代码打包成类

支持图标功能

class_name ScriptName, "res://path/to/optional/icon.svg"

只有GDScript为每一个独立的脚本创建全局变量


计时器

1.可以使用节点/信号/行为来进行连接,也最简单呐
2.代码

get_node("Timer").connect("timeout",self,"_on_Timer_timeout")

Signal 信号 (事件)

创建

# Signal with no arguments
signal data_found
# Signal with two arguments
signal data_found_with_args(a, b)

发送

emit_signal("data_found", your_data)

接收 (代码方式

notifier.connect("data_found", handler, "your_handler")

链接
1.可以使用节点/信号/行为来进行连接,也最简单呐
2.代码

get_node("target").connect("custom_signal",self,"_on_TimerTest_custom_signal")

https://docs.godotengine.org/zh_CN/latest/getting_started/scripting/gdscript/gdscript_basics.html?highlight=match#match


内置类型

内置类型是堆栈分配的。它们作为值传递。这意味着在每次赋值或将赋值作为参数传递给函数时都会创建一个副本。唯一的例外是 数组 s 和 字典 ,它们是通过引用传递的,所以它们是共享的。(不是像 PoolArrays PoolByteArray 那样,这些也是作为值传递的,所以在决定使用哪个时要考虑这个!)

`null` 是一个空数据类型,不包含任何信息,不能分配任何其他值。
`bool` 布尔数据类型只能包含 true 或 false。
`int` 整数数据类型只能包含整数(包括负数和正数)。
`float` 用于包含浮点值(实数)。
`String` Unicode格式 中的字符序列。字符串可以包含 标准C转义序列 。GDScript支持 格式化字符串即printf功能。

内置向量类型

`Vector2d` 2D向量类型包含 x 和 y 字段,也可以像数组一样访问。
`Rect2d` 二维矩形类型包含两个向量字段: position 和 size。或者包含一个 end 字段,该字段是 position+size。
`Vector3d` 3D向量类型包含 x , y 与 z 字段,也能够像数组一样访问。
`Transform2D` 用于二维变换的3x2矩阵。
`Plane` 3D平面类型的标准形式包含一个 normal 法向量字段以及一个 d 距离标量。
`Quat` 四元数是一种用于表示3D旋转的数据类型。它对于内插旋转很有用。
`AABB` 轴向包围框(或3D框)包含两个向量字段: position 和 size。或者包含一个 end 字段,该字段是 position+size。
`Basic` 3×3矩阵被用于3D旋转与缩放,其包含3个向量字段(x, y 和 z) 并且可以像3D向量组那样访问。
`Transform` 三维变换包含一个基字段 basis 和一个向量字段 origin。

引擎内置类型

`Color` 颜色数据类型包含 r, g, b, 和 a 字段。它也可以作为 h, s, 和 v 来访问色相/饱和度/值。
`NodePath` 编译路径,到一个主要用在场景系统中的节点。它可以很容易地分配给字符串,或用字符串赋值。
`RID` 资源ID(RID)。服务器使用通用的RID来引用不透明数据。
`Object` 任何非内置类型的基类。

容器内置类型

`Array` 任意对象类型的泛型序列,包括其他数组或字典。数组可以动态调整大小。数组从索引 0 开始建立索引。从Godot 2.1开始,索引可能是负的,就像在Python中一样,从尾部开始计数。
`Dictionary` 包含唯一关键字引用的值的关联容器。

变量

类型在变量声明中使用“:”(冒号)符号在变量名后面指定,后面是类型。

var my_vector2: Vector2
var my_node: Node = Sprite.new()

如果在声明中初始化了变量,则可以推断类型,因此可以省略类型名称:

var my_vector2 :=  Vector2() # 'my_vector2' is of type 'Vector2'
var my_node := Sprite.new() # 'my_node' is of type 'Sprite'

转换

分配给类型化变量的值必须具有兼容的类型。如果需要强制某个值为某种类型,特别是对象类型,则可以使用类型转换操作符 as。
如果该值不是子类型,则强制转换操作将导致“null”值。

var my_node2D: Node2D
my_node2D = $Sprite as Node2D # Works since Sprite is a subtype of Node2D

var my_node2D: Node2D
my_node2D = $Button # Results in 'null' since a Button is not a subtype of Node2D

对于内置类型,如果可能,它们将被强制转换,否则引擎将引发错误。

var my_int: int
my_int = "123" as int # The string can be converted to int
my_int = Vector2() as int # A Vector2 can't be converted to int, this will cause an error

在与树交互时,类型转换还有助于拥有更好的类型安全变量:

# will infer the variable to be of type Sprite:
var my_sprite := $Character as Sprite

# will fail if $AnimPlayer is not an AnimationPlayer, even if it has the method 'play()':
($AnimPlayer as AnimationPlayer).play("walk")

常量

常量与变量类似,但必须是常量或常量表达式,并且必须在初始化时分配。


函数

可以定义参数类型,默认值以及返回类型

func my_function(int_arg := 42, String_arg := "string") -> int:
    return 0

引用函数

与Python相反,函数不是GDScript中的第一类对象。这意味着它们不能存储在变量中,不能作为参数传递给另一个函数,也不能从其他函数返回。这是出于性能原因。
若要在运行时按名称引用一个函数(例如,将其存储在一个变量中,或将其作为参数传递给另一个函数),必须使用 call 或funcref 帮助器:

# Call a function by name in one step.
my_node.call("my_function", args)

# Store a function reference.
var my_func = funcref(my_node, "my_function")
# Call stored function reference.
my_func.call_func(args)

记住,像 _init 这样的默认函数,以及 _enter_tree , _exit_tree , _process , _physics_process 等大多数通知都是在所有基类中自动调用的。因此,当以某种方式重载它们时,只需要显式地调用函数。


静态函数

函数可以声明为静态的。当一个函数是静态的,它不能访问实例成员变量或 self 。这主要用于帮助助手函数库:

static func sum2(a, b):
    return a + b

条件

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

for

与python类似


tool 工具模式

默认情况下,脚本不在编辑器中运行,只能更改导出的属性。在某些情况下,确实希望在编辑器中运行脚本(只要它们不执行游戏代码或手动避免那样做)。为此,可以用 tool 关键字并将它放在文件的顶部:

func _process(delta):
    if Engine.editor_hint:
        rotation_degrees += 180 * delta

https://docs.godotengine.org/zh_CN/latest/tutorials/misc/running_code_in_the_editor.html?highlight=tool


自定义信号

signal 信号函数名
signal 信号函数名(传递参数)
https://docs.godotengine.org/zh_CN/latest/getting_started/step_by_step/signals.html?highlight=signal


onready 后置初始化

当使用节点时,通常希望在变量中保留对场景部分的引用。由于场景只允许在进入活动场景树时配置,所以子节点只能在 Node._ready() 准备后获得。

var my_label
func _ready():
    my_label = get_node("MyLabel")

等同于

onready var my_label = get_node("MyLabel")

https://docs.godotengine.org/zh_CN/latest/getting_started/scripting/gdscript/gdscript_basics.html?highlight=onready


无效数与无穷大

NAN 无效数
INF 无穷大


setter 和 getter

当 变量 的值需要被 外部的 源(即不是来自类中的本地用法)修改时,必须调用 setter 函数(上面的 setterfunc )。 这发生在值 改变之前 。必须用 * setter * 来设置新值。 反之亦然,当访问 变量 时,必须用 *getter * 函数(上面的 getterfunc ) 返回 所需的值。 下面是一个示例:

var variable = value setget setterfunc, getterfunc

var myvar setget my_var_set, my_var_get

func my_var_set(new_value):
    my_var = new_value

func my_var_get():
    return my_var # Getter must return a value.


setter 或者 getter 函数都可省略:

# Only a setter.
var my_var = 5 setget myvar_set
# Only a getter (note the comma).
var my_var = 5 setget ,myvar_get

本地 访问不需要触发setter和getter

func _init():
    # Does not trigger setter/getter.
    my_integer = 5
    print(my_integer)

    # Does trigger setter/getter.
    self.my_integer = 5
    print(self.my_integer)

match语法

删减后的switch
常数

match x:
    1:
        print("We are number one!")
    2:
        print("Two are better than one!")
    "test":
        print("Oh snap! It's a string!")

变量类型

match typeof(x):
    TYPE_REAL:
        print("float")
    TYPE_STRING:
        print("text")
    TYPE_ARRAY:
        print("array")

通配符模式

match x:
    1:
        print("It's one!")
    2:
        print("It's one times two!")
    _:
        print("It's not 1 or 2. I don't care tbh.")

绑定模式
绑定模式引入了一个新变量。与通配符模式类似,它匹配所有内容,并为该值提供一个名称。它在数组和字典模式中特别有用。

match x:
    1:
        print("It's one!")
    2:
        print("It's one times two!")
    var new_var:
        print("It's not 1 or 2, it's ", new_var)

数组模式

match x:
    []:
        print("Empty array")
    [1, 3, "test", null]:
        print("Very specific array")
    [var start, _, "test"]:
        print("First element is ", start, ", and the last is \"test\"")
    [42, ..]:
        print("Open ended array")

字典模式

match x:
    {}:
        print("Empty dict")
    {"name": "Dennis"}:
        print("The name is Dennis")
    {"name": "Dennis", "age": var age}:
        print("Dennis is ", age, " years old.")
    {"name", "age"}:
        print("Has a name and an age, but it's not Dennis :(")
    {"key": "godotisawesome", ..}:
        print("I only checked for one entry and ignored the rest")

多重模式:

match x:
    1, 2, 3:
        print("It's 1 - 3")
    "Sword", "Splash potion", "Fist":
        print("Yep, you've taken damage")

https://docs.godotengine.org/zh_CN/latest/getting_started/scripting/gdscript/gdscript_basics.html?highlight=match#match


继承

不支持多继承

extends SomeClass

func _init(args).(parent_args):
   pass

func _init(e=null, m=null).(e):
    # Do something with 'e'.
    message = m

func _init().(5):
    pass

编辑面板对接变量 export

定义一个初始值
export var number = 5
需要输入整数值
export(int) var number
需要给予指定的类型
export(Texture) var character_face
export(PackedScene) var scene_file
数组,获得列表中对应的索引值
export(int, "Warrior", "Magician", "Thief") var character_class
数组,获得列表中对应的字符串
export(String, "Rebecca", "Mary", "Leah") var character_name
枚举

enum NamedEnum {THING_1, THING_2, ANOTHER_THING = -1}
export (NamedEnum) var x

获得文件路径 (默认res下
export(String, FILE) var f
获得文件夹路径 (默认res下
export(String, DIR) var f
获得txt文件路径 (默认res下
export(String, FILE, "*.txt") var f
获得图片路径 (默认项目文件夹下
export(String, FILE, GLOBAL, "*.png") var tool_image
获得文件夹路径 (默认项目文件夹下
export(String, DIR, GLOBAL) var tool_dir

多行文本
export(String, MULTILINE) var text
输入0~20的整数
export(int, 20) var i
输入-10~20的整数
export(int, -10, 20) var j
输入-10~20的浮点数,步长为0.2
export(float, -10, 20, 0.2) var k
获得100~1000的以e为底的指数值,步长为20
export(float, EXP, 100, 1000, 20) var l
获得浮点数以EASE运动函数为基准的值??
export(float, EASE) var transition_speed

获取颜色值
export(Color, RGB) var col
获取颜色值 (支持透明
export(Color, RGBA) var col

位操作值
export(int, FLAGS) var spell_elements = defValue
export(int, FLAGS, "Fire", "Water", "Earth", "Wind") var spell_elements = 0

获取数组

export var a = [1, 2, 3]
export(Array, int) var ints = [1,2,3]

数组值
export(Array, int, "Red", "Green", "Blue") var enums = [2, 1, 0]
多维数组
export(Array, Array, float) var two_dimensional = [[1, 2], [3, 4]]
可变数组

export(Array) var b
export(Array, PackedScene) var scenes
export var vector3s = PoolVector3Array()
export var strings = PoolStringArray()

遗憾的是下面代码c=b或者c=a,a怎么更改,都不会影响编辑器下的c, 变量只可以用常量来初始化数值
export(int,10,20)var a=0 var b = a+5 export(int,10,20)var c=a

内存管理

如果一个类继承自 Reference , 则实例将在不再使用时被自动释放。 没有垃圾收集器,只有引用计数。 默认情况下,所有未定义继承的类都会扩展 Reference 。 如果不希望这样,那么类必须手动继承 Object 并且必须调用 instance.free()。 为了避免无法释放的引用循环,一个 weakref 函数被用来来创建弱引用。

或者,当不使用引用时,可以使用 is_instance_valid(instance) 来检查对象是否已被释放。


yield 协同

GDScript通过 yield 内置函数支持 coroutines 。调用 yield 将立即从当前函数返回,返回值是当前函数的冻结状态。在结果对象上调用 resume 将会继续执行,并返回函数返回的任何内容。一旦恢复,状态对象就变得无效。下面是一个示例:

func my_func():
   print("Hello")
   yield()
   print("world")

func _ready():
    var y = my_func()
    # Function state saved in 'y'.
    print("my dear")
    y.resume()
    # 'y' resumed and is now an invalid state.

打印

Hello
my dear
world
func my_func():
   print("Hello")
   print(yield())
   return "cheers!"

func _ready():
    var y = my_func()
    # Function state saved in 'y'.
    print(y.resume("world"))
    # 'y' resumed and is now an invalid state.
Hello
world
cheers!

使用 yield 的真正强度是在与信号结合时。 yield 可以接受两个参数,一个物体和一个信号。当接收到信号时,执行将重新开始。下面是一些示例:

下一帧执行
yield(get_tree(), "idle_frame")

动画播放完毕后执行
yield(get_node("AnimationPlayer"), "finished")

等待5秒执行
yield(get_tree().create_timer(5.0), "timeout")

协同程序本身在转换到无效状态时使用 completed 信号,my_func 将只在按钮被按下后继续执行。

func my_func():
    yield(button_func(), "completed")
    print("All buttons were pressed, hurray!")

func button_func():
    yield($Button0, "pressed")
    yield($Button1, "pressed")

Assert 断言

assert 关键字可以用来检查调试构建中的条件。这些断言在非调试生成中被忽略。

# Check that 'i' is 0.
assert(i == 0)

鸭子类型

如果击中大岩石的对象有一个 smash() 方法,它将被调用。不需要考虑继承或多态性。动态类型化语言只关心具有所需方法或成员的实例,而不关心它继承什么类型。鸭子类型的定义应该使这一点更清楚:
“当我看到一只鸟像鸭子一样走路,像鸭子一样游泳,像鸭子一样呱呱叫时,我就叫它鸭子”
有可能被击中的对象没有smash()函数。一些动态类型语言在方法调用不存在时简单地忽略它(如Objective C),但是GDScript更严格,因此需要检查函数是否存在:

func _on_object_hit(object):
    if object.has_method("smash"):
        object.smash()

编程风格

https://docs.godotengine.org/zh_CN/latest/getting_started/scripting/gdscript/gdscript_styleguide.html


类的引用

如果已经写了

class_name Rifle

就没有必要进行常量引用了

不需要
const Rifle = preload('res://player/weapons/Rifle.gd')

警告与忽略

https://docs.godotengine.org/zh_CN/latest/getting_started/scripting/gdscript/static_typing.html#warning-system


禁止的写法

https://docs.godotengine.org/zh_CN/latest/getting_started/scripting/gdscript/static_typing.html#cases-where-you-cant-specify-types


格式化字符串

同py写法

# Define a format string with placeholder '%s'
var format_string = "We're waiting for %s."

# Using the '%' operator, the placeholder is replaced with the desired value
var actual_string = format_string % "Godot"

print(actual_string)
# Output: "We're waiting for Godot."

另一种写法

# Define a format string
var format_string = "We're waiting for {str}"

# Using the 'format' method, replace the 'str' placeholder
var actual_string = format_string.format({"str": "Godot"})

print(actual_string)
# Output: "We're waiting for Godot"

多占位符和py写法不一样,后面跟数组

var format_string = "%s was reluctant to learn %s, but now he enjoys it."
var actual_string = format_string % ["Estragon", "GDScript"]

print(actual_string)
# Output: "Estragon was reluctant to learn GDScript, but now he enjoys it."

数字动态填充

var format_string = "%*.*f" #%7.3f
# Pad to length of 7, round to 3 decimal places:
print(format_string % [7, 3, 8.8888])
# Output: "  8.889"
# 2 leading spaces

print("%0*d" % [2, 3]) #%02d
#output: "03"

字符串

"Hi, {name} v{version}!".format({"name":"Godette", "version":"3.0"})    
"Hi, {0} v{1}!".format({"0":"Godette", "1":"3.0"})
"Hi, {0} v{version}!".format({"0":"Godette", "version":"3.0"})
"Hi, {name} v{version}!".format([["version","3.0"], ["name","Godette"]])
"Hi, {0} v{1}!".format(["Godette","3.0"])
"Hi, {name} v{0}!".format([3.0, ["name","Godette"]])
"Hi, {} v{}!".format(["Godette", 3.0], "{}")
"Hi, {0} v{1}".format(["Godette", "3.0"], "{_}")
"Hi, 0% v1%".format(["Godette", "3.0"], "_%")
"Hi, %0 v%1".format(["Godette", "3.0"], "%_")

输出
Hi, Godette v3.0!
混合用法

"Hi, {0} v{version}".format({0:"Godette", "version":"%0.2f" % 3.114})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容