How can I access code from scene a to scene b (they aren't parents/child nodes)

Godot Version

4.3

Question
here’s the code of enemy and code of ball because this is ping pong game

The ball’s code

extends CharacterBody2D

signal ball_direction

var speed = 200.0
var speed_increase = 1.05

func _ready() -> void:
	start_ball()

func start_ball():
	#var direction = Vector2(randf_range(-1, 1), randf_range(-1, 1)).normalized()
	#velocity = direction * speed
	velocity.x = [-1,1][randi() % 2] * speed
	velocity.y = [-0.8,0.8][randi() % 2] * speed

func _physics_process(_delta: float) -> void:
	var collosion = move_and_collide(velocity * _delta)
	if collosion:
		velocity = velocity.bounce(collosion.get_normal())
	ball_direction.emit()

the enemy’s code

extends CharacterBody2D

@export var enemy_speed = 300

func _physics_process(_delta: float) -> void:
	velocity = Vector2()
	
	if ball.position.y < 0:
		velocity.y -= enemy_speed
	elif ball.position.y > 0:
		velocity.y += enemy_speed
	move_and_slide()

I tried to make the ball global but it only made the ball stuck in the same position instead of moving

any suggestions ?

both nodes should have been added to the SceneTree at one point.
You have four options:

Method 1

Create an autoload that always knows who the player or enemy node is

  • Every enemy/player can access the autoload to retrieve information about the other node.

Method 2

Create a method inside your player or enemy, maybe call it .init_player() or .init_enemy() Whenever you instantiate a player or enemy node, you can pass the enemy or player node as a parameter. That way you are able to reference them inside the script.

enemy.gd

var player_ref

# Initializes the enemy node by giving it a reference to the player
func init_enemy(player_node) -> void:
    player_ref = player_node

Method 3

The third method is to completely separate enemy and player from referencing each other directly. Let the logic handle them instead. What do I mean by that?
- If the area2d nodes should detect the player or enemy, let the area2d signals detect them and handle the collision itself without direct reference

# area2d could be an area around the enemy, or a weapon/bullet that happens to touch the player body
func _on_area2d_body_entered(body) -> void:
    if body.name == "Player":
        var player = body # this is the player node!
    else:
        var object = body # this is something else that was detected!

Method 4

the last method is the lazy unstable reference by making use of the SceneTree.
I highly discourage anyone from using it.

State of SceneTree
- root
    - Level
        - Player
        - Enemy
        - Tilemap
        - etc
enemy.gd

var player_ref

# this method is called once when the Enemy starts existing
func _ready() -> void:
   player_ref = get_node("../Player") # go outside the Enemy script, then move into the Player script on the same parent node (which is Level)
1 Like

thanks, I meant the enemy moves automatically whenever the ball is near to him, but I’ll try your codes and see if one of them is working :slight_smile:

ok I tried to use metod 4 but I got an error, the .position.y isn’t working with the code

In that case, your ball must have a way to detect if something is near it. Maybe an area2d.

func _on_area2d_body_entered(body) -> void:
    if body.name.begins_with("Enemy"): # i am not sure how your enemy node is called
        var enemy = body
        enemy.move_away(self.global_position) # maybe the enemy has a method to know where the ball is, and then calculate a direction away from the ball?

This method only works after I know how your SceneTree looks like. It could be that your Ball is in some weird scenetree structure.

image
here’s the scene tree of the main scene

scene of ball

image

thank you very much!
when you said I got an error, the .position.y isn’t working with the code, does this mean the enemy is tracking the ball? Or the other way around? Is this code in ball.gd or enemy.gd?

Could you post the code section?
and most importantly, does the ball exist before or after the enemy enters the scene?

the tracking is ball

the code in enemy is

func _ready() -> void:
	var ball = get_node("./character_body_2d.tscn")

or

@onready var ball = get_node("./character_body_2d.tscn")

forget to mention, they both exist at the same time when scene starts

@onready var ball = get_node("./character_body_2d.tscn")

i would change it to the name you used in your SceneTree which is simply “Ball”. Also the get_node() is missing a dot, the correction could be

var ball
func _ready() -> void:
	ball = get_node("../Ball")

and this is assuming the Ball exist before or at the same time as the enemy.


Referencing documentation: Node — Godot Engine (stable) documentation in English

the same glitch happens to me with this part of enemy’s code

func _physics_process(_delta: float) -> void:
	velocity = Vector2()
	
	if ball.position.y < 0:
		velocity.y -= enemy_speed 
	elif ball.position.y > 0:
		velocity.y += enemy_speed
	move_and_slide()

In your SceneTree, can you put the Ball Scene above the Enemy scene?

Also I don’t quite understand your velocity = Vector2() code, I believe your velocity must already exist? Maybe change it to velocity = Vector2.ZERO in order to completely reset the velocity.

Lastly, once the error happens, can you go into your debugger window and see the value of ball ?

image
This is the glitch that has been hunted me

and this

You are still somehow using ../character_body_2d.tscn somewhere in your code.
Please change it into ../Ball

sorry for late replay, anyways the ball itself is called character_body_2d

i see, this is very strange.
From what I gather after looking at
image
is that the Ball node is called “Ball” in the node scene.
if that is not the case, please ensure that the Ball node is renamed as “character_body_2d”

alright, I’ll rename it

also please remove the “.tscn” from your get_node as we want to access the node and not the packedScene path.
It should then read “get_node(”…/character_body_2d")