Need help with Character tree interacting with another tree with a signal

Godot Version

4.2.1

Question

Hi guys, I’m slowly working on my 2d platformer concept. The idea is that the character has an ability to throw a projectile after pressing an input, if you press the input again when the projectile is in the air it will change in to a platform that exists for 5 seconds

extends CharacterBody2D

enum STATE {PROJECTILE,PLATFORM}
var direction = 1
var state = STATE.PROJECTILE
const SPEED = 600

func _ready():
$AnimationPlayer.play(“ice_shot”)
velocity.x = SPEED * direction
$ice_timer.start(1.0)
func _physics_process(delta):
match state:
STATE.PROJECTILE:
if Input.is_action_just_pressed(“ice”):
$AnimationPlayer.play(“ice_platform”)
$ice_timer.start(5.0)
state = STATE.PLATFORM
move_and_slide()
if is_on_wall():
queue_free()
STATE.PLATFORM:
velocity.x = 0
$Sprite2D.scale.x = 0.5
$CollisionShape2D.scale.x = 2

func _on_ice_timer_timeout():
queue_free()

I would want the projectile to have a property that if my character stand on it a timer will be set up for the platform to disappear after a second, the issue comes in the fact that the projectile is preloaded in the character script, and that means character and projectile are separate trees, so I cannot connect them with an on body entered area signal

Or is there a way to connect them with a signal? If anyone could help me with finding a solution I would be grateful, in worst case scenario a 5-second timer on a platform is also not a bad idea.

You can use code to connect two nodes from separate trees.

Could you share your player script? The one that spawns projectiles? I presume what you are looking for would look like this

extends CharacterBody2D

var projectile_prefab = preload("res://projectile")

func shoot() -> void:
    var projectile = projectile_prefab.instantiate()
    projectile.body_entered.connect(on_projectile_body_entered)
    add_sibling(projectile)

func on_projectile_body_entered(body) -> void:
    if body == self: # touched player
        print("player touched a projectile")

func shoot_ice():
if Input.is_action_just_pressed(“ice”) and ice_cooldown == true:
var i = ICESPEAR.instantiate()
i.direction = direction
get_parent().add_child(i)
i.position.y = position.y + 20
i.position.x = position.x + 100 * direction
ice_cooldown = false
$ice_cooldown.start(2)

i was trying the code you gave me and it doesnt work, i forgot to mention that a projectile is a character body (so it would be easier for me to use velocity on it) i tried to make my own signal in projectile script but this also doesnt work properly, i guess i dont understand something well enough for it to work.

I took some time and found a ridiculous roundabout way of solving it my way.

Just added a Raycast2D and told it that if it’s going to react to a character, it will change to a new state and start a timer.
I’m guessing, gertkeno idea didn’t work because as I forgot to mention, the projectile is not an Area2D but a KinematicBody2D for sake of using move_and_slide.
Still thank you for helping, leaving the code below if anyone is interested.

extends CharacterBody2D

enum STATE {PROJECTILE,PLATFORM,DISAPEARING}
var direction = 1
var state = STATE.PROJECTILE
const SPEED = 600

func _ready():
	$AnimationPlayer.play("ice_shot")
	velocity.x = SPEED * direction
	$ice_timer.start(1.0)
func _physics_process(delta):
	match state:
		STATE.PROJECTILE:
			if Input.is_action_just_pressed("ice"):
				$AnimationPlayer.play("ice_platform")
				$ice_timer.start(5.0)
				state = STATE.PLATFORM
			move_and_slide()
			if is_on_wall():
				queue_free()
		STATE.PLATFORM:
			velocity.x = 0
			$Sprite2D.scale.x = 0.5
			$CollisionShape2D.scale.x = 2
			if $RayCast2D.is_colliding():
				$ice_timer.start(1.0)
				state = STATE.DISAPEARING
		STATE.DISAPEARING:
				print($ice_timer.time_left)
			

func _on_ice_timer_timeout():
	queue_free()