Time between consecutive executions of a single function in Python - python

Apologies if the question is a little vague, I'll edit it if necessary.
I'm creating a chess game in Python with Tkinter and want to add a chess timer.
When a player moves a piece the move() function is called, causing the piece to be moved to the correct square and the turn switches (from black to white and vice-versa) - turn is a list ["W", "B"] that keeps track of whose turn it is.
Called when a player selects a square to move to:
def move():
#code here
turn.reverse()
To time each move, I want to measure the time between consecutive execution of the move() function (i.e. time between turn switches).
To summarise:
How can I measure the time between consecutive executions of the same function?
Edit
From the answers I can see that my question was misunderstood, I'm sorry for not clarifying:
I'm not looking to measure the time it takes to execute a function (the move() function).
I am looking to measure the time between consecutive executions of a function. The answers given here assume I only want to measure the execution time of the function from start to end. You cannot assume that the move() function executes again immediately after it has finished; it is called by clicking a button so there may be a delay (thinking about the move) before the move() function is called again.
Any help would be greatly appreciated.

You can use time module of python. If i understood your question properly, Something like this can be done:
import time
initial_time = time.monotonic()
def move():
#code here
time_gap = time.monotonic() - initial_time
print(time_gap)
initial_time = time.monotonic()
turn.reverse()

Related

Python: implement a "software-wide" setting that does not change often without running an if statement in every loop

I want Python to kind of ignore a statement that is unlikely to be called in a function that is often called.
I do not have a formal education in programming, so please excuse my lackluster ability to desribe things. I will try to explain the concept by example.
Say I am writing a video game, first-person shooter, drawing 60 frames per second.
In the settings menu, the user can select whether or not to display the name of other players above their head. If they disable this, I store this value as showplayernames = False.
Then in my drawing function that outputs the graphics I have:
def draw():
#code that draws the graphics on screen
if showplayernames:
#code that draws the name of players on screen
I call this function 60 times a second, but there is absolutely no point for checking if showplayernames is True 60 times a second. It will not change that often, in fact I could make this a kind of "constant" during play by preventing it to change. If showplayernames is False, then the third and fourth lines of the code are completely redundant, but they are executed nevertheless. The computer isn't smart enough to know it can ignore it, and there is a performance difference: reading a value and then checking if it is false takes time.
I could write two copies of the game (or at least the draw() function), one with only the first two lines when the user selects not to show names in the settings, and another without the if statement, and then run the appropriate one.
def draw_with_names():
#code that draws the graphics on screen
#code that draws the name of players on screen
def draw_without_names():
#code that draws the graphics on screen
Although looping through either of these 60 times a second is more efficient than running draw() ,this is obviously not the way to go. There are dozens of settings like this.
So how do software and game designers implement these kind of "software-wide" settings efficiently?
I'm not a game developer, but here's one option. Create a list of function pointers and add or remove from the list based on settings. Example:
def draw_player_names():
# Code to overlay names
def draw_fps():
# Code to overlay fps
def draw():
# Main code to draw a frame of the game
# Hold all the functions to call
optional_funcs = []
if showplayernames: optional_funcs.append(draw_player_names)
if show_fps: optional_funcs.append(draw_fps)
# Main game loop
while True:
draw()
for f in optional_funcs: f()
This can be extended for any number of functions/options.
not an game designer, but here is my voice.
You could store settings inside json file next to you python, but then you need to cover reading, getting right values etc.
You could use Environment variables to store value but that would end up using still "if" in the code.
Game designers use triggers and events to get things done, and on the lowest level I would assume those things also use if's.
system-wide-settings will in the end be used with if's
You could use overwrites based on event/trigger and use "same" draw function in both times but that only complicates code, and we all know to "keep it simple".
Sorry if this is not the answer you were looking for.
As Matthias said, you shouldn't really bother about this kind of optimization. Look at these two very silly functions:
def lot_of_ifs(settings):
#do something
a=2**10
b=2**10
c=2**10
for setting in settings:
if setting:
#do something more
a=2**10
b=2**10
c=2**10
def no_ifs():
#do something
a=2**10
b=2**10
c=2**10
timeit("lot_of_ifs([0,0,0,0,0])", globals=globals())
0.2630380000000514
timeit("no_ifs()", globals=globals())
0.10232830000040849
The cost of creating a list, looping over it, and executing five ifs is about 0.16 seconds for one million iterations, or 160 nanoseconds per iteration, while at 60 fps you have 16.6 million nanoseconds to execute your code.

how to sleep in one function without sleeping the whole program

