Hi everyone. First time here. I have searched over forums and nothing seems to answers my question in an understandable way sadly. Here are the basics. I am playing around with Godot learning movement and such. I am creating individual scenes to instance into a Main.tscn. I like that approach for the sake of keeping everything organized. But my question is: How do I reference a variable in a script attached to a node in a instanced scene?

For instance. My scene structure is Main> Player,Baddie. Player and "Baddie" being instanced scenes containing a KinematicBody 2D, Sprite, and CollissionShape 2D. My goal is to "reference" my velocity variable in the Player.tscn and pass that to the Baddie.tscn so I can create a player follow script for the Baddie. That way when instanced into the Main.tscn with a player they start tracking to the player.

Pretty simple I would assume. And if I just made everything in a single scene I could have figured it out. But I am kinda stumped on this. Any help would be appreciated.

There are multiple ways you can programmatically get a reference to a instanced node from another instanced node, each with their own pros and cons.


The simplest way is to use get_parent and then get_node. Using the screenshot you posted, you could access the player's variables with this method like this:

# Baddie.gd
extends KinematicBody2D
export (int) var speed = 200
var player = null

func _ready():
	player = get_parent().get_node("Player")
	var b = player.velocity

What this code is doing is it first gets the parent node, in this case the node named Node2D, and then uses get_node to get a child node of Node2D, in this case we want the node named Player.

This has the advantage of being easy to quickly write up and use, but this method assumes that the player and the baddie will both be children nodes of Node2D directly. In other words, you cannot have the Player node or the Baddie node parented to any other node than Node2D, as otherwise it will be able to access each other using the code above.

So long as your node structure doesn't change, this method will work fine.


Another method you can take is exporting the node path to the player node, so you can set which node the baddie gets through the editor. For example:

# Baddie.gd
extends KinematicBody2D
export (int) var speed = 200
export (NodePath) var path_to_player = null;
var player = null

func _ready():
	player = get_node(path_to_player);
	var b = player.velocity

Then you just need to select the Baddie node in the editor, and in the script variables you will find that you can assign path_to_player to a node in the scene.

This method works well if you do not know where the player will necessarily be in the scene. However, this method doesn't really work if you are spawning/instancing enemies dynamically or at run-time, as you cannot easily set path_to_player in code.

This method is really ideal for levels where all of the enemies and the player are predefined and placed within the level.


Finally, the last method is to define a manger of sorts to access other nodes. There are several ways to write the manager, but a simple manager could look something like this:

# Attach to Node2D!
extends Node2D
var spawned_entities = {}
func add_entity(entity):
	if (spawned_entities.has(entity.name) == false):
		spawned_entities[entity.name] = entity
	else:
		print ("Entity already added to spawned entities")
func remove_entity(entity):
	if (spawned_entities.has(entity.name) == true):
		spawned_entities.erase(entity.name)
	else:
		print ("Entity not within spawned entities")
func get_entity(entity_name):
	if (spawned_entities.has(entity_name) == true):
		return spawned_entities[entity_name]
	else:
		return null

And then in Player.gd, you would need to add the following:

# Add the following to Player.gd somewhere!
var entity_manager = null
func _ready():
	# Insert other code here
	# NOTE: getting entity_manager like this may or may not
	# not work depending on your project and how the node tree is setup.
	# The important part is just getting a reference to it, how you do it is
	# up to you. We will use get_parent for this example
	entity_manager = get_parent()
	# Add the player to the spawned entities
	entity_manager.add_entity(self)

Finally, you could get the player in the baddie script using the following code:

# Baddie.gd
extends KinematicBody2D
export (int) var speed = 200
var entity_manager = null
var player = null

func _ready():
	# As previously mentioned, you might need to get entity_manager
	# differently depending on your project
	entity_manager = get_parent()
	# Add the enemy to the spawned entities
	entity_manager.add_entity(self)
	# Get the player from the entity manager
	player = entity_manager.get_entity("Player")
	var b = player.velocity

