Author Topic: Switch polling inside of a for loop - switch methods also not firing  (Read 575 times)

bingopodcast

  • Newbie
  • *
  • Posts: 13
    • View Profile
This is likely a dumb question, but I have a for loop that is structured like so:

def sw_trough4_inactive(self, sw):
      for i in range(self.game.timer.position, 40):
            starttime = time.time()
            self.game.timer.step()
            print "Timer position %s" % self.game.timer.position
            time.sleep(3.0 - ((time.time() - starttime) % 3.0))
      else:
            self.game.tilt.engage(self.game)
            print "TILTED"

This works beautifully and will tilt my machine after the 40th step of my fictional timer unit (which is what I want).  Unfortunately, I have to wait for the full movement of the timer unit to the 40th position until I can press other switches!

What is the preferred way to allow for switch input to still take place while the game is executing a time-delayed for loop?  Of course, if I don't have the 3 second delay that the game provides mechanically in the real world, the loop executes so quickly that I don't notice it practically, but since I am waiting for the user to press either the start button or the coin switch, I can't really just eat their money or sit there blankly. ;-)  I guess I need to push my actual loop to a thread?  I understand how python threading works, at least conceptually, and the concept of the GIL.  Again, this is a really simple basic question and I feel dumb for asking it.

I absolutely know I am missing something really silly, and I just can't think of why this wouldn't be working.

I have a similar trouble with while loops, so much so that I threw out all the code I had previously written that used whiles and am now rewriting them with sw_x_active() type calls instead.  This seems to work (except in the above case), but in separate modes, when entering into the mode, my sw_switch_inactive() methods are not being called.  If I manually actuate the switch so that it changes state from closed back to open, it will allow the method to fire, but if I enter the mode, it will not fire the method.

In this case, I've written a 'tilt' mode, which will do a few different things.

1) Step the timer unit until the machine tilts.
2) Handle the tilt ring activation, eventually rendering the appropriate layer.
3) Wait for a coin (uses a method that relies on switch replay0 being active) - defined as sw_replay0_active()
4) Wait for a start button press (uses a method that relies on switch replay0 being inactive) - defined as sw_replay0_inactive()

I have print statements in #3 and #4, and they are not printed unless I bounce the switch.  Once the mode comes online, I would expect that one or the other would fire and print something.  They don't. 

Gerry Stellenberg

  • Administrator
  • *****
  • Posts: 2397
    • View Profile
    • PinballControllers.com
Re: Switch polling inside of a for loop - switch methods also not firing
« Reply #1 on: April 17, 2016, 04:29:05 PM »
The way pyprocgame (and most game frameworks) works, the framework has what's called a "run loop", which iterates automatically every so often (typically 60hz or faster).  Every time through the loop, the framework checks to see if anything is pending (ie. switch events, programmed delays, etc and then responds with new actions (change drivers, draw display content, start new timers, process mode logic, etc.

By putting in a "time.sleep()" command, you're blocking the main run loop from iterating; so it can't check for new switch events or service any other mode logic until the sleep and for loop completes.  Therefore you'll want to avoid ever using a time.sleep in your game code.  Instead, you'll want to figure out a way to implement your loop and delays without blocking the main run loop.  In pyprocgame, you'd typically do with this with some class properties / variables (loop count and such) and mode.delay calls.

See http://pyprocgame.pindev.org/ref/game.html?highlight=delay#procgame.game.Mode.delay
Also search any existing project for "delay" and you'll find many examples of its use.

With an active mode.delay, the framework will check all active delays every time through the run loop.  If the delay is expired, the method specified in the delay call will be called.  So to implement a loop with a delay, your expiration method would probably decrement a counter and re-issue the mode.delay call.

In summary, any time you need to iterate over something, only use a built-in loop syntax (ie. for loop, while loop, etc) if you're sure the loop will iterate immediate and then finish.  If the loop won't finish immediately (like if it needs to wait for something else to happen), then implement it using mode.delay and local variables.  That will allow the run loop to continue doing it's job of servicing the entire game.

- Gerry

bingopodcast

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Switch polling inside of a for loop - switch methods also not firing
« Reply #2 on: April 17, 2016, 05:59:46 PM »
Perfect! Thank you!