So I am trying to make a game, in this game I call upon a function that I want to slowly execute, but when I use "time.sleep(x)" it pauses everything in the file instead of just pausing the process of the function. I am trying to add a jump feature to a 2-d game, so if there is a better way to do it then I would be grateful for any advice but this is just the first idea that game to me.
for n in range(15):
Dino.rect.bottom -= 5
update_screen(Dino, screen, cactus)
time.sleep(0.01)
time.sleep(0.25)
inair = False
for n in range(15):
Dino.rect.bottom += 5
update_screen(Dino, screen, cactus)
time.sleep(0.01)
so I have it so that when I jump, it gives me a slow jump instead of just teleporting but like I said, it pauses everything while jumping.
This is not a good approach to timing. As you say, this sleeps the entire program. Multi-threading is a bit complex for simply moving a sprite.
A simple way to solve this problem is to use the PyGame function time.get_ticks() which returns an ever-increasing time in milliseconds.
Using this time-stamp, record the previous-time of an operation, but then do not update again until enough time has elapsed.
For example:
DINO_UPDATE_DELAY = 100 # milliseconds
next_dino_update = 0 # time next move due
[...]
# Move dino, if necessary
time_now = pygame.time.get_ticks()
if ( time_now > next_dino_update ):
Dino.rect.bottom += 5
next_dino_update = time_now + DINO_UPDATE_DELAY # in the future
# Paint the dino, wherever it is
update_screen(Dino, screen, cactus)
It's also possible to request a timer to send the event-loop a message in the future.
MOVE_DINO_EVENT = pygame.USEREVENT + 1
[...]
pygame.time.set_timer( MOVE_DINO_EVENT, DINO_UPDATE_DELAY )
EDIT: More in-depth explanation.
So basically you're implementing an animation, like an anime/cartoon. The thing on the display moves at some speed. In the above code, you seem to be moving a "dino" in the direction of y + 5 every 0.01 seconds (10 milliseconds).
Right now, you paint the dino, then sleep(), then move & paint again. When it hits the apogee of the jump, you wait 250 milliseconds, then repeat the previous phase for the down-jump.
So the problem with using sleep() is that it holds up the whole program (including the event loop, which can cause bad stuff to happen).
So instead of sleeping for some time period, the above example simply looks at the PyGame clock to determine if that same time-period has past. This allows the program to know if the animation needs to be updated.
The whole idea is to keep looking at the clock, using the time as the arbiter of what/where to draw next, rather than multiple calls to sleep().

What is the best way to make a player move at every interval in pygame?

Is there a library or a simple way to only loop something every 0.5 seconds without interrupting the rest of the program?
I have just started using pygame and have made a simple platformer and a Pong replica so far. I decided to try and make a Snake replica (I only currently have the head) and I need the snake to only move every 0.5 seconds while inputs can be registered at the 30 fps which I have the rest of the game running at. This is my current workaround:
while running: #this is tabbed back in my code
# keep loop running at the right speed
clock.tick(FPS)
# get time at each iteration
currentTime = str(time.time()).split(".")[0]
gameTime = int (currentTime) - int (startTime)
# this is used to check for something every 0.5 second (500 ms)
currentTimeMs = str(time.time()).split(".")[1]
# snake will move evry 0.5 second in a direction
if currentTimeMs[0] in ["5","0"] and moveDone == False:
moveDone = True
player1.move(direction)
elif currentTimeMs[0] not in ["5","0"]:
moveDone = False
There is more code within the while running: loop to get the direction and display the sprites but its not necessary for this. My current code works fine and will repeat the move function for my player1 every time that x in mm:ss:x is 0 or 5 (0.5 seconds apart) and will not repeat if it is that multiple times over a few frames.
This code needs to work within the running loop and not stop the program so time.sleep() doesn't work. I have also tried using the schedule library but it will not work as it cannot seem to allow the direction variable to change when passing it into the function.
My question therefore is; Is there a library or a shorter way to accomplish what I need?
Thanks in advance and I can message you the whole code if you need.
I suggest using pygames event mechanics and pygame.time.set_timer() (see here for docs).
You would do something like this:
pygame.time.set_timer(pygame.USEREVENT, 500)
and in the event loop look for the event type.
if event.type == pygame.USEREVENT:
If this is the only user defined event that you are using in your program you can just use USEREVENT.
When you detect the event the timer has expired and you move your snake or whatever. A new timer can be set for another 1/2 second. If you need more accuracy you can keep tabs on the time and set the timer for the right amount of time, but for you situation just setting it for 1/2 sec each time is okay.
If you need multiple timers going and need to tell them apart, you can create an event with an attribute that you can set to different values to track them. Something like this (though I have not run this particular code snippet, so there could be a typo):
my_event = pygame.event.Event(pygame.USEREVENT, {"tracker": something})
pygame.time.set_timer(my_event , 500)
You can store the moment of last move and then compare to actual time. To do it you can use perf_counter from time. Here is an example
last_move_time = perf_counter()
while running:
if perf_counter() - last_move_time > 0.5:
# move player
last_move_time = perf_counter()

