0 votes

Hi,

We have main scene with enemy spawned by code:

var enemy_ship = preload( "res://enemy_ship.scn" ).instance()
get_node(".").add_child(enemy_ship)

How to access to main scene nodes from this node?

get_node() does not work - it has access only to enemy_ship.scn nodes :(

Thanks

in Engine by (144 points)
edited by

sorry if i am being persistent here but look this image

enter image description here

in the left side i have a script of a ship not created yet. Look the line

print(get_node("...

now the right side, this is the structure of the game, the ship is created by an script in ApolonPlanet and i can acess all structure... Stage1, Nav, Camera, System1 in this case... if you can give more info, maybe i can spot the error... :D but feel free to not do so... :D

mmmm.... i found int get_instance_ID ( ) const - it returns ID.

instance_from_id( int instance_id )

Thanks. For now i don`t know how it will be works in my code - i must test it.

Yeah, your scene system is clear. But ... code on the left - is a 'ship' or 'ApolonPlanet' code?
I tried to access to main loop nodes exactly from 'spawned ship' code
My game system is:
-There are some turrets, controlled by player (spawned by main game loop script)
-There some enemies with "search random turret&attack" AI (spawned by main game loop script)

The problem is - how to find 'turret" node in the scene and identify it as "turret"
(there are many different game objects in the scene)

code on the left is a script attached to the ship... ApolonPlanet spawn the ship :)

ok, i once have a similar problem, i have an AI that look for enemies in the scene, i attached a area2d and analyze to find 'possible enemies' like this:

if a body enter in contact with the area2d, access a variable in the script of the body that tell me his class, like friend, enemy, etc

something like:

_on_area2d_enter( body ):
    if get_node("../"+body.get_name()).Class == "Enemy":
          #attack

so, by body.get_name(), if i have a Turret1 node, will be:

get_node("../"+"Turret1" this is equal to

get_node("../Turret1) then i acess the variable in his script

get_node("../Turret1).Class

dont now if this resolve your problem, but can give you some ideas

if you dont want an area2D, you can keep track of objects created and their type in array and search for then, when find, you will have his name and class(like enemy), by his name you can access it with get_node...

Thank you for help. I used your recommendations and overall it works for me. I`ll continue optimizing my code.

2 Answers

+2 votes

Haven't tested myself, but I think this is what you are looking for:

get_tree().get_current_scene()
by (112 points)

Ohh...absolutely forget about this! It works! Thank you.

You're welcome :)

+1 vote

I am sorry if I don't provide the answer you are hoping for, but you should avoid accessing nodes in the way you described.
By referencing nodes outside of your scene you are a) making assumptions about the scene that your scene is going to be instantiated in without communicating them and you are b) creating a scene that cannot be run on its own.

In order to avoid that you could either store the referenced nodes in variables and require the instantiating code to fill them (either directly or using a setter or setup-Method - a setup method would probably be the best way as it would list all required variables as parameters), or you could use signals in those places where you would call methods on the referenced node.
For example if the scene you are creating is a target crosshair and you want the turret to always target it you could add a signal that triggers whenever the crosshair moves ("onMove" or something) and passes the new position as an argument. In the instantiating scene you would then assign a function to the signal that turns the turret.
That way the crosshair can be tested by itself and if someone else wants to use the scene they don't have to read the source code or run it first to see which nodes are required with which names, because they can just open the menu for attaching signals and see a list of all signals.

by (1,122 points)

Hmm.... So, what is your solution for "Enemy AI" which spawned on the map (current scene) and must search targets in scene for attack?

-We must spawn random types of enemies in random position with random time. Spawned enemy don"t know situation on the map at the moment. How we can use "signals"? "Enemy AI" must scan all node tree, identify concrete node as target (turret) and attack it. If AI don`t find any targets, it switch to "idle" mode and continue scanning targets.

get_tree().get_current_scene().get_node("../MainLoop").get_child()

must works and it works - i tested it. Its wrong?

I am currently working on something similar, and I actually have two solutions implemented. In my game the AI can have exchangeable strategies, types of perception, movement and skills.

Now when the game spawns a new creature it passes the level node to it so that the creature's perception node can call a function on the level node that returns all creatures of a given player. This is the method that I currently use which is intended for creatures that can always see the whole map.

If I should add creatures later that should only care about enemies in a certain area it would be redundant to have the level return all possible targets and then write code yourself that filters out which ones are in the correct zone, since that's exactly what physics engines are made for.
So in that case I would add an Area2D or something similar to the perception scene and use that to request all objects inside it.
Unfortunately you can't name physics layers, so if you want to separate targets from other colliders using layers you still need to open the perception scene to tell which objects are returned as targets.
Alternatively you can add a method to all potential targets (something like getType() or getFaction()) that returns something like "AI" or "neutral" etc. That way you can skip all found colliders that don't have that method and filter the rest by their faction / type.

That way querying objects is reduced to either of these two options:
1. use a function call to have a node report their subnodes (so the code that defines which nodes to report is part of the scene that needs to work with the code)
2. use a built-in mechanic like Area2Ds or CollisionShapes to query nodes based on their position.

Your solution works of course, but I think it's more error-prone, since anyone working with it needs to know where to put new nodes in the hierarchy and how to name them. If my level-node doesn't have a "getCreaturesOfPlayer(...)"-function I can use an assertion. If your scene doesn't have a turret-node you can't tell whether it's a bug or whether there just don't happen to be any enemies at the time.

Hmm... Yes, it seems your solution is more flexible than mine. Ok, i will keep it in mind. Thanks.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.