godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Include a method to stop a SceneTreeTimer #8577

Open securas opened 11 months ago

securas commented 11 months ago

Describe the project you are working on

SceneTreeTimers can be generated but there is no mechanism to stop them. If it is necessary to interrupt the timer for any particular reason one must wait for the timer to finish or introduce some mechanism on methods triggered by the timeout signal that they should not run anymore. This is a problem when trying to re-use resources that have SceneTreeTimers since there is no way to stop those timers when the resource is not in use.

A PR has been made with a possible implementation of this proposal: https://github.com/godotengine/godot/pull/85662

Describe the problem or limitation you are having in your project

As described above, being unable to safely stop SceneTreeTimers, prevents their use in reusable resources. This is important for console games, where reusing nodes is a major way to overcome the console limitations. It is also important for the sake of consistency. Tree-generated tweens can be stopped so it should come naturally that tree-generated timers should also be stoppable.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Include a method in the SceneTreeTimer to stop the timer.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Referring to https://github.com/godotengine/godot/pull/85662

If this enhancement will not be used often, can it be worked around with a few lines of script?

There is little to no control of SceneTreeTimers. Of course, there are ways to avoid the impact of not stopping a timer. But this change would greatly simplify their use when not following the "await" use case.

Is there a reason why this should be core and not an add-on in the asset library?

I'm not entirely sure that SceneTreeTimers can be controlled by a plugin.

yoont4 commented 4 months ago

I saw in the PR that they wanted more discussion in the proposal to see if this is needed.

I highly agree with this being a necessary parity feature. SceneTreeTimer, as I understand, is a very lightweight way of instantiating timers, as opposed to creating a node object for each one. I understand those are still lightweight, but not as much so, and still involve modifying the scene tree.

A common case is I simply want to trigger some staggered logic (menu transitions, cutscene logic, etc.), but I don't want to create and destroy timer nodes for each step. I also want the ability to kill the timers and skip to the final result, say if a player clicks the skip button.

As of now, I create tweens like so to act as a "timer":

func cool_func():
  var tween_timer = create_tween()
  timers.append(tween_timer)
  tween_timer.finished.connect(func(): 
    print('some delayed action')
  )

func kill_timers():
  for tween in tween_timers: 
    tween.kill()
  tween_timers.clear()

Which feels super unintuitive, but so does creating and queue_free()ing Timer nodes

ahrastnik commented 3 months ago

Here's a concrete example: I have a drone that has a self-destruct state. When entering mentioned state, a SceneTreeTimer is created, which when expired, calls the method to detonate the drone. However, if the state is changed, the detonation, of course, mustn't happen. This is where the proposed stop() method would apply.

AFAIK, the SceneTreeTimer is meant as a "set and forget" type of one-time thing. I've been in dozens of situations as above one so far, requiring a way of stopping it - there were/are more cases requiring an option to stop it than not. Therefore, implementing this would be a no-brainer from my perspective.