Have python.sleep variate with computation time - python

For an animation project, we want to model a variable number of objects. This means that the computation and rendering part will take variable computation time. But we want the frame rate of the animation to remain constant. So we would like to compute how much time a section of code has taken, and if it is less then the expected frame rate, we wait the remainded before calculation the next frame.
Is there an easy way to do this?

One way to do it is by using the time library that has a method time that allows you to count how much time a section of code has taken to execute, an example down below.
import time
start_time = time.time()
#Your code here
end_time = time.time() - start_time
print(end_time)

You stopwatch the time, and sleep it for 1-x seconds.
sleep_time = 1/1 #Second number is frames per unit of time, first number is unit of time. In seconds.
from time import time #Important function: time(): Secs since unix epoch
while True: #Init animation
init_time = time() #Init stopwatch
#Code here Do your code
timer = time()-init_time #End stopwatch and remember time in a variable.
while time() < init_time+sleep_time-timer: pass #Wait ___ seconds
#Restart and go to next frame.
If the code that you coded in lasts longer than 'sleep time', than it will not wait.
Hope this helps, and good luck with animating!

Related

How can I write a loop to make the timer run every two seconds

I have a question on how I am able to set the timer so that every time it exits the loop it sets the time back to 2 seconds. The problem is that the first time the sound works after 2 seconds, the next times it is executed immediately. Thank you very much in advance for any advice.
This is my code:
time = 2
while time > 0:
timer = datetime.timedelta(seconds=time)
time -= 1
duration = 1000
freq = 440
winsound.Beep(freq, duration)
I am not sure if you meant that, but for me it seems like you just want to wait 2 seconds before executing the next steps. You can do that like so:
import time
while True:
time.sleep(2) # waits 2 seconds
winsound.Beep(440, 1000)
Anyways I don't recommend you to use a plain infinite loop, without a break statement. Therefore I recommend you to add one, like down below.
import time
while True:
time.sleep(2) # waits 2 seconds
winsound.Beep(440, 1000)
if True: # break on a specific statment
break
Edit: As CrazyChucky mentioned in the comments, this approach should work fine in most of the cases, but it can end up being more than two seconds sometimes. Therefore you should work with timedeltas or take a look at scheduler.
To be more accurate as possible use:
import time
timer = 0
step = 2
t0 = time.time()
while True:
timer = time.time() - t0
wait = step - timer
time.sleep(wait)
print(time.time())
winsound.Beep(freq, duration)
t0 = time.time()
This script take in count the execution time of script lines for your computer.
You just have to reinitialize the time at the end of the loop
time = 2
while True:
timer = datetime.timedelta(seconds=time)
time -= 1
duration = 1000
freq = 440
if time == 0:
time = 2
break
winsound.Beep(freq, duration)

How to make the threading be executed following a fequencey (say, every 3 sec) at a (relatively) accurate time considering function execution time?

