Call an action only once in _process()

Godot Version

4.1.1 but it doesn’t really matter which version it is

Question

For example, I want to play a sound when a specific variable is true:

func _process():
    if variable:
        $Audio.play()

This would start the sound on every frame which is not what I want. I could create a second variable and make it true on just one frame and only play the sound then, but that’s so inconvenient and probably really bad code :confused:

That I want to play a sound is just an example, I need this in almost every project, HOW DO I DO IT :sob:

1 Like
func _process():
    if variable:
        $Audio.play()
        variable = false

Usually this is somewhat akin to a state machine. I would try to leverage an animation system, or a signal that happens during the event to call the play function.

So basically if the value is set true somewhere, just remove the Boolean = true and just play the audio then.

2 Likes

Hmmm, but what if ‘variable’ has to stay true because it’s used in other functions and all? :thinking:

Sure, it really depends. I don’t think there is anything wrong with your approach. What ever method, your mission is to not play it every frame.

Let’s say this is a treasure chest and you want to transition to an open state. Once open some process is done. “variable” is your open state.

With a state machine you can define a closed and open state. When an action to open happens you would play the sound and transition to open state. I would tuck the play sound into the animation or the action sensor to transition.

This situation can usually be solved with a finite state machine. And there are multiple forms of it. Godot has a built in state machine hidden in the AnimationTree node.

Here is a video i like showing how to use it.

1 Like

If you wanted to play the full sound instead of restarting it every frame, you could do

func _process():
	if variable:
		if !$Audio.playing:
			$Audio.play()

This would effectively put the sound on loop as long as the variable is true though, not sure if that’s what you want.

1 Like

Hm ok so there’s not really one way to only trigger things once in _process()…

Thank you for the tips and the very kind help!
(also sorry for the late reply)

Yes, if we want to keep it simple, and you used variable for other things, you just need to add another Boolean that is set to false once it’s been set to true by some event. I like to call it a “latching” mechanism.

func _process():
    if variable:
      ...
        If variable_play:
           $Audio.play()
           variable_play = false # latch it
      ...

As you might notice this could get convoluted if you keep using this pattern. Finite state machines try to simplify this. This pattern above could be called a decision tree, which is actually the basis for basic AI.

I see!

I got a good example now: For lerp_angle() to work I need it to be only called once, right?
So that’s the problem: How do I do that?

func _process(delta):
	if Global.picked_up == true:
		lerp_angle(global_rotation_degrees.x, 0, 0.5 * delta)
		lerp_angle(global_rotation_degrees.y, 0, 0.5 * delta)
		lerp_angle(global_rotation_degrees.z, 0, 0.5 * delta)
var is_picked: Boolean = False
func _process(delta):
    if Global.picked_up == true:
      if not is_picked:
        is_picked = True
        lerp_angle(global_rotation_degrees.x, 0, 0.5 * delta)
        lerp_angle(global_rotation_degrees.y, 0, 0.5 * delta)
        lerp_angle(global_rotation_degrees.z, 0, 0.5 * delta)
1 Like

Others method will be to use signal. You subscribe on ready and unsuscribe after use. With this is even possible for skip process part

1 Like