Turn off visibility on event

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

My problem is that i want to add a function where when the Player is pressed that the Enemies disappear unill the next level loads

This is my Main Script for the Enemy

Option 1 that i tried:

var Enemy2 = [
preload("res://Enemy/Enemy1.tscn"),
preload("res://Enemy/Enemy3.tscn"),
preload("res://Enemy/Enemy4.tscn")
]

func _on_player1_pressed():
	     Enemy2.visible = false

Invalid set index ‘visible’ (on base: ‘Array’) with value of type ‘bool’

Whenever i try to make this Enemy2 invisible some error with Array happens.

So i tried Option 2:

signal next_level

var Enemy2 = [
preload("res://Enemy/Enemy1.tscn"),
preload("res://Enemy/Enemy3.tscn"),
preload("res://Enemy/Enemy4.tscn")
]

func _on_player1_pressed():
       emit_signal("next_level")

Enemy Script:

func  _ready() -> void:
      $Enemy2sprite.connect("next_level", self, "_on_next_level")


#Option 1

func _on_next_level():
     $Enemy2sprite.visible = false



#Option 2

func _on_next_level():
    $Tween.interpolate_property($Enemy2sprite, "modulate:a", 1, 0, 1)
	$Tween.start()


#Option 3

func hide_for_time(t):
	visible = false
	yield(get_tree().create_timer(t), "timeout")
	visible = true

func _on_next_level():
	get_node("Enemy2sprite").hide_for_time(1.0)
:bust_in_silhouette: Reply From: ra45

Do you need to be invisible, but still interact with the player? If not, you can remove them. But if you need it, you need to get all the enemies in an array, by get_node(enemy) or if you have all of them under one node by using get_children(). After that, you need to loop through the array and set the visibility.

for i in children:
      i.visible = false

No i don’t have to interact with the Player

i tried to remove and erase but it doesn’t react

func _on_player1_pressed():
         Enemy2.remove(3)
         Enemy2.remove("res://Enemy/Enemy2.tscn")

I also tried these with erase() function. but nothing happens
I can start the Game and press Player1. but it ignores these codes
any clue what im doing wrong?

Rayu | 2020-11-22 07:12

The best way to remove a node from a scene is free() or queue_free(). The last one is the best because it removes the node at the end of the current frame.

Enemy.queue_free()

You can also call commands on groups. So you can put all of your enemies in an enemy group and queue_free 'em all.

get_tree().call_group("Enemy", "queue_free")

ra45 | 2020-11-22 09:21

No reaction :confused:

Maybe it has something to do with this

func spawn_enemy1():
	var rand1 = floor(rand_range(0, Enemy1.size()))
	var piece1 = Enemy1[rand1].instance()
	add_child(piece1)

Rayu | 2020-11-22 09:44

Maybe it has something to do with this

It doesn’t.

I recommend you to use the debugger. Make a breakpoint on the line that removes the enemy. If you found something weird I am here to help.

ra45 | 2020-11-22 10:03

When i use Enemy.queue_free()
Debugger: Invalid call. Nonexistent function ‘queue_free’ in base ‘Array’

When is use Enemy.get_tree().call_group(“Enemy”, “queue_free”)
the Debugger shows nothing at all

Rayu | 2020-11-22 10:51

Debugger: Invalid call. Nonexistent function ‘queuefree’ in base ‘Array’

You need to call queue_free() on the node like Enemy[0].queue_free()

Enemy.gettree().callgroup(“Enemy”, “queue_free”)

This works only if made a group and assigned the enemies to the group and also you don’t need to put Enemy before. You use only gettree().callgroup(“Enemy”, “queue_free”)

Sorry for confusing you

ra45 | 2020-11-22 11:04

In order to get the node i used a signal on my Main Script to The Enemy script

Main Script
signal next_level

fun _on_player1_pressed():
     emit_signal("next_level")

Enemy Script (The Script is on a RigibBody2D and the Sprite has the texture, it doesn’t matter if the texture is gone or the RigidBody2D as whole)

idk wich func i should put it in. I’ve put it on the ready fun and _process func

func _ready():
     $Enemy2Sprite.connect("next_level", self, "_on_next_level")
     
func _on_next_level():
     $Enemy2sprite.queue_free()    .visible = false    .remove()    .erase()
     #i've tried them all

but what im a doing wrong the signal is not connecting

E 0:00:08.809 connect: In Object of type ‘Sprite’: Attempt to connect nonexistent signal ‘next_level’ to method ‘RigidBody2D._on_next_level’.
<C++ Error> Condition “!signal_is_valid” is true. Returned: ERR_INVALID_PARAMETER
<C++ Source> core/object.cpp:1503 @ connect()
Enemy2.gd:45 @ _process()

and i have no idea how to make a group :confused:

Rayu | 2020-11-22 12:58

In the main script before(usually at the top) you call emit_signal you need to declare that signal using:

signal next_level

And in _on_next_level(): you need to put self.queue_free(). You don’t need to get the node if it is itself.

