How to keep a proper area_enter signal after switching scene ?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By mbenoni
:warning: Old Version Published before Godot 3 was released.

Hello everybody,

I’m posting this question about a problem that I encounter currently in my project.

About the problem itself :

  • I have set a “character” as an Area (3D), and that is monitoring.
  • I have set some objects as Area (3D) too, that are monitorable.
  • I’ve made a connect(“area_enter”,self,“someFunc”) on the character node.

And, at the first time, it works PERFECTLY FINE ! someFunc() is called everytime when my character enter an Object.

The problem occurs when I leave the scene and load another, and then come back to the scene. After some times, many objects aren’t detected anymore. It seems that my “area-enter” signal is not emitted anymore.

So, have you any idea about why it doesn’t work ? Why it bugs when i’m leaving the scene and then comes back ?

In order to “show” my problem in details:

This is my script for the character:

extends Area

var SPEED_FORWARD = Global.SPEED
const SPEED_SIDE = 450
const SPRITE_SIZE = 50
const SIZE_MAP = 720

var side
var inputNode
var areaNode

func _ready():
	inputNode = get_node("../ControlCharacterUI/CharacterUI")
	set_monitorable(true)
	set_enable_monitoring(true)
	self.connect("area_enter", self, "on_area_enter")
	set_fixed_process(true)

func _fixed_process(delta):
#We get the move wanted by the user by calling the appropriate node.
	side = inputNode._get_move()

	#If the right or left limit of the "moving zone" is reached, we forbid the move.		
	if(self.get_transform().origin.x - SPRITE_SIZE < -SIZE_MAP/2): 
		if (side == -1):
			side = 0
	if(self.get_transform().origin.x + SPRITE_SIZE > SIZE_MAP/2):
		if(side == 1):
			side = 0
				
	# We move the character forward and left/right according to the side previously get
	self.translate(Vector3(side * SPEED_SIDE * delta, 0, -delta * SPEED_FORWARD))
	

func on_area_enter( area ):
	area._action()

And there my script for the objects:



var isAlreadyCollided = false
func _action():
	if(!isAlreadyCollided):
		isAlreadyCollided = true
            -----DOING SOME IRREVELANT HERE-----
		self.hide()

func _ready():
	set_monitorable(true)
	set_enable_monitoring(true)

Here are screens :
http://img15.hostingpics.net/pics/800784SuperSolutecShape.png

http://img15.hostingpics.net/pics/168115SuperSolutecArea.png

(Objects have the same parameters, except for being monitorable instead of monitoring, and the shape, that is a BoxShape instead of a CapsuleShape)

For the context :
The elements/objects are dispatched in a “Level1.tscn”:
http://img15.hostingpics.net/pics/164673Level.png

And next, in a main scene, there is our Character, and a script add the “Level” as a child of an “AllElements” node.
http://img15.hostingpics.net/pics/144747Mainarbo.png

And here the portion of script used in AllElements:

var scene = load("res://Levels/Level1.tscn")
var instance = scene.instance()
self.add_child(instance)

Final scene : http://img15.hostingpics.net/pics/348996Final.png

SO, that’s all for how it is done.

The problem occurs when we switch between the main scene and another scene, and then come back to the main scene. It’s done with :

Global.goto_scene("res://Menus/MainMenu/MainMenu.tscn")

in the “main.tscn” and

Global.goto_scene("res://main.tscn")

in the “MainMenu.tscn”.

Where Global.goto_scene(path) is :

var current_scene = null

    func goto_scene(path):
        call_deferred("_deferred_goto_scene",path)
    
    func _deferred_goto_scene(path):
        current_scene.free()
        var s = ResourceLoader.load(path)
        current_scene = s.instance()
        get_tree().get_root().add_child(current_scene)
        get_tree().set_current_scene( current_scene )

After changing of scene ( main.tscn → MainMenu.tscn → main.tscn … ) like 2 to 4 times, the area-enter signal doesn’t work anymore.

Have you any idea ? Thanks you in advance !

EDIT: The same problem occurs if, for example, I load the Level1.tscn on ready() 's function of AllElements, then instanciate it, then queue_free() it, then re-instanciate it. After a while, some elements aren’t detected by area_enter anymore.

A bit too hard to say. I would recommend debugging your signal with a print out. Just to see if it exists.

for sig in get_signal_connection_list("area_enter"):
	printt(sig.method, sig.source.get_name(), sig.target.get_name())

avencherus | 2017-04-20 19:50

Hello avencherus !

I’ve put the lines you give me in a _fixed_process, in order to see if my signal does’nt exists after a time.

My logs are clear :

on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec
on_area_enter	SuperSolutec	SuperSolutec

So it seems the connection is here. And these logs are here when my obstacles are detected and when they are not. (after all, some of the objects continue to work proper among the objects. The problem is they are all the same, so why some work and some others don’t ? )

I’ve tried, instead of “load → instance add_child → free → instance → add_child → free”
to do "Load → Instance → remove_child → add_child → remove_child " and it seems in this case it’s work.

So it confirms the problem is about “freeing” a scene and reinstantiate it later, when switching scene or replace some sub-scenes with scripting dynamically. Any idea ?

(I will continue to test some prints etc)

PS EDIT:

I’ve tested with the following in the fixed_process of my character:

printt(get_overlapping_areas())

and it seems it prints “Area” only when I go on “working” obstacles with my character. When my obstacles aren’t detected and are bugged, it doesn’t print anything, no overlapping area.

PS PS EDIT :
It seems that, in debugging mode → Monitors, in the category Physics3d, the “Collision Pairs” go down from 12 to 4 when it starts bugging in the scene.

mbenoni | 2017-04-21 07:33

Godot version?

eons | 2017-04-27 14:13

It’s the v2.1.3 !

mbenoni | 2017-04-27 14:19

:bust_in_silhouette: Reply From: mbenoni

So, i’ve not resolved the problem itself, but that’s my conclusion:

It seems that there is a problem with collision/body_enter/area_enter when instancing a scene multiple times, as can be seen above.

I’ve found another topic that state the same problem on 2D Area, with no answers too.

So it seems it’s not an “editor-use” problem, but more a problem in the code of the engine. Maybe it should be pointed out to the devs or in the godot engine’s github.

For me, i’ve solved this by loading and instancing ALL of the scenes that contains collisions/area elements or others when my game starts, and re-use them again and again. I’ve made some scripts that “reinitialise” positions, etc, in order to have only one instance of a level with his elements, or of my character, in all the game and from launching to closing.

It’s a bit “ugly”, but it’s by the way the only solution that works currently.

If someone find another, or want to show this on the github, be free to do !