• Godot Help
  • why "wait for sec''' so difficult Is there any others options to delay a func?

To get a little more abstract, and answer your rhetorical question, it's difficult because godot is event-oriented. In event-oriented programming, everything you code should happen in response to an event -- no exceptions. The event may be a player input, an animation finishing (or hitting any particular frame), a timer expiring, an object collision, etc. Any time you feel the need to use a "sleep" or "delay" function, it should tell you that you're doing something wrong.

The reasons why this style of programming is useful are fairly complicated, so I won't try to explain them here, but if you work against the engine on this, it will tend to cause you problems.

I agree with @cybereality and @duane that you shouldn't be messing with yield/await if you're a beginner, and instead approach it in the way @DaveTheCoder suggested. That being said, making a coroutine that calls your function periodically may be an elegant way to do it because you see an explicit loop in your code, which is neat:

func call_consecutive(method: Callable, delay: float, number_of_calls: int) -> void:
	while number_of_calls:
		method.call()
		await get_tree().create_timer(delay).timeout
		number_of_calls -= 1
		
func _ready():
	var move_to_next_position = func():
		print("MOVING TO NEXT POSITION")
	
	call_deferred( "call_consecutive", move_to_next_position, .5, 10 )

It could be particularly useful if you want to do something in irregular intervals, or need to check for some conditions in-between the calls:

var some_condition = false

func call_consecutive(method: Callable, delays: Array) -> void:
	for delay in [0] + delays:
		await get_tree().create_timer(delay).timeout
		method.call()
		if some_condition:
			break
		
func _ready():
	var do_the_thing = func():
		print("DOING THE THING")

	call_deferred( "call_consecutive", do_the_thing, [.5, 1.0, .3])