ra45 | 2020-11-22 13:31

E 0:00:10.987 connect: In Object of type ‘Sprite’: Attempt to connect nonexistent signal ‘next_level’ to method ‘RigidBody2D._on_next_level’.
<C++ Error> Condition “!signal_is_valid” is true. Returned: ERR_INVALID_PARAMETER
<C++ Source> core/object.cpp:1503 @ connect()
Enemy1.gd:45 @ _ready()
Game.gd:218 @ spawn_enemy4()
Game.gd:78 @ _ready()
_

Enemy1.gd:45 @ _ready()

$Enemy1sprite.connect("next_level", self, "_on_next_level")

Game.gd:218 @ spawn_enemy4()

func spawn_enemy4():
	var rand4 = floor(rand_range(0, Enemy4.size()))
	var piece4 = Enemy4[rand4].instance()
	add_child(piece4)   <------- line 218

Game.gd:78 @ _ready()

func _ready() -> void:
	$Node2D_Z_Index/ControlScore/ScoreCount.text = str(Globals.Score) 
	set_process(true) 
	var actor_id = randi() % 4 + 1
	if actor_id == 1:
		spawn_player1(1)
		for _i in range(4 + Globals.Score):
			spawn_enemy1()
	elif actor_id == 2:
		spawn_player2(1)
		for _i in range(4 + Globals.Score):
			spawn_enemy2()
	elif actor_id == 3:
		spawn_player3(1)
		for _i in range(4 + Globals.Score):
			spawn_enemy3()
	else: 
		spawn_player4(1)
		for _i in range(4 + Globals.Score):
			spawn_enemy4()  <------ line 78

i use the the $Enemy1sprite.connect(“next_level”, self, “_on_next_level”) on all 4 Enemy scripts maybe thats the issue?
and this error keeps reapeating on all Player1,2,3,4 Enemy1,2,3,4

Rayu | 2020-11-22 14:42

try self.connect("next_level", self, "on_nextlevel_").

type ‘Sprite’: Attempt to connect nonexistent signal ‘nextlevel’ to method ‘RigidBody2D.onnextlevel’.

this looks very weird

ra45 | 2020-11-22 15:06

Nope :confused:

How can it say that the signal is nonexistent How? HOW?

Main Script:

signal next_level

func _on_player1_pressed():
       emit_signal("next_level")

Then the signal goes to the Enemy script

func _ready():
         $Enemy2Sprite.connect("next_level", self, "_on_next_level")
or 
         self.connect("next_level", self, "on_nextlevel_")

func _on_next_level():
     $Enemy2sprite.queue_free()    .visible = false    .remove()    .erase()

i’ve tried them all but always it says nonexistent signal ???

(sorry if i waste your time you don’t have to answer)

Rayu | 2020-11-22 15:22

I am so sorry. This is my fault. I forgot something.
You need to connect from where you declared your signal.
You need to do something like:

$MainScript.connect("next_level", self, "on_nextlevel_")

func _on_next_level():
     queue_free()

You need to replace $MainScript with the path to the node that has MainScript attached.

ra45 | 2020-11-22 15:33

the structure is like this

RigidBody2D (Enemy Script)
-CollisonShape2D
-Enemy2sprite

what do you mean with the path of the MainScript?

Rayu | 2020-11-22 15:41

the main script needs to be attached to a node. What’s that node?

ra45 | 2020-11-22 15:43

simple Node2D

you mean like this

Enemy Script:

signal next_level

func _ready():
     emit_signal("next_level")

Main Script

func _on_player1_pressed():
	$Game.connect("next_level", self, "on_next_level")

func _on_next_level():
	 queue_free()

still doesn’t work

Rayu | 2020-11-22 17:36

Then you need to get that node. I think you could do get_tree().get_current_scene().connect("next_level", self, "on_nextlevel_")

ra45 | 2020-11-22 17:44

E 0:00:04.024 connect: In Object of type ‘Node2D’: Attempt to connect nonexistent signal ‘next_level’ to method ‘Node2D.on_next_level’.
<C++ Error> Condition “!signal_is_valid” is true. Returned: ERR_INVALID_PARAMETER
<C++ Source> core/object.cpp:1503 @ connect()
Game.gd:105 @ _on_player1_pressed()
Player1.gd:54 @ _on_Player1sprite_pressed()

:confused: should i just give up ?

it always say noneexistent signal. but i have made another signal the player_pressed signal it works fine, why not that one ?

Rayu | 2020-11-22 17:50

:confused: should i just give up ?

No. Definitely no.
Try connecting the signal from the editor.

ra45 | 2020-11-23 10:07

Thank you for your effort man.

i added my enemies to a Group and did this in the Main Script:

fun _on_player1_pressed():
	get_tree().call_group("Enemies1", "hide_for_time", 1)

and this in the Enemy Script

func hide_for_time(time):
	visible = false
	yield(get_tree().create_timer(time), "timeout")
	visible = true

Rayu | 2020-11-24 10:57