tutorial_scripting_2 - seraph526/godot-se GitHub Wiki
脚本 (继续)
处理
Godot中的一些行为是通过callbacks或虚函数触发的,所以不需要写一直监测运行的代码.另外,许多事情可以由动画师来完成.
但是,通常还是要在每一帧运行一个脚本的情况.有两种运行模式,空闲处理和固定处理.
空闲处理通过 Node.set_process() 函数激活.激活后, Node.set_process() 每帧都会执行.
func _ready():
set_process(true)
func _process(delta):
[dosomething..]
delta参数描述从上次调用_process()到现在过去的时间(以秒为单位的浮点类型) 固定处理类似,唯一的要求是要和物理引擎同步. 简单的测试这点的方法是创建一个只有一个Lable节点的场景,代码如下:
extends Label
var accum=0
func _ready():
set_process(true)
func _process(delta):
accum+=delta
set_text(str(accum))
这会显示一个按秒增加的计算器.
组
节点可以被添加到组中(每个节点下,你想要多少都可以).这对于管理大场景来说是简单而且有效的功能.有两种方法做这个,第一种方法是通过UI,从组按扭实现:
func _ready():
add_to_group("enemies")
这种方式,如果玩家潜行到秘密基地,如果被发现,所有的组中的敌人都会发出警报.通过调用SceneMainLoop.call_group():
func _on_discovered():
get_scene().call_group(0,"guards","player_was_discovered")
上述方法调用组中"guards"的每一位成员的函数"player_was_discovered".或者,通过调用SceneMainLoop.get_nodes_in_group()得到"guards"节点全部列表:
var guards = get_scene().get_nodes_in_group("guards")
关于SceneMainLoop的更多知识点将在后面讲述。
消息系统
Godot有一个消息系统。通常这个系统不会在脚本层使用,因为它太底层了,虚函数提供了大部门接口,但知道它们的存在还是必要的。在你的脚本中填加一个Object._notification()函数:
func _notification(what):
if (what==NOTIFICATION_READY):
print("This is the same as overriding _ready()...")
elif (what==NOTIFICATION_PROCESS):
var delta = get_process_time()
print("This is the same as overriding _process()...")
文档class list中列出了所有有接收到的消息。但是,再强调一下,大部分的函数都提供了简单的重写方式。
可重写函数
如前面提到的,最好使用这些函数。节点提供了许多有用的重写函数,如:
func _enter_scene():
pass # 当节点进入激活的场景时,此函数被调用。此时子节点还没有被加载到当前场景。通常,大部分情况下,最好使用_ready()函数。
func _ready():
pass # 此在_enter_scene函数后调用,但是它能保证所有的子节点都被正常加载,都能被函数调用
func _exit_scene():
pass # 当节点退出当前激活场景时,调用此函数。此时,所有子节点已经全部退出当前场景。
func _process(delta):
pass # 当set_process()被激活时,此函数每帧都调用。
func _fixed_process(delta):
pass # 当set_fixed_process()被激活时,此函数每物理帧调用。
func _paused():
pass #当游戏暂停时调用,调用后,节点不再接收任何callback进程
func _unpaused():
pass # 当游戏继续时调用
创建节点
由代码创建节点,只要调用.new()方法,(像其他的基于类的数据类型一样),如:
var s
func _ready():
s = Sprite.new() # create a new sprite!
add_child(s) #add it as a child of this node
要删除节点,在场景内或场景外,一定要使用free()
func _someaction():
s.free() # immediately removes the node from the scene and frees it
当节点释放后,所有的子节点也会被释放。因此,手动删除节点要容易的多。只是释放根节点,所有子节点也会被同时释放。
但是,经常会出现我们删除的节点处于锁定状态,就是说,这个节点正在发出信息或要访问一个函数。这会导致游戏崩溃。运行Godot的debugger模式,经常会抓取到这种情况,并提出警告。
最安全的删除节点的方法是使用queue_free代替free().它将安全的删除处于闲置状态的节点。
func _someaction():
s.queue_free() # remove the node and delete it while nothing is happening
初始化场景
从代码初始化场景非常简单,有两种方式。第一种是从磁盘加载场景。
var scene = load("res://myscene.scn") # will load when the script is instanced
有些时候,使用preload会更方便,因为,它在解析时执行。
var scene = preload("res://myscene.scn") # will load when parsing the script
但是,场景仍不是一个包含子节点的节点。它是一种打包的特殊资源 PackedScene.要创建实际的节点,要执行PackedScene.instance()函数。它将返回可以加载到场景中的节点树。
var node = scene.instance()
add_child(node)
两步执行的优势是打包的节点可以保持加载和准备使用,所以可以按照需求用来创建更多的实例。这一点特别有用,如,要在场景中快速地实例化几个敌人,子弹等。