ball animation is really junky while running pong game

the ball animation while running the program is very stuttery and i can't figure out why.
this is just the beggining of the program so ignore the fact that the game isn't ready to play yet.
this is the code: https://www.codepile.net/pile/dqKZa8OG
i want the ball to move smoothly without stuttering.
and in addition how do i make it so the program deletes the last location of the ball after each update?
It's not "junky" because of the timer, you can only see updates since you're probably moving the mouse in the meantime, then you're updating the ball position everytime you move it (which is wrong, as you're updating the position anytime any events is processed).
The problem is that you're using Clock in the wrong way: the pygame.time.Clock class creates an «object that can be used to track an amount of time», meaning that it is not a timer that can "react" once it times out. The tick method you're calling only updates the current Clock returning how many milliseconds have passed since the last call to tick itself, based on the fps argument you are providing.
What you need is to set a timer, possibly by using a specific eventid just for the updates. Also, since you're updating the ball position based on the events, you'll get more movements if you move the mouse (or any other event is called) making the ball move faster even if it shouldn't - and that's what you'll need the Clock object for.
# I'm using a smaller speed, otherwise it'll be too fast; it should
# depend on the window size to ensure that bigger windows don't get
# slower speeds
ball_velocity = .2
fps = 60
UPDATEEVENT = 24
[...]
def start_move_ball(angle):
ticks = clock.tick()
speed = ball_velocity * ticks
# "global ball" is not required, as you are assigning values to an
# existing object, not declaring it everytime.
# You can also use in-place operations to set the speeds, which is
# better for readability too.
ball[0] += angle[0] * speed
ball[1] += angle[1] * speed
def main_loop():
angle = choose_angle()
pygame.time.set_timer(UPDATEEVENT, 1000 // fps)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return False
# update only if necessary!
elif event.type == UPDATEEVENT:
window.fill((0,0,0))
start_move_ball(angle)
draw_mid(window)
draw_players(window)
draw_ball(window)
pygame.display.flip()
The timer is set outside the while cycle, as it automatically sends the event each time interval. You could also leave it within the while (the once=True argument is not really required in this case, as it automatically updates the timer based on the same eventid), but wouldn't make much sense, since set_timer always fires the event after the first time it's set.
I'm using 24 (pygame.USEREVENT) as an eventid, but you can set its id up to pygame.NUMEVENTS - 1, as suggested in the event documentation. If for any reason you want to stop the timer, just use pygame.time.set_timer(eventid, 0) and the timer for that eventid (24 in this case) will not be fired up again.
A couple of suggestions, besides all:
Remove the pygame.display.update() line in draw_mid(window), since it causes flickering while painting.
Avoid using external services to link code (it's not your case, but if the code is too long, first try to reduce it to minimal, reproducible example, eventually leaving all the relevant parts), as they could become unavailable sometime in the future, making your question hard to understand to somebody that is facing a similar issue and reads your answer some time after you posted it.

Python: Sleep methods

I know this is already technically "asked" on this forums but this question is based around a different concept that I couldn't find.
While using time.sleep(whatever) it obviously sleeps, I get that but while using Pygame it will lock up the program. Is there any real method of using a sleep or a pause in the code other than an input that doesn't lock up pygame? I've tried;
time.sleep
pygame.wait and
pygame.delay
these all do the exact same thing. I'm working on a game for a Computer Science class that involves a small animation of 13 photos I have that are slightly different, but when played 0.12seconds apart, it makes it look good, sadly the whole freezing up of the window from wait statements makes it skip and look very bad.
Thanks to whoever can figure out this mystery.
I think you may want to try using the method that is shown here.
an example of what I mean is this:
class Unit():
def __init__(self):
self.last = pygame.time.get_ticks()
self.cooldown = 300
def fire(self):
# fire gun, only if cooldown has been 0.3 seconds since last
now = pygame.time.get_ticks()
if now - self.last >= self.cooldown:
self.last = now
spawn_bullet()
notice he uses pygame.time.get_ticks() to check if a variable is less than that and if it is, he passes in the if statement and spawns the bullet.
a simpler way to view this concept is the following
curtime = pygame.time.get_ticks() + 10 # the 10 is what we add to make it sleep
while True: # Create a loop that checks its value each step
if curtime < pygame.time.get_ticks(): # check if curtime is less than get_ticks()
print("Sleep is over now!")
break # exit the loop
I hope that helps you in any way, it seems like it might be a viable option since it keeps freezing when you use normal functions.
ONE MORE THING
do note that pygame.time.get_ticks() will give you the current time in milliseconds, for full documentation on this go here.

Categories