0

I have a game that I've written for my first project and I'd like to have a system where I can play and pause the game. When you click the unpause button, I want it to call a function every 1 second that advances the date. Time.sleep stops the whole program so it's not useful to me and I cant seem to restart threads after I've started one. Here's the advancing day function.

def time():
    global timer
    timer = threading.Timer(1.0, time)
    timer.start()
    thirtyonemonths = [1, 3, 5, 7, 8, 10, 12]
    thirtymonths = [4, 6, 9, 11]
    globalvars.day = globalvars.day + 1
    for self in thirtyonemonths:
        if self == globalvars.month:
            print "hi"
            if globalvars.day == 32:
                globalvars.day = 1
                globalvars.month = globalvars.month + 1
    for self in thirtymonths:
        if self == globalvars.month:
            print "hi"
            if globalvars.day == 31:
                globalvars.day = 1
                globalvars.month = globalvars.month + 1
    if globalvars.month == 2:
        print "hi"
        if globalvars.day == 29:
            globalvars.day = 1
            globalvars.month = globalvars.month + 1
    if globalvars.month == 13:
        globalvars.month = 1
        globalvars.year = globalvars.year + 1
    threading.Thread.time(self)
timer = threading.Timer(1.0, time)

Later I have the code for when the button is clicked that checks if it's paused or not

if b.collidepoint(pos):
    if globalvars.ispaused == 1:
        globalvars.ispaused = 0
        timer.start()
        break
    if globalvars.ispaused == 0:
        globalvars.ispaused = 1
        timer.cancel()
        break

Everything works perfectly up until I press the button a third time. Does anyone know a way I can restart the thread or maybe use a different method to do what I want?

Taegis
  • 3
  • 2
  • @Apero: He _is_ using threading. That's what `threading.Timer` is. – abarnert Oct 28 '14 at 19:09
  • http://stackoverflow.com/questions/8600161/executing-periodic-actions-in-python – DevLounge Oct 28 '14 at 19:11
  • Also have a look to this: https://docs.python.org/2/library/sched.html – DevLounge Oct 28 '14 at 19:12
  • Please try to rewrite this as a [minimal, complete, valid example](http://stackoverflow.com/help/mcve). The way you're doing the GUI is probably relevant here. If it's not, try to reproduce the problem without any GUI stuff, and it'll be even easier for someone to solve. – abarnert Oct 28 '14 at 19:14

2 Answers2

0

Without seeing the rest of your code, it's hard to be sure where the problem is, but my guess would be that sometimes, when you click the button, ispaused is 1, but timer is an expired timer rather than a paused one. Calling start on an expired timer has no effect.

While that could be fixed, there are easier ways to do this.

For one thing, it looks like you're using some kind of GUI or game framework here. I have no idea which one you're using, but pretty much every one of them has a function to do timers (in the main event loop, as opposed to in a separate thread, but that's not the key thing here) that are more powerful than threading.Thread—in particular, that can automatically recur every second until canceled. That would obviously make your life easier.

If not, it's pretty easy to write your own repeating Timer, or to just find one on PyPI. Notice that the threading docs start with a link to the source code. That's because, like many modules in the stdlib, threading is written to be simple and easy to understand, to serve as sample code on top of being useful in its own right. In particular, Timer is dead simple, and it should be pretty obvious how to extend it: Just put a loop around the run method.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thank you very much for the response. I was in the process of extending Timer when another person offered a more simple solution. I ended up just stopping the contents of my time() function unless the unpaused variable was equal to 1. That way I dont need to start and stop the thread. – Taegis Oct 28 '14 at 20:42
  • 1
    Although for future reference, when you say "extend Timer" you mean taking the source for the original class within the threading library and editing it? Would I copy the class and paste it into my source code? I've never really edited the libraries that come with python. I'm assuming that I'd rename it and import the threading library as well right? Unless you meant something completely different. I'm a noob :p – Taegis Oct 28 '14 at 20:50
  • 1
    That or you can [extend the class](http://stackoverflow.com/a/2706023/786020). So something like `class MyTimer(threading.Timer): def run(self): while (True): threading.Timer.run(self)`. But not quite that, likely. – Poik Oct 28 '14 at 21:03
  • @Taegis: Usually you'd call what you're suggesting "forking the class", and sometimes it's perfectly viable. But, while "extending" is admittedly a vague term, I think it usually implies subclassing if possible (as Poil described), falling back to either forking or monkeypatching if the class wasn't designed in a way that makes that feasible. – abarnert Oct 28 '14 at 21:33
0

At the start of your function you've set up a new global each time and a timer:

global timer
timer = threading.Timer(1.0, time)
timer.start()

Then at the end of the function you have threading.Thread.time(self) which isn't needed and needs to be removed. Then after the function declaration you have timer = threading.Timer(1.0, time) which may be an error because when it is first called, the global timer may not have been created yet. Replace that last line of code with time() to just call the function immediately the first time. Changing these two lines will probably fix your code good enough.

Also, you have your for loops like this:

for self in thirtyonemonths:

and the problem with this would be the use of the keyword self . If this function is defined inside a class, then this use of self may be interpreted as a reference to the object. It is usually better not to use keywords such as self as iterators. Replace all uses of self with something else, like m to improve your code.

Vega_KH
  • 1
  • 2
  • Ahh ok thank you. I got rid of the piece of code at the end and also fixed the use of "self". I ended up just stopping the contents of my time() function unless the unpaused variable was equal to 1. That way I dont need to start and stop the thread. – Taegis Oct 28 '14 at 20:58