Fireballs - is there way to make burned/smoked area?

Your raycast can get normals.

var collider = get_collider()
if is_colliding():
    var normal := get_collision_normal()

but then it seems like you are using remote transforms to copy this positional data instead of moving your _explode function under this if is_colliding() statement

if is_colliding():
	audio_stream_player_3d.stop()
	var point := get_collision_point()
	var normal := get_collision_normal() # get normal
	var rotate_up := Quaternion(Vector3.UP, normal) # use normal to rotate

	var explosion := explosion_scene.instantiate()
	var decal := decal_scene.instantiate()
	explosion.position = point
	decal.position = point
	decal.quaternion = rotate_up # assign rotation

	get_tree().current_scene.add_child(explosion)
	get_tree().current_scene.add_child(decal)
	explosion.blast()
	queue_free()

using physics process to get_nodes_in_group is pretty bad; and every other decal will be doing this too. Your decals script could track the total decals with a static variable instead. A static variable is shared between every instance of the script, so increasing it on ready, and decrementing on _exit_tree works as cheap way to count every living instance.

static var decals_amount: int = 0
const MAX_DECALS_AMOUNT: int = 10

func _ready() -> void:
	decals_amount += 1
	if decals_amount > MAX_DECALS_AMOUNT:
		var all_decals := get_tree().get_nodes_in_group("Decals")
		# a better solution would find the oldest
		all_decals.pick_random().queue_free()

func _exit_tree() -> void:
	decals_amount -= 1

func _on_timer_timeout() -> void:
	queue_free()
1 Like