thanks guys for responses its sooo difficult I will better use cell pattern then coroutines

    Serhy i'm not fond of pre-baked timers in godot. they can be a bit unwieldy on logic.

    What I do is create a manual timer out of frames and use a simple bool logic to stop it. This is also useful as we can get increments slightly faster than a half second. The math isn't as clean as the seconds-based Godot timer but it moves by frame so it's smooth. Surely a "brute force" solution but it works for me.

    So something like:

    const var _timerRefill = 100 ## your max value here
    export var _timerValue : int = 100 ## export total value to editor
    export var _timerRate : float = 0.5 ## export rate of total drain
    var _isRunning = false ## bool logic to begin
    
    
    func _process(_delta):
            if _timerValue > 0: ## if it's running, drain the timer
                if _isRunning:
                     _timerValue-=_timerRate
            else:
                _isRunning = false ## flip the bool off and reset when done
                _timerValue = _timerRefill
                ## do something
    ~~~~

    It's not really that difficult. You just have to think in terms of events. Here is one way you can do it.

    var timer = Timer.new()
    timer.wait_time = 3.0
    timer.connect("timeout", self, "some_function") 
    add_child(timer)
    timer.start()

    After 3 seconds, some_function() is called.

    so there is some step by step move. scratched by our solution and thankful to a tutorial published on youtube . following code is
    this line modification was crucuel. an extra boolean check
    if singl_UprightleftButton1.moveIfClickedUP_B1 && Continue_process_on_timerEnd_B2 && itteratQuantity_index!=4:

    extends KinematicBody2D
    
    var currentPos= self.position	
    
    var itteratQuantity_index= 0
    
    var Continue_process_on_timerEnd_B2= true
    var delayTimeFor_int= 3
    var timer= null
    
    func _ready():
    	timer = get_node("Timer")
    
    	timer.start()
    	
    func _process(delta):
    	
    	if singl_UprightleftButton1.moveIfClickedUP_B1 && Continue_process_on_timerEnd_B2 && itteratQuantity_index!=4:
    			
    #		print(itteratQuantity_index)
    		var charr= singl_PathsDictionary.randomUP.get_slice('/',itteratQuantity_index)
    		print(charr)
    		if charr=='U':
    #			print('ifU')
    			currentPos[1] -=singl_PathsDictionary.distanceToMove_const
    
    			Continue_process_on_timerEnd_B2= false
    
    		elif charr=='R':
    #			print('ifR')
    			currentPos[0] +=singl_PathsDictionary.distanceToMove_const
    		elif charr=='L':
    #			print('ifL')
    			currentPos[0] -=singl_PathsDictionary.distanceToMove_const
    #		print(singl_PathsDictionary.distanceToMove_const)
    
    		self.position= Vector2(currentPos[0],currentPos[1])
    
    		print('index',itteratQuantity_index)
    		itteratQuantity_index += 1
    
    		if	itteratQuantity_index== 4:
    			singl_UprightleftButton1.moveIfClickedUP_B1= false
    			itteratQuantity_index= 0 

    there was a problem i coudn't start timer from "process func" So i forced to start it in "ready func"

    • xyz replied to this.
      4 days later

      unfortunally cause of little bit lags that slows move of the character i had to change code (maybe too much singletons and slices) Forced to Add more "$Timer"s in "_process" The code become unhandly and again tooo difficult. So i'm transiting to position = position.move_toward(Vector2(0,0), delta * speed) and "float distance_to ( Vector2 to )" pattern

      Serhy The code you posted looks... well... overcomplicated. It also uses strange naming conventions making things look even more confusing. To get a proper solution it'd be best to describe what exactly are you're trying to achieve. I'm sensing this could be yet another case of the infamous xy problem.

        xyz with that code above Character is moving. but its moving too slowly. no matter what time delay im setting...

        • xyz replied to this.

          Serhy You've got the answer to your initial question. Apparently it did not solve your actual problem because you didn't identify that problem correctly. So to save everyone's time, it'd be best to describe the exact behavior you want to implement. That way it'd be much easier for people to suggest how to do it.

            xyz i'm appreciate your attention. Actually now im just posting for my self and maybe for some random traveler who went on the same path like mine. "Behavior" of the character shoud do: after one click on button, should move in already created custom path ( L T 2) from angle to angle/ step by step. without user finger help holding a key on keyboard.

            • xyz replied to this.

              Serhy should move in already created custom path ( L T 2) from angle to angle/ step by step. without user finger help holding a key on keyboard.

              This is still stated too vaguely. In coding, problems should be defined and communicated as accurately as possible. How is this path defined? By a list of point coordinates? If so, are points equidistant? Is transition from point to point (a step) instantaneous or gradually animated? Is there an additional pause between transitions? Does this movement sequence needs to be interruptible? What's L T 2? Etc... People on forums don't see your screen and cannot read your mind. You need to write everything down.

              Going by your last (imprecise) description, the easiest way to do this would be to just fire a bunch of consecutive tweens. The advantage is that it will work in fire-and-forget manner. You can setup everything at once when mouse is pressed and let the engine's tweening system take care of the timing.

                xyz i'm bitting my lip ( reading this reply 😉
                yes "tweens" I just saw it in a template And was going to try ...

                • xyz replied to this.

                  Serhy Here's how to do it with tweens:

                  extends Node2D
                  
                  var points = [ Vector2(100,100), Vector2(200, 200), Vector2(200, 100) ] # add more points
                  
                  var movement_speed = 500.0
                  var delay = .2
                  
                  func _input(event):
                  	if event is InputEventMouseButton and event.is_pressed():
                  		var t: Tween = get_tree().create_tween()
                  		var p_prev = position # previous position for calculating movement time
                  		for p in points: 
                  			var movement_time = p_prev.distance_to(p) / movement_speed
                  			t.tween_property(self, "position", p, movement_time)
                  			t.tween_interval(delay)
                  			p_prev = p
                  9 months later

                  await get_tree().create_timer(1).timeout

                  as simple as it gets