Python Game Timer (Threads?)

2019-08-14 05:47发布

问题:

I am designing a game in Python and would like to know how to make an efficient timer that can run along side my game.

Note: I am using Pygame.

I currently have a timer like so:

import time

seconds = 60

def start_timer():
    global seconds
    while seconds > 0:
        print seconds
        seconds -= 1
        time.sleep(1)

However, when run in my main game function my game hangs because of the timer.sleep.

def main(self):
    Timer.start_timer()

I'm pretty sure my issue has something to do with not using threading, although I'm not 100% sure. Can somebody help explain to me what the proper solution is?

回答1:

If you're using PyGame, it has its own time functionality that you should be using.

If you're using an event-loop or hybrid design, where you loop over pygame.event.get() or similar and call "event handlers" for different events like mouse-click or key-down, you can use set_timer to create an event that fires every second. For example:

TIMER1_EVENT = pygame.USEREVENT + 1

def start_timer1():
    global seconds
    seconds = 60
    pygame.time.set_timer(TIMER1_EVENT, 1000)

def on_timer1():
    global seconds
    print seconds
    seconds -= 1
    if seconds < 0:
        pygame.time.set_timer(TIMER1_EVENT, 0)

# elsewhere, inside your main event loop
elif event.type == TIMER1_EVENT:
    on_timer1()

There are very simple example programs linked in the docs for each function; if you look at the examples for set_timer you'll see how easy it is to use.

If you're using a pure frame loop instead, you're presumably already calling Clock.tick or similar, and you're going to have to use the return value from that to count down milliseconds since the last time and decide whether you've passed another integral number of seconds and when you're passed 0.



回答2:

If you're using PyGame, or some other graphical library, and have built your game around an event loop or frame-rate loop, you want to use the functions that come with that library. If you're got an event loop, you can ask it to schedule an event to fire in 60 seconds. If you're got a frame-rate loop, you may be able to do the same thing, or need to check the remaining time once/frame.

But if you're not doing that, then yes, threading is the answer.

For simple timers, the simplest solution is the Timer class. However, this doesn't automatically do repeating timers, so you have to add that manually. For example, you can start a 1-second timer, and have it start another 1-second timer when it expires:

def start_timer():
    global seconds
    if seconds > 0:
        print seconds
        seconds -= 1
        threading.Timer(1, start_timer).start()

seconds = 60
threading.Timer(1, start_timer).start()

However, it's usually a lot easier to use a timer that knows how to do repeats for you. You can build one yourself (notice that the threading docs contain a link to the source, and it's not hard to figure out how to add logic that makes it fire every interval seconds for count times, instead of just once). Or you can go search PyPI and find dozens of people who've already implemented that for you.

Also keep in mind that once you use threads, you have to deal with threading issues. If you're using a GUI library, they often won't let you call GUI methods from a background thread. If you're accessing a variable that's shared between two threads, you often need a Lock or other synchronization object to protect it. And so on.