You would use Timers. Don't use Yield, it doesn't do what you think.
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.
- Edited
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
- Edited
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"
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.
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.
- Edited
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.
- Edited
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
await get_tree().create_timer(1).timeout
as simple as it gets