Home runs can be as slow as 90 mph off the bat.   This suprised me, at first, as that is the speed of a pitched fastball, and we do not imagine that someone can throw a baseball over the outfield fence from home plate.  However, a good strong arm can reach home plate on a throw from mid center field, and the nearest fence portions, of small ballparks such as Fenway, are as close as 325 ft.

There were two home runs at under 89.5 mph off the bat, but both were in-the-park home runs. 😉 

The fastest home runs were slightly over 122 mph, off the bat.

HitTracker :: Home run tracking and distance measurement 

This weekend was mildly productive.  I resolved the memory leak in Pitchers Duel, which was actually a memory leak in Lamina.   So I put a corrected version of Lamina in subversion; I also updated the demos to fail more politely in the absence of necessary GUI libraries.

I will try to get a new release packaged up and put on Pypi this week, but the current code is available at the link below.

/branches/Lamina/Pitchers Duel

David

I like the term ‘Pitchers Duel’, because it describes a type of game that I enjoy thinking about.  Low score, few baserunners, many strikeouts.  Baserunning doesn’t matter much in these games, because rarely does a runner get on base.  The consistency of out-getting makes the contest look like a pure contest between pitchers:  Which pitcher will slip up first, and allow a run to score?

Most baseball fans, to the contrary, like high scoring games.  Baseball game attendence has increased in eras with high-scoring and dropped in low-scoring eras.   So I am considering alternative names for this computer game, that will appeal more to baseball fans.

The pitcher – catcher combo is known as the ‘battery’:

      Battery plus

Various phrases that emphasise the hitting aspect of the game:

       Bat and Ball / Ball and Bat

       Batter Up

       Ball and Stick

A more balanced title that includes both sides of the contest: 

        Hit and Pitch

This title represents the ‘moment of truth’ in each at-bat, where you know you may get only one more pitch. 

        Strike Two

Both batters and pitchers are very concerned about the strikezone, its extents, whether a given pitch is in or out, and how the player fares in the balance of strikes vs balls.

       Strike Zone

       Balls and Strikes

      Ahead of the Count

      Full Count

A facetious, but sorta mean-spirited, option: 

      NOT Barry Bonds

Let me know what you feel is a good choice.

This subclass of Twisted’s selectreactor has methods to yield control of the reactor to its caller, and resume control later.

The guts of mainLoop have been moved to a generator method, and mainLoop instantiates the generator and calls .next() on it.

There are new methods for new functionality.

.release() causes the mainLoop to yield at the end of its current iteration.

.resume() transfers control back into the reactor. A .resume call is like .run, in that it does not yield control until the next .release or .stop.

.isRunning() tells you whether the reactor is running.



from twisted.python import log, failure, util
from twisted.internet.selectreactor import SelectReactor

class PausingReactor(SelectReactor):
    """Implement selectreactor that can be exited and resumed. """

    def __init__(self, *args):
        SelectReactor.__init__(self, *args)
        self._releaseRequested = False
        self._mainLoopGen = None

    def _mainLoopGenerater(self):
        """Generater that acts as mainLoop, but yields when
        requested.
        """
        while self.running:
            try:
                while self.running:
                    # Advance simulation time in delayed event
                    # processors.
                    self.runUntilCurrent()
                    t2 = self.timeout()
                    t = self.running and t2
                    self.doIteration(t)

                    if self._releaseRequested:
                        self._releaseRequested = False
                        yield None
            except:
                log.msg("Unexpected error in main loop.")
                log.deferr()
            else:
                log.msg('Main loop terminated.')

    def mainLoop(self):
        """Setup mainLoop generater, and initiate looping. """
        self._mainLoopGen = self._mainLoopGenerater()
        self.resume()

    def resume(self):
        """Resume mainLoop looping after interruption. """
        try:
            self._mainLoopGen.next()
        except StopIteration:
            pass

    def release(self):
        """Request main loop pause and reacter yield to caller. """
        self._releaseRequested = True

    def isRunning(self):
        """Is reactor running? """
        return self.running

def install():
    """Configure the twisted mainloop to be run using the pausingreactor.
    """
    reactor = PausingReactor()
    from twisted.internet.main import installReactor
    installReactor(reactor)

__all__ = ['install']

To use the module,
import pausingreactor; pausingreactor.install()

The pausingreactor module, and a couple of files to test it, are linked. The stresstest.py sends increasing long strings to an echo type server ‘uppercaser_ns.py’, reads them back and checks them for intactness. It also pauses a couple times per second for a fraction of a second.

pausingreactor.py

stresstest.py

uppercaser_ns.py

Enjoy.