I want to run a function every 3 second, and I do have searched similar topics. However, I didn't find any solution that can indeed meet my requirement, and the key issue is that in these solutions, they do not consider the time of executing the function itself. Consider the following code.
import datetime as dt
import time
import threading
def counting():
global num
time_now = dt.datetime.now()
if num > 0:
print(f'count: {num}, time now: {time_now}')
num -= 1
t = threading.Timer(3.0, counting)
t.start()
num = 5
counting()
This prints every 3.0 seconds. The main issue is that in a real case, in stead of print(f'count: {num}, time now: {time_now}') , I will call a function, say, func1(), which will take some time between 1 second and 2.5 seconds. Hence, the real interval time between two calls will be more than 3 seconds (about 4-5.5 seconds). How can I write it to be exactly (of course, very small error is allowed) every 3 seconds between two calls? Thanks!
The way to do it is to use a monotonic clock to find out the current time, and subtract that from the time at which you next want your scheduled function to be called; then you know exactly how long you'll need to sleep for, regardless of how long your func1() took to execute. Here's an example (I removed the threading since the logic is the same regardless of whether it's running in the main thread or some child thread):
import random
import time
def func1():
seconds_to_sleep = random.randrange(1000, 2500) / 1000.0
print("pretending to work for %f seconds" % seconds_to_sleep)
time.sleep(seconds_to_sleep)
def scheduled_function(scheduled_time, now):
if (now > scheduled_time):
print("scheduled_function was called %f seconds late" % (now-scheduled_time))
else:
print("scheduled_function was called %f seconds early" % (scheduled_time-now))
next_call_time = time.monotonic() # schedule the first call to happen right away
while True:
now = time.monotonic()
time_until_call_time = next_call_time-now
if (time_until_call_time > 0.0):
time.sleep(time_until_call_time) # wait until our next scheduled call-time
scheduled_function(next_call_time, time.monotonic())
func1() # sleep for some unpredictable amount of time to simulate a workload
next_call_time = next_call_time + 3.0 # each call should happen ~3 seconds after the previous call
The solution using the Ada programming language is very simple. Ada provides a "delay until" syntax allowing to delay until some future time.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Calendar.Formatting; use Ada.Calendar.Formatting;
procedure Main is
task periodic;
task body periodic is
Now : Time;
Future : Time;
The_Delay : constant duration := 3.0;
begin
for I in 1..10 loop
Now := Clock;
Put_Line("Periodic message at time " & Image(Now));
Future := Now + The_Delay;
delay 1.0;
delay until Future;
end loop;
end periodic;
begin
null;
end Main;
A recent execution of this program results in the following output (Time is the UTC time zone):
Periodic message at time 2021-05-27 02:26:46
Periodic message at time 2021-05-27 02:26:49
Periodic message at time 2021-05-27 02:26:52
Periodic message at time 2021-05-27 02:26:55
Periodic message at time 2021-05-27 02:26:58
Periodic message at time 2021-05-27 02:27:01
Periodic message at time 2021-05-27 02:27:04
Periodic message at time 2021-05-27 02:27:07
Periodic message at time 2021-05-27 02:27:10
Periodic message at time 2021-05-27 02:27:13
The variable The_Delay is a constant value indicating 3.0 seconds. The Now time is the time at the beginning of each iteration. The Future time is Now plus 3.0 seconds. The resulting time is not offset by the task execution as long as that execution does not exceed 3.0 seconds. In order to simulate a long task execution the task delays (sleeps) 1.0 seconds during each iteration. The "delay 1.0;" statement is an absolute delay while the "delay until Future;" statement is a relative delay.
I guess I got the answer myself. We need to use schedule module. See the examples in https://schedule.readthedocs.io/en/stable/examples.html
The following is my test code.
import datetime as dt
import time
import threading
import schedule
def job():
print("I'm running on thread %s" % threading.current_thread())
print(dt.datetime.now())
time.sleep(2)
def run_threaded(job_func):
job_thread = threading.Thread(target=job_func)
job_thread.start()
schedule.every(6).seconds.do(run_threaded, job)
schedule.every(6).seconds.do(run_threaded, job)
schedule.every(6).seconds.do(run_threaded, job)
t_end = dt.datetime.now() + dt.timedelta(seconds = 20)
while dt.datetime.now() < t_end:
schedule.run_pending()
You can see that I am letting it run for every 6 seconds (by applying three multithread parallel computing), and I do let it sleep for 2 seconds in the function job() to replace the real running time. And from the output result, you will see that it runs every 6 seconds instead of 8 seconds!

Python : Basic countdown timer & function() > int()

I'm trying to ucreate a timer function that runs in the background of my code and make it so I can use/check the time. What I mean by use/check, I'm trying to make it so I can call upon that timer function and use it as integer.
This is the code I currently have:
def timer():
for endtime in range(0, 15):
print(15 - endtime)
time.sleep(1)
def hall():
timer()
while (timer > 0):
do something
Currently only using print(15 - endtime) for confirmation it is counting down.
But what the code does now is execute the countdown and that's it, it never touches the while loop. And of course the last issue is I can't set a function to an int. So I'm looking for some way where I can check where the timer is at and use it in that while loop.
The way you do it, you'll going to have to use multithread.
Here is another, simpler approach :
On your script beginning, set a time_start variable with the number of seconds since the epoch using time.time()
Then when you need the number of elapsed seconds, use time.time() - time_start :
t_start = time.time()
# do whatever you'd like
t_current = int(time.time()-t_start) # this way you get the number of seconds elapsed since start.
You can put that in a function as well, defining t_start as a global variable.
import time
t_start = time.time()
def timer():
global t_start
print(str(int(time.time()-t_start)))
print('start')
time.sleep(2)
timer()
time.sleep(3)
timer()
import time
def timer(tim):
time.sleep(1)
print tim
def hall():
tim = 15
while (tim > 0):
print 'do something'
timer(tim)
tim-=1
Not the cleanest solution, but it will do what you need.
The problem with your code is that when you run hall(), Python first executes the whole of timer() (i.e. the whole for loop), and then moves on with the rest of the code (it can only do one thing at a time). Thus, by the time it reaches the while loop in hall(), timer is already 0.
So, you're going to have to do something about that timer so that it counts down once, and then it moves on to the do something part.
Something that you can do is this:
def hall():
for a in range(0, 15):
print(15 - a)
# do something
time.sleep(1)
This should work just fine (if you're only executing hall 15 times), and condenses your code to just one function.

Measuring user acting time in python

So I have a script where it measures how fast a person can press the keyboard 100 times. I have used the time module to set the start and the end of the measuring:
import time
import os
start = time.time()
pause() * 100 #defined the definition to os.system("pause")
end = time.time()
How do I make it so python can compare the elapsed time so if the time taken is >20seconds, it performs commands, and if it is equal or less than 20 seconds then preforms other commands?
You mean like this?
elapsed_time = end - start
if elapsed_time > 20:
# code
else:
# other code

What's the proper way to write a game loop in Python?

I'm trying to write a python game loop that hopefully takes into account FPS. What is the correct way to call the loop? Some of the possibilities I've considered are below. I'm trying not to use a library like pygame.
1.
while True:
mainLoop()
2.
def mainLoop():
# run some game code
time.sleep(Interval)
mainLoop()
3.
def mainLoop():
# run some game code
threading.timer(Interval, mainLoop).start()
4.
Use sched.scheduler?
If I understood correctly you want to base your game logic on a time delta.
Try getting a time delta between every frame and then have your objects move with respect to that time delta.
import time
while True:
# dt is the time delta in seconds (float).
currentTime = time.time()
dt = currentTime - lastFrameTime
lastFrameTime = currentTime
game_logic(dt)
def game_logic(dt):
# Where speed might be a vector. E.g speed.x = 1 means
# you will move by 1 unit per second on x's direction.
plane.position += speed * dt;
If you also want to limit your frames per second, an easy way would be sleeping the appropriate amount of time after every update.
FPS = 60
while True:
sleepTime = 1./FPS - (currentTime - lastFrameTime)
if sleepTime > 0:
time.sleep(sleepTime)
Be aware thought that this will only work if your hardware is more than fast enough for your game. For more information about game loops check this.
PS) Sorry for the Javaish variable names... Just took a break from some Java coding.

Categories

Resources