The advantage of using a system like this is that so long as your scripts can find a reference to Entity_Manager/Node2D, you can access any of the spawned entities added to the spawned_entities dictionary. Then when a entity is removed, you just need to call entity_manager.remove_entity(self) before calling queue_free to remove it from the dictionary.

This makes it easier to access entities that are spawned while the game is running, as so long as you know its name (in the case of the example above), you can get a reference to it. You could also store the entities differently depending on your needs. For example, you could store all of the entities in a list instead of a dictionary.

The downside of this method is it takes a bit more boiler plate code to get going, but if you are spawning/instancing enemies or other entities you need to access from other scripts during run-time, this might be a good way to be able to access them through a single interface.

The other downside with this method is that all nodes still need to get a reference to Entity_Manager/Node2D before they can access the other nodes.

Also, I should note that this method really should be tailored to the needs of your game. For example, if there is only ever one player, than storing the player in a dictionary might not be ideal, and instead you might want to define a variable in Entity_Manager to store the player instead for easier access.


Of course, there are many other ways you could go about it based on what works best for you and your project. Hopefully this helps! :smile:

Side note: Welcome to the forums!

OH WOW! First off thank you! I honestly gave up on public forums 10 years ago for help in learning software. Long story short I decided to give it a shot with Godot because the community seemed to be very helpful and I can't let experiences from my youth take away great resource to learn again.

With that being said. I am going to open Godot and take a look at what you posted here and see if I can make sense of everything. I will update my post with that information in case it's helpful to someone else with the same question.

Seriously thank you for taking the time to do this write up. Gives me serious faith in community again. haha.

Nate.

Well Eureka!

After I dove into it and a little trial and error I figured out the bases of what I wanted to do! Man that is satisfying. With that being said, I set forward to make the "Baddie" just follow after the player. And with this script I did just that. I am starting to gather how Godot can call to different attributes displayed in the UI and manipulate them. So something has begun to click. Now to keep working on my little project.

    extends KinematicBody2D
    export (int) var speed = 200
    
    var player = null
    var velocity = Vector2()
    var target = null
    
    func _ready():
    	player = get_parent().get_node("Player")
    
    	
    
    func _physics_process(delta):
    	var target = player.position
    	velocity = (target - position).normalized() * speed
    	if (target - position).length() > 5:
    		velocity = move_and_slide(velocity)
    	print (target)

Thank you again!!

@ThorMuscles said: OH WOW! First off thank you! I honestly gave up on public forums 10 years ago for help in learning software. Long story short I decided to give it a shot with Godot because the community seemed to be very helpful and I can't let experiences from my youth take away great resource to learn again.

With that being said. I am going to open Godot and take a look at what you posted here and see if I can make sense of everything. I will update my post with that information in case it's helpful to someone else with the same question.

Seriously thank you for taking the time to do this write up. Gives me serious faith in community again. haha.

Nate.

No problem! I'm happy that what I wrote can be of assistance.

I would say for the most part the Godot community is one of the most open and helpful communities I've been a part of. Almost everyone I have interacted with through Godot has been very helpful, given great feedback for my projects, and provided insightful answers to questions I have had.

I hope you will continue to be part of the community here! :smile:

Note: due to my position here on the forums I have a small bias.

@ThorMuscles said: Well Eureka!

After I dove into it and a little trial and error I figured out the bases of what I wanted to do! Man that is satisfying. With that being said, I set forward to make the "Baddie" just follow after the player. And with this script I did just that. I am starting to gather how Godot can call to different attributes displayed in the UI and manipulate them. So something has begun to click. Now to keep working on my little project.

    extends KinematicBody2D
    export (int) var speed = 200
    
    var player = null
    var velocity = Vector2()
    var target = null
    
    func _ready():
    	player = get_parent().get_node("Player")
    
    	
    
    func _physics_process(delta):
    	var target = player.position
    	velocity = (target - position).normalized() * speed
    	if (target - position).length() > 5:
    		velocity = move_and_slide(velocity)
    	print (target)

Thank you again!!

Great! I'm glad you got it working :smiley:

4 years later