赞
踩
在Unity中,运行时实例化GameObject,如果不显式指定它的父节点,系统会默认把它放到场景的顶层,而在Godot中,你则必须显式指定每一个节点的父节点。指定谁作父节点? 这个问题貌似不难回答,但是要兼顾到开发及测试过程中节点结构的各种不确定性,实现起来就需要点技巧了,比如《Instancing with signals》中给的这个例子:
一个会旋转的角色Player
发射出的子弹,应该以谁作父节点?下图所示效果
Player
作父节点?Player
的旋转属性,显然是不对的Player
的父节点作父节点?示意代码
var bullet_instance = Bullet.instance()
get_parent().add_child(bullet_instance)
这种做法貌似是没问题的,但别忘了,Godot的每一个场景都是可以单独运行的,尤其是在开发测试时,如果你想单独测试Player
场景, 由于get_parent()
找不到父节点而必然导致崩溃。还有就是在开发过程中如果节点树的结构发生变化,你无法保证Player
的父节点永远适合做Bullet
的父节点。
那么如何在不改变代码的情况下,灵活地指定父节点呢?
Godot 文档里提供了一个这样的小技巧,听起来拗口,实则很容易理解,它体现了一种依赖倒置的策略,即:想发射子弹的时候,让Player
发出 shoot
信号,而让当时适合做Bullet
父节点的节点接收信号并实例化Bullet
,然后把它作为自己的子节点。
示意代码如下:
Player的代码
extends Sprite
signal shoot(bullet, direction, location)
var Bullet = preload("res://Bullet.tscn")
func _input(event):
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT and event.pressed:
emit_signal("shoot", Bullet, rotation, position)
func _process(delta):
look_at(get_global_mouse_position())
信号接收者处理shoot
信号的代码
func _on_Player_shoot(Bullet, direction, location):
var b = Bullet.instance()
add_child(b)
b.rotation = direction
b.position = location
b.velocity = b.velocity.rotated(direction)
这样,各种场合下都不需要因为更换Bullet
的父节点而修改代码了,更加符合开闭原则。
总结
凡事有利有弊,文档中提供的这种方法须在编辑器中连接信号,所以测试完毕后千万不要忘了断开连接。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。