0 votes


I'm trying to make a turn based game where at the start of a player's turn I want a camera ($Camera2D) to center on the current player.

With the code I'm running below, I get the following error:
"Attempt to call function 'maptoworld' in base 'null instance' on a null instance.

Here's my code flow:

* MapView (Node2D node)
** Camera2D (Camera2D node)
** TileMap (TileMap node)

Top Node: MapView
Attached Script: MapViewtest1.gd
extends Node2D onready var turn_queue_gd = preload("TurnQueue.gd").new() func _ready(): turn_queue_gd.next_turn()

Script: TurnQueue.gd
Attached to Node: not attached to any node
extends Node func next_turn()->void: var player_gd:Node = preload("Player.gd").new() # start the player's turn yield(player_gd.play_turn(), "completed")

Script: Player.gd
Attached to Node: not attached to any node
extends Node func play_turn()->void: # which player? var player_num:String = "player1") # this prints the correct Vector2 map_position: # print(GameConstants.capital_location_dict[player_num]) # move camera to player's start point $Camera2D.set_offset($Navigation2D/Terrain_TM.map_to_world(GameConstants.capital_location_dict[player_num]))

Basically, I'm thinking that since Player.gd is not attached to the tree structure (gettree().getroot()) it doesn't know what $Camera2D is.

So my general question is: If you have a gd script not attached to any node, how do you reference specific nodes in a scene (e.g. $Camera2D)?

Thanks for your time,

P.S. I don't know how to add tabs here, but the code is indented correctly.

in Engine by (176 points)

Is your player.gd script supposed to be a Singleton?

No, though I do have a script that is a Singleton (GameConstants.gd) that stores the dictionary: capitallocationdict.

My thought now is that I am structuring this wrong. I was thinking of having one node triggering a script, and then having a bunch of stand alone scripts interacting with each other to handle the logic/flow.

From what I have read, creating and using nodes are "cheap" so I have created multiple scenes:

* which has TurnQueue.gd attached to it
* and has PlayerTurn.tscn as a child node

* which has Player.gd attached to it

Now I can simply rotate through player (nodes) for turns and I should be able to access $Camera2D since they are in same tree.

Does that seem like a better approach?
e.g. Better to have many nodes with attached scripts vs. a few nodes with lots of stand alone scripts

Could you reformat your code snippets? It's kind hard to read.

Just make 4 spaces for each indent.

1 Answer

+2 votes
Best answer

You could store a reference to the main scene inside of the player.


var turn_queue_gd = preload("TurnQueue.gd").new(self) # you can pass. variables to scripts when creating them. The script will need an _init function.


var main

func _init(main):
    self.scene = main

func next_turn():
    yield(player_gd.play_turn(scene), "completed")


func play_turn(scene):
    scene.get_node("Camera2D") # Now you can just get the node from the scene. :)
by (3,908 points)
selected by

Cool! Interesting... will have to play around with this.

So in regards to my original error:
"Attempt to call function 'maptoworld' in base 'null instance' on a null instance"

it looks like my mistake was not referencing the node relative to where my current script existed.

Without having to worry about where my gd_script is on the tree, I was able to successfully reference them this way:

old (error way):

new (correct way):

Thanks for your time @SIsilicon

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 Frequently asked questions and 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 [email protected] with your username.