How use function from another script?

Godot Version

4.3

Question

I’m new here.
All the guides on this topic did not help at all.
I’m trying to make it so that when a player enters the zone, a separate script with the spawn of monsters function will start its work.
But I don’t understand how call a function from another script.

Ok so let’s break this topic down into two parts:

  1. Detecting the player entering the Zone
  2. Starting the monster spawn function

In this case you don’t even need to call a function from another script. Instead, the spawn zone script can just detect the player, and then start it’s own work.

For the zone you would use and Area2D node (assuming 2D, otherwise use Area3D) with a collision shape as a child to define the shape of the area/zone.

For your player, make sure to put it into a group. I will assume that the group is named "player". I will also assume that the player is a physics object, like a CharacterBody2D for example.

Then, add a script to the Area2D we created earlier:

extends Area2D  # Or 3D, depending on your game

func _ready():
    # Connect the body entered to our custom function
    body_entered.connect(_on_body_entered)

func _on_body_entered(other_body):
    # Check if the body that entered the zone is the player
    if other_body.is_in_group("player"):
        print("Detected the player, we can spawn stuff now!")

I hope this answers your question, even though there is no calling of functions on other scripts.


If you want to know how to call functions on another script, the way is always: first get a reference to the node/object that the script is attached to, then use the dot to call a function. For example imagine a level script on your root node, and a node called “Flower” as a child of your level. Then you could get the reference via the node path, and call a function like this:

func _ready():
    var other_node = $Flower
    other_node.bloom()

I have spawn and arena scripts in different scenes, would the above example with a body_entered work in this case?

In second case:
I insert a link to the spawner to initialize the function, but I get an error instead.

@export var SPAWNER = preload(“res://scripts/spawner.tscn”)

func _on_area_2d_body_entered(body: Node2D):
SPAWNER._spawner_ready()

ERROR:
Invalid call. Nonexistent function ‘_spawner_ready’ in base ‘PackedScene’.

Yes, you can link to another object. Let’s assume you have this scene tree:

Area2D (your zone)
 ├─ CollisionShape2D
 └─ SpawnerInstance

Assuming your script is attached to the Area2D, you can connect a function to the signal like this:

@onready var spawner = $SpawnerInstance

func _ready():
    body_entered.connect(spawner._spawner_ready)

Or use the UI in the editor. You can select the Area2D and head to the “Node” dock, then select the signal and connect it to your spawner node function.


Ok I think there is a few things confused here. So let’s start with a few definitions:

  • Script:
    This is the source code file you have. In itself, it does nothing. It can be instanced to create objects.
  • Instance/Object:
    This is an object in the engine, possibly with a script attached. This is what you can call functions on.
    When you run your game, all the nodes in your scene are instances. Some may have a script attached. There can even be multiple instances with the same script (for example, you can have one enemy.gd script and instance it multiple times to have multiple enemies.
  • Scene File:
    This is a tscn file to save what a scene contains. Think of it as a kind of “blueprint” for creating a scene. In itself it does nothing. It must be instantiated (for example, by loading it as the main scene. Or by including an instance of it in another scene).

The TL;DR of this is: You need a reference to an object if you want to call a function on it.

Now let’s look at your code. The following line loads a Scene File:

@export var SPAWNER = preload(“res://scripts/spawner.tscn”)

That is just a blueprint of how to create the spawner scene. It does not know about it’s instances (and it can’t. Like imagine this was the blueprint for an enemy scene: There could be many different instances of that scene file, so there is no way to know which enemy instance you want to use).

So instead of this, you need to get a reference to the actual Instance of the spawner scene. The usual way is to use a node path. Now, I don’t know your scene layout. But let’s say you have a node tree like this:

Area2D (your zone)
 ├─ CollisionShape2D
 └─ SpawnerInstance

Then when your script is attached to the Area2D, then the node path would be $SpawnerInstance as it is the direct child.

So your code would need to look like this (note the onready keyword, you can only access stuff from the scene tree once the tree is ready:

@onready var spawner = $SpawnerInstance

func _on_area_2d_body_entered(body: Node2D):
    spawner._spawner_ready()
1 Like

I get it now. Thank you very much for a very detailed answer!

No problem, happy to help! :gdparty:

I’m sorry, I put it wrong. I originally meant that the trees are different for the arena and the spawner, but it seemed to me that the phrase “scene” was correct in this situation at that time.

I thought it was not worth wasting your time even more without getting the desired answer, so I decided to close the question. But now I have overcome this, and I want to ask you to help me again…

This is my arena.
In which, when entering a zone from another tree, a spawner should be called
изображение

And that is spawner
изображение
I want the spawner to be universal, so I don’t throw it into the tree with the arena

Sorry again for this…