2
votes

Lots of googling and I'm still not grasping what is probably a simple solution.

Scene: "Main". Contains a TileMap "Grid" with a script attached to it "Grid.gd".

Scene: "Player". Contains a KinematicBody2D "Player" with a script attached to it "Player.gd"

In Player.gd, I need to call a method in Grid.gd "_Calculate", pass it two variables, and have it return one variable.

var vNewPosition = Grid._Calculate(vPlayer, vInputDirection)

Error: The identifier "Grid" isn't declared in the current scope.

Obiously I need to reference the Grid.gd script somewhere to access it, but none of the many examples I have tried work.

Thanks in advance, Josh

1
Does the "Main" scene also contains the "Player" scene? If not, how are these scene related? - Theraot
They are separate scenes. The Main scene has an instance of the Player scene. Basically there will be multiple Scenes (levels), all of which use an instance of the Player scene. - JSands

1 Answers

2
votes

Given that

The Main scene has an instance of the Player scene

And

In Player.gd, I need to call a method in Grid.gd "_Calculate", pass it two variables, and have it return one variable.

I'll give you a few options.


The bad way

If Player knows the node path to Grid, it could use get_node to get it.

onready var _grid = get_node("../../grid")

Or something like that.

And then use it:

var vNewPosition = _grid._Calculate(vPlayer, vInputDirection)

This approach is, of course, not recommended. It will break if the node path is wrong.


The common way

Assuming Player does not know the node path (which is more likely), you can export a NodePath variable in Player.gd and use it to get the Grid:

exprort var grid_path:NodePath
onready var _grid = get_node(grid_path)

Then you need to set the Grid Path property in the Main scene to Grid.

This approach is better than the prior one, in that it does not depend on the path to Grid. However it still depends on a Grid being there. If Player makes no sense when there is no Grid, this approach is OK.


The good way

If Grid may or may not be there, and we want Player to work regardless, we can tweak the above approach:

exprort var grid_path:NodePath
onready var _grid = get_node_or_null(grid_path)

And remember to check if grid is null before using it:

if grid == null:
    return # or whatever

var vNewPosition = grid._Calculate(vPlayer, vInputDirection)

Or like this:

var vNewPosition = grid._Calculate(vPlayer, vInputDirection) if grid != null else null

Which also allows us to specify a default value that vNewPosition will take when there is no grid (the null at the end of the line). And thus you can have the Player work when there is no Grid, and when there is it will use, and regardless of where (because Main tells it where it is).

This solution is not completely decoupled, because Player still knows grid is a thing that has _Calculate. Also we presume there is zero or one, not multiple. I can think of a way to approach that, but decoupling for the sake of decoupling is unnecessary. I'm calling this good enough for your use case. Yet, let me know if you want the over-engineered way.