Reacting to Impact

There are three reactions impacts in this system: the effect it has on the projectile, the effect it has on the target, and any side effects of the impact. We start with the first one: our plasma bolt will flare up when it hits something or fade away when it misses.

We start by creating two virtual functions in the base Projectile.gd class for both impact and miss.

func _impact() -> void:
    pass


func _miss() -> void:
    pass

Making the plasma bolt flare on hit and fade away on miss

We can replace the calls to queue_free in the timeout and collision functions with these functions in BasicProjectile.gd.

func _physics_process(delta: float) -> void:
    var movement := _update_movement(delta)

    var collision := move_and_collide(movement)

    if collision:
        _impact()


func _on_Timer_timeout() -> void:
    _miss()

As for what they do, that’s up to you. In my case, I use a Tween node to take advantage of HDR colors with a glow filter. When they hit, they flare up bright and become transparent. When they miss, they shrink to nothing as they lose cohesion from lack of energy. Other good options are particles and audio.

There are a couple of noteworthy points in the functions themselves beside the use of Tween and yield. After impact, I don’t want the projectile to continue moving and colliding again, so I stop the physics process. When missing, I let it keep moving until its death, but I disable its ability to collide with anything by setting its layer and mask collisions to 0.

I call queue free at the end in both cases, so Godot takes the projectile out of memory.

func _impact() -> void:
    set_physics_process(false)
    tween.interpolate_property(self, "modulate", modulate, modulate * 3, 0.1, Tween.TRANS_CUBIC)
    tween.interpolate_property(self, "modulate", modulate * 3, Color.transparent, 0.2, 0, 2, 0.1)
    tween.start()
    yield(tween, "tween_all_completed")
    queue_free()


func _miss() -> void:
    collision_layer = 0
    collision_mask = 0
    tween.interpolate_property(self, "scale", scale, Vector2.ZERO, 0.25)
    tween.start()
    yield(tween, "tween_all_completed")
    queue_free()