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()