I have been considering networking options for months, and over the last couple of weeks have had time to explore specific options. I initially made exploratory forays into two disparate implementations: One approach was to write the game logic in ‘inside-out’ form so that everything could be done by callback; the other approach was to put the network code into another process, and pipe data to and from it via os pipes.

The ‘inside-out’ approach would add significant burden to coding the game logic, and was abandoned after an evenings work. The separate process approach was making some headway, but I have put it aside as well, for yet another approach.

What I want(1) is a twisted reactor that can be exited and reentered. I could then use the substantial asset of proven twisted code for various high and low level operations, but use a conventional subroutine-oriented code structure. When an engine needs to exit, it can have the reactor yield to its caller; the caller then follows game logic to set up another engine, which resumes the reactor operation. The timing constraints would be the same as for a call-back, (ie: don’t delay the reactor more than necessary), but the game logic would be more readable and more writable without having to put everything in callbacks.

The usage would be like:

 
class Engine() 
   def iterate(self): 
       # do per frame stuff 
       if self._done:  reactor.release() # yield to engine's caller 
       else:   reactor.callLater(0, self.iterate) 
   def run(self): 
       # init stuff 
       reactor.callLater(0, self.iterate) 
       if reactor.isRunning(): reactor.resume() 
       else:  reactor.run()    

def intro(): 
   # set up intro pages 
   eng = Engine() 
   eng.add(intro_pages) 
   eng.run()   

def room(room_context): 
   eng = Engine() 
   eng.add(room_context) 
   eng.run() 
   return eng.retval   

def main(): 
   intro() 
   # set up lobby context 
   next = room(lobby_context) 
   while next != GAME_EXIT: 
        # set up context for next room 
        next = room(room_context)           

The code is fairly readable, with more specialized function in specialized subroutines.  Calls to the engine can be from main(),  or from a subroutine a few calls deep.  

See my next post for the reactor subclass itself.

1)
OK, what I really want is a file-like connection object:
con = Connection(‘gameserver.org’)
con.write(‘game update data’, game_data)
news = con.read()
check = con.read_non_blocking()
But I am not going to find (or write) that, so I’ll settle for an pause-able reactor.

APRESS.COM : Beginning Game Development with Python and Pygame: From Novice to Professional

by Will McGugan

This book seems well fitted for a beginner, as it starts with a basic Python tutorial, and steps up gradually to more sophisticated material. The book is more useful as a tutorial, describing a tank game with increasing complexity, from interactive text to 2D animation, to 3D in OpenGL, than as a reference.

The chapter titles are meaningful, but task oriented, ‘making things move’, ‘user input’, …. ‘making things go boom’. Once you’ve identified the chapter that might answer your question, you have to skim to find the material, though the material does have abundant subheadings, at least one per page, to help you in skimming. There is a nice index of 20 pages, which seemed thorough, in that the half dozen items I looked up were all there.

Will covers a pretty good range of topics, including packaging, sound, openGL, artificial intelligence, and inputs. The only section that surprised me in its presence was the ‘Moving into the third dimension’, in that he discusses the calculations involved in mapping 3D space to the 2D display. Most 3D programmers, I suspect, just offload that calculation burden onto the OpenGL (or DirectX) engine, and do not do such translations ourselves. Maybe the skills might be useful for people who want 3D effects in straight pygame, and the chapter may serve as a transition from the 2D material presented prior, to the OpenGL material to follow. I just skimmed through briefly, as I was already familiar with OpenGL.

The only substantial omission I found was that networking was not addressed. He may consider the networking options too unsettled at this point to be able to recommend a specific approach.

I was disappointed to not find any advice on determining which joystick button or mouse button is which. Pygame recognizes buttons 1, 2, 3, etc.., but there is no firm rule on which number belongs to a given button on the input device. The right mouse button is button 2, or button 3, depending on whether scroll-wheel is present, and I don’t know a systematic way to determine what buttons the user’s mouse has, and what numbers thy hold. Maybe this problem doesn’t have a clear resolution.

I cant complete a review of a book on game programming in python without a comparison with the other book on the topic. Sean Riley’s ‘Game Programming with Python’. GPwP is a bigger, more involved work, that is less tied to Pygame, and less approachable for beginners. If you are a beginner looking to ease your learning curve, get BGDwP. If your question isn’t answered by BGDwP, it might be by GPwP. For what it’s worth, ‘Game Programming with Python’ does discuss networking, but did not help me with my joystick button interpretation.

The sequence above was flat, not involving any subroutines. Any significant game is going to make a *very* long main generator, without subroutines. However, any subroutine called from the generator cannot chain to an engine or other functionality via the reactor. Returning control to the reactor is done by yielding. If the sub-generator yields, it yields to its caller, which needs in turn to yield, recursively all the way to the reactor.

(more…)