This site is currently in read-only mode during migration to a new platform.
You cannot post questions, answers or comments, as they would be lost during the migration otherwise.
0 votes

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.

Godot version latest
in Engine by (24 points)

1 Answer

+1 vote
Best answer

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

by (286 points)
selected by

Im using node3d

and also im trying to see visibility of something off screen

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

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?

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

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

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()

Now it seems to do nothing

maybe i need to write it into another function?

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.

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

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.

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")

I worded the other reply wrong

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

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

I have an enemy spawn timer and a game over timer

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

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()

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

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

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.

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

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()

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

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

This does not work,why?

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()

I've made a test project that I believe implements what you're looking for. Have a look at it here: https://we.tl/t-LyZV8Ac8a3

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

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.