【问题标题】:Godot Engine Multiple Objects InstancedGodot引擎多个对象实例化
【发布时间】:2021-08-09 04:56:48
【问题描述】:

我在实例化对象时遇到问题。

一方面,我在一个场景中有一个射弹的以下脚本:

extends KinematicBody2D

var speed = 200
var life_time = 2
var life_spawn = 0

func _physics_process(delta):
    var collision = move_and_collide(Vector2.UP * delta * speed)
    life_spawn += delta
    if life_spawn > life_time:
        queue_free()
    pass

另一方面,我让玩家在其他场景中使用以下脚本:

extends KinematicBody2D

func _physics_process(delta):
    if Input.is_action_pressed("ui_accept"):
        createLaser()
    pass

func createLaser():
    var laser = preload("res://scenes/space_ship/laser/Laser.tscn")
    var left_fired_laser = laser.instance()
    var right_fired_laser = laser.instance()
    var left_cannon = get_node("Cannons/left_cannon").get_global_position()
    var right_cannon = get_node("Cannons/right_cannon").get_global_position()
    left_fired_laser.position = Vector2(left_cannon.x, left_cannon.y)
    get_parent().call_deferred("add_child", left_fired_laser)
    right_fired_laser.position = Vector2(right_cannon.x, right_cannon.y)
    get_parent().call_deferred("add_child", right_fired_laser)
    pass

问题是对象被实例化了很多次。即使我放了一个 yield() 函数。如果我放那个函数,对象会等待被实例化,但无论如何它都会被实例化很多次。

【问题讨论】:

    标签: godot gdscript


    【解决方案1】:

    您要实例化多少个实例以及多久实例化一次?

    你说:

    问题是对象被实例化了很多次。

    但是多少次是很多?

    我会回答想到的案例。此外,其中一些可以组合。

    如果这个答案没有涵盖你想要的……你需要更具体。除此之外,希望你可以考虑这些工具来解决这个问题:

    • is_action_pressedis_action_just_pressed 之间进行选择。
    • Timers的使用(实际对象或临时用delta)。
    • 信号(包括但不限于实际Timers的timeout信号)。

    说到信号,下面的所有方法都不需要实例的特殊知识(除了它是一些Node2D)。您可以将自定义信号添加到实例并连接到它们以了解何时可以创建更多实例。

    您可以做的另一件事是保存对实例的引用以询问它们(例如,您可以使用is_instance_valid)。但是,我在下面介绍了一种使用tree_exited 信号的方法,我认为这种方法更通用。

    您还可以通过调用方法跟踪来利用 AnimationPlayer。例如,如果您需要在动画的特定帧上添加实例。


    每个输入一次

    只要按下输入,此代码就会实例化每个物理帧:

    func _physics_process(delta:float) -> void:
        if Input.is_action_pressed("ui_accept"):
            createLaser()
    

    如果您只想在按下输入时实例化第一个物理帧,请使用is_action_just_pressed

    func _physics_process(delta:float) -> void:
        if Input.is_action_just_pressed("ui_accept"):
            createLaser()
    

    每隔一段时间一次

    我们可以使用与子弹寿命相同的临时计时器策略:

    var instance_period:float = 10.0
    var instance_elapsed:float = 0.0
    
    func _physics_process(delta:float) -> void:
        instance_elapsed += delta
        if Input.is_action_pressed("ui_accept") and instance_elapsed > instance_period:
            createLaser()
            instance_elapsed = 0.0
    

    只有一次

    如果你只想要一个,我们可以保存一个布尔变量来知道我们是否已经实例化:

    var did_instance:bool = false
    
    func _physics_process(delta:float) -> void:
        if Input.is_action_pressed("ui_accept") and not did_instance:
            createLaser()
            did_instance = true
    

    只有固定的次数

    你可以使用整数倒计时:

    export var yet_to_instance:int = 10
    
    func _physics_process(delta:float) -> void:
        if Input.is_action_pressed("ui_accept") and yet_to_instance > 0:
            createLaser()
            yet_to_instance -= 1
    

    我将其设为导出变量,以便您可以从 Inspector 面板对其进行编辑。

    *此方法与“每次输入一次”(即使用is_action_just_pressed)很好地结合在一起。当数字为 1 时,您也可以考虑“仅一次”的特殊情况。


    只有一次充电次数

    这是一种将临时计时器与固定实例次数相结合的特殊方式:

    var recharge_period:float = 10.0
    var recharge_elapsed:float = 0.0
    
    export var max_to_instance:int = 10
    onready var yet_to_instance:int = max_to_instance
    
    func _physics_process(delta:float) -> void:
        if Input.is_action_pressed("ui_accept") and yet_to_instance > 0:
            createLaser()
            yet_to_instance -= 1
            # recharge_elapsed = 0.0
    
        recharge_elapsed += delta
        if recharge_elapsed > recharge_period:
            if yet_to_instance < max_to_instance:
                yet_to_instance += 1
    
            recharge_elapsed = 0.0
    

    通过这种方式,您可以创建的实例数量最多可增加超时。如果您想在输入时阻止该数字增加,则可以取消注释 # instance_elapsed = 0.0您可以将其视为自动重新加载。

    此方法与“每次输入一次”(即使用 is_action_just_pressed)很好地结合在一起。或者使用“每隔一段时间”(即临时时间)来限制实例率。


    最多活一个量

    我们将连接到tree_exited 信号以更新我们的计数:

    const laser = preload("res://scenes/space_ship/laser/Laser.tscn")
    
    export var max_to_instance:int = 20
    
    func _physics_process(delta:float) -> void:
        if Input.is_action_pressed("ui_accept") and max_to_instance > 0:
            createLaser()
    
    func createLaser() -> void:
        createLaserFrom($Cannons/left_cannon)
        createLaserFrom($Cannons/right_cannon)
    
    func createLaserFrom(cannon:Node2D) -> void:
        var fired_laser = laser.instance()
    
        max_to_instance -= 1
        fire_laser.connect("tree_exited", self, "laser_exited")
    
        get_parent().add_child(fired_laser)
        fired_laser.global_position = cannon.global_position
    
    func laser_exited() -> void:
        max_to_instance += 1
    

    这种方法与“每次输入一次”(即使用is_action_just_pressed)很好地结合在一起。或者使用“每隔一段时间”(即临时时间)来限制实例率。

    【讨论】:

    • 每隔一段时间我们可以使用与子弹寿命相同的临时计时器策略:var instance_period:float = 10.0 var instance_elapsed:float = 0.0 func _physics_process(delta:float) -&gt; void: instance_elapsed += delta if Input.is_action_pressed("ui_accept") and instance_elapsed &gt; instance_period: createLaser() instance_elapsed = 0.0这就是我的答案!谢谢!问题是:在短时间内创建了很多次实例,我想添加一个冷却时间。感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    相关资源
    最近更新 更多