Why does the timer only start when the character is visible but when its not visible it doesn't stop?

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

So why doesn’t this work?

onready var Enemy = $George
func _ready():
if Enemy.visible == false:
	$Timer.stop()
elif Enemy.visible == true:
	$Timer.start()

The timer does start after the enemy is visible but after he disappears it doesn’t stop.

:bust_in_silhouette: Reply From: Ev1lbl0w

Visibility on screen is not the same as visibility on the node. If you want to test if an object has left the screen, use a VisibilityNotifier2D

Im using node3d

Skizi | 2022-09-05 18:07

and also im trying to see visibility of something off screen

Skizi | 2022-09-05 18:10

func _physics_process(delta):
if Enemy.is_visible_in_tree():
	$Timer.start()
if Enemy.is_visible_in_tree() != false:
	$Timer.stop()

This also works for the first time the enemy appears,but if i make him go away with hitscan the timer does not stop,but it stops before the enemy appears

Skizi | 2022-09-05 18:24

There’s also a 3D version: https://docs.godotengine.org/en/stable/classes/class_visibilitynotifier.html

Are you changing the visible property somewhere in code for the Enemy?

Ev1lbl0w | 2022-09-05 18:40

yes i am here is the code

extends KinematicBody
var health = 1

func _process(delta):
	if health <= 0:
		$CollisionShape.visible = false
		$Head.visible = false
		$Rarm.visible = false
		$Rarm/Rhand.visible = false
		$Larm.visible = false
		$Larm/Lhand.visible = false
		$Torso.visible = false
	if health >= 1:
		$CollisionShape.visible = true
		$Head.visible = true
		$Rarm.visible = true
		$Rarm/Rhand.visible = true
		$Larm.visible = true
		$Larm/Lhand.visible = true
		$Torso.visible = true

Skizi | 2022-09-05 18:41

also the visibilitynotifier doesn’t help me since i wanna change something thats not in view of the camera

Skizi | 2022-09-05 18:44

Enemy.is_visible_in_tree() != false will return the same value as Enemy.is_visible_in_tree(), so I think the code is repeatedly starting and stopping the timer. Also, $Timer.start() will always restart the timer when called multiple times in a _process/_physics_process function, so only start the timer if it’s not running. See if the following works:

func _physics_process(delta):
    if Enemy.is_visible_in_tree() and $Timer.is_stopped():
        $Timer.start()
    else:
        $Timer.stop()

Ev1lbl0w | 2022-09-05 19:01

Now it seems to do nothing

Skizi | 2022-09-05 19:10

maybe i need to write it into another function?

Skizi | 2022-09-05 19:19

Maybe you need to rethink how you’re implementing that functionality. What are you trying to implement? I can help you better if I understand what you’re trying to accomplish.

Ev1lbl0w | 2022-09-06 10:46

What im trying to accomplish is when the enemy is visible and you kill him,he disappears but after the timer runs out i want him to appear again in the same spot

Skizi | 2022-09-06 13:36

In that case, I’d set the Timer node with oneshot enabled, so it only fires once, and use the timeout signal to respawn the enemy. However, even if the enemy is not visible, it will still call _process/_physics_process, so you need to disable that as well:

extends KinematicBody
var health = 1

func _process(delta):
    if health <= 0:
        visible = false
        $Timer.start()
        set_process(false)

func _on_Timer_timeout():
    health = 100
    visible = true
    set_process(true)

Also there’s no need to set each object’s visible property individually like you’re doing. If the parent node is hidden, all it’s children will be hidden from the game.

Ev1lbl0w | 2022-09-07 10:10

What im trying is,if the enemy is visible for to long i want you to die so basically i want on timer timeout to change to the game over screen,and i want that timer to stop if he is not visible anymore

func _on_Timer_timeout():
get_tree().change_scene("res://Menu/Gameover.tscn")

Skizi | 2022-09-07 10:40

I worded the other reply wrong

Skizi | 2022-09-07 10:43

Create another Timer (I’ll call it GameOverTimer) for that and do something similar:

  • Start the GameOverTimeout timer when the enemy becomes visible (both when the scene starts, a.k.a _ready(), and when enemy respawns after dying).
  • Stop the GameOverTimeout when the player kills the enemy (stopping it won’t trigger the timeout signal)
  • Connect to the timeout signal of GameOverTimeout. When the signal is reached, run the code to change scene and do a game over

Ev1lbl0w | 2022-09-07 10:48

Well yeah thats what i already have but the timer does not stop when he dies, i tried

if Enemy.health >= 1:
$Timer.start()
else:
$Timer.stop
If Enemy.visible == true:
$Timer.start()
else:
$Timer.stop

Skizi | 2022-09-07 10:56

I have an enemy spawn timer and a game over timer

Skizi | 2022-09-07 10:57

But it doesn’t register that the timer has to stop when the enemy is not visible

Skizi | 2022-09-07 11:00

This is the Enemy spawn timer code:

export var num_enemy = 3
func _ready():
time_to_enemy = num_enemy
randomize()
$EnemySpawn.wait_time = rand_range (100, 200)


func _on_EnemySpawn_timeout():
Enemy.health = 1
time_to_enemy -= 1
	if time_to_enemy == 0:
	$EnemySpawn.stop()

Skizi | 2022-09-07 11:01

Where is this code running? Is it constantly running under a _process/_physics_process? Also the $Timer.stop has no parenthesis, it should be $Timer.stop()

if Enemy.health >= 1:
$Timer.start()
else:
$Timer.stop



If Enemy.visible == true:
$Timer.start()
else:
$Timer.stop

Ev1lbl0w | 2022-09-07 11:11

it was running under the _ready function,also i know the stop needed () but i wrote the code here since i deleted it from my original code cause it didn’t work

Skizi | 2022-09-07 11:16

If it was running under _ready, then it is only ran once and never again. If it runs in _process, then there might be an issue, because constantly calling $Timer.start() resets the timer back to the initial value, and thus it will never finish the countdown and emit timeout signals.

If you’re starting/stopping timers on the methods where you kill/respawn the enemy, that should be enough to make it work. If that’s the case, try removing/commenting this code.

Ev1lbl0w | 2022-09-07 11:23

The problem is it doesn’t listen to my starting/stopping timer code,maybe you could give me an example of how to do it since my method does not work

Skizi | 2022-09-07 11:26

Ok this seems to solve half of my issue:

   func _on_EnemySpawn_timeout():
    Enemy.health = 1
    time_to_enemy -= 1
        if time_to_enemy == 0:
        $EnemySpawn.stop()
    if Enemy.health == 1:
	$Timer.start()

Skizi | 2022-09-07 11:33

Now i need to stop it when the enemy is not visible

Skizi | 2022-09-07 11:34

func _physics_process(delta):
	if Enemy.health == 0:
		$Timer.stop()

This does not work,why?

Skizi | 2022-09-07 11:37

So i made a timer that is 0.05 seconds that always runs but now it seems that the game over timer doesn’t start again:

func _on_Timer2_timeout():
	if Enemy.visible == false:
		$Timer.stop()

Skizi | 2022-09-07 11:43

I’ve made a test project that I believe implements what you’re looking for. Have a look at it here: WeTransfer - Send Large Files & Share Photos Online - Up to 2GB Free

Ev1lbl0w | 2022-09-07 11:49

Do you have like a discord i want to give you the source code to my game to see what’s wrong,i don’t want it shared here

Skizi | 2022-09-07 11:53