How would a charge-up system be made?

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

Hi all.
I was poking around with timers, and figured out how to have a delayed output, but what I am looking for is a way to have something charge up when an input button (i.e. the “X” key) is held, and emit its output when it reaches 100%.

Sorry if any of you have a hard time understanding my question.

I know what I’m thinking of, but had a hard time trying to put it into words.

System_Error | 2019-01-11 20:32

:bust_in_silhouette: Reply From: markopolo

Not sure I understand what you want, but here’s something that might do it:

  1. Create a Timer node. One Shot yes, Autostart no.
  2. Wire up the timer’s timeout signal to whatever listener.
  3. When user presses the “x” key, start the timer.
  4. If the user lets go of the “x” key, stop the timer (and reset it if you want players to have to charge for the full duration all in one go instead of being able to incrementally charge it).
  5. When the timer times out, the signal will fire and the charge will be complete.

Is that sort of what you’re looking for?

This is what I’ve been looking for, yes. Thank you.

System_Error | 2019-01-11 21:45

Thinking… Would the block have something like this?

if Input.is_action_pressed('x'):
	$ChargeTime.start()
	yield($ChargeTime, "timeout")
	beam_fire()

Trying to figure it out. I know that the interrupt part would have $ChargeTime.stop() in it…

System_Error | 2019-01-11 23:01

I’d be more likely to use _unhandled_input rather than if Input.is_action_pressed in some _process function, since I think is_action_pressed returns true every time you ask as long as the button is being held down (instead of just once when it is initially pressed).

yield is also not the way to go here; that setup will return once for every time you call yield (!) once it finally times out. That could mean a lot more lasers than you intend :smiley:

I’m thinking of something like this:

func _ready():
  $ChargeTime.connect("timeout", self, "beam_fire")

func _unhandled_input(event):
  if event.is_action_pressed('charge') and $ChargeTime.is_stopped():
    $ChargeTime.start()
  elif event.is_action_pressed('charge') and $ChargeTime.paused:
    $ChargeTime.paused = false
  elif event.is_action_released('charge'):
    $ChargeTime.paused = true

Here’s the docs for Input Events that explains _unhandled_input and its alternatives.

(ignore this, see edit)
While I was writing this, I realized that the godot Timer actually resets every time you call start, so the above code won’t let the player incrementally charge up :frowning:

You can still achieve that functionality by adding a variable that keeps track of how much time remains and updating the timer with a new wait_time every time you start it, but at that rate it’s probably better to just ditch the Timer and keep track yourself with the delta from _process :\

EDIT: Whoops, I’m a fool. Timer has a paused field that you can totally use to pause and resume the timer. Updated the code above.

markopolo | 2019-01-12 02:03

Again, thanks. I’ll look through the docs for a bit, and I might use this in another thing I have planned for in the future.

System_Error | 2019-01-12 08:23