Создан экземпляр нескольких объектов Godot Engine

avatar
gabe
9 августа 2021 в 04:56
629
1
2

У меня проблема с созданием экземпляров объектов.

С одной стороны у меня есть следующий скрипт для одного снаряда в одной сцене:

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(). Если я поставлю эту функцию, объект ожидает создания экземпляра, но он все равно создается много раз.

Источник

Ответы (1)

avatar
Theraot
9 августа 2021 в 06:29
1

Сколько экземпляров и как часто вы хотите запускать?

Вы говорите:

Проблема в том, что экземпляр объекта создается много раз.

Но сколько раз это много?

Я отвечу на вопросы, которые приходят на ум. Кроме того, некоторые из них можно комбинировать.

Если этот ответ не охватывает то, что вы хотите… Вам нужно будет уточнить. Обнажив это, надеюсь, вы сможете понять это, используя следующие инструменты:

  • Выбор между is_action_pressed и is_action_just_pressed.
  • Использование Timers (фактический объект или импровизированный с delta).
  • Сигналы (включая, помимо прочего, timeout сигналы фактических Timers).

Говоря о сигналах, все нижеприведенные подходы не требуют специальных знаний экземпляра (за исключением того, что он какой-то 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

Я сделал это переменной экспорта, чтобы вы могли редактировать ее с панели инспектора.

*Этот подход хорошо сочетается с "Один раз на вход" (т. е. используйте 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). Или, в качестве альтернативы, с параметром "Один раз так часто" (т. е. временное время), чтобы ограничить количество экземпляров.

gabe
9 августа 2021 в 12:55
0

Время от времени Мы можем использовать ту же стратегию импровизированного таймера, которую вы используете для срока службы пули: 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 Вот мой ответ! Благодарю вас! Проблема заключалась в следующем: экземпляры создавались много раз за короткое время, и я хотел добавить охлаждение. Спасибо за Ваш ответ!