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

Hi Im trying to delay next func from execution But for this moment i have so many issue with that

onready var timer= get_node("Timer")
func _ready():
	timer=Timer.new()
	timer.set_wait_time(3)
	add_child(timer)
if charr=='U':
				print('ifU')
				currentPos[1] -=singl_PathsDictionary.distanceToMove_const
				timer.start()
				while timer.time_left > 1:
					print('nothing')

first i tryied to use is_stopped() method
timer.is but it doesn''t even apear in editor

this stazis using while is looping and crashes editor

Doing that in _ready() usually makes no sense.

Explain the purpose of your code. What are you trying to do?

    DaveTheCoder > Im trying to delay next func from execution

    something like yield(wait(2),"completed");
    so character will not immediatly jump to end of path It should pass step by step with delay in few seconds

    Okay, so you want to move a character along a path in steps, with a time delay between the steps.

    What kind of node is the character? For example, is it a KinematicBody2D?

    Don't do the movement in _ready(). Start the Timer in _ready(). Connect the Timer node's timeout signal to a function, such as _on_timeout(), and do the movement there.

    The simplest is sceneTreeTimer:

    https://docs.godotengine.org/en/stable/classes/class_scenetreetimer.html

    However I don't use it because it's not part your scene and might cause issues. Better to create a Timer, and then "await timer.timeout" (edit: and usually better to put code in the timer callback, than using await, await is more for some situations usually where you are awaiting a special signal). If you build the Timer into your scene with the editor and make a unique name, that will simplify it much more than doing it with code.

    TBH Godot should have a time argument to call_deferred() , that would simplify a lot

    You would use Timers. Don't use Yield, it doesn't do what you think.

    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