How to change between characters in at run time.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By romndesh

I have a game where the main character is a KinematicBody2d with an Sprite and CollisionShape2d as node childs. I saved the character as a branch scene.

The purpuse of the game is that when te player touch an object(area2d) the character becomes to another character. So, I need to disable, kill, delete, or hide the main character when the object is touched and make the second character visible in the scene. I used queue_free() but works only one time, the second time I get this error:
“Attempt to call function ‘queue_free’ in base ‘previously freed instance’ on a null instance”

This is the script of the object that I want to touch.

extends Area2D

onready var player = get_tree().get_nodes_in_group("SimpleG")[0]
onready var player2 = get_tree().get_nodes_in_group("SimpleG")[1]

func _physics_process(delta):
    var bodies = get_overlapping_bodies()

    for body in bodies:
        if body.name == "Player":
                 #code to switch characters
:bust_in_silhouette: Reply From: MysteryGM

I used queue_free() but works only one time, the second time I get this error:
“Attempt to call function ‘queue_free’ in base ‘previously freed instance’ on a null instance”

And then you link all but the code that is actually producing the error :slight_smile:
These are possible problems:
1.) You aren’t instancing a new copy when you make the player “visible” again. When calling queue_free() the object is removed and has to be instanced() back.

2.) Event/signal is triggered more than once rapidly. This is actually common with Godot’s overlap, it fires a signal quickly after the first.
In the Godot Step by Step they disable the collisions to prevent this:

func _on_Player_body_entered(body):
    hide() # Player disappears after being hit.
    emit_signal("hit")
    $CollisionShape2D.disabled = true

Instead of hide you use queue_free()

I hope one of these help.
If none of these help can you then link the code removing objects, so that we can see if the problem is there maybe.

Thanks for the help! I did the following things:

First of all I added my player(kinematicBody2d) to a group. After that, in the Area2d object script I got the players node througout the groups. Finally I connected the signal _body_entered(body) to disappear the Area2d and change the players.

Here is the script if someone wants to use it.

extends Area2D


# "action_when_body_is_touched" & "SimpleG" are the groups where the players belongs.

onready var player = get_tree().get_nodes_in_group("action_when_body_is_touched")[0]
onready var player2 = get_tree().get_nodes_in_group("SimpleG")[0]
var pos = Vector2()

func _ready():
	pass
			
func _on_Food_body_entered(body):
	if body.get_name() == "Player":     # Player is the name of the kinematicBody2D
		# code for kill the pizza
		queue_free()
		emit_signal("hit")
		$shape.disabled = true     # shape should be the name of your collisionShape2d, by default: CollisionShape2D
		
		# code for kill the player and set the new one.
		player.queue_free()
		pos = player.get_global_position()
		player2.position = pos
		player2.show()

romndesh | 2018-10-10 19:35