From 254ed927d67ab05330ff7452b20cd0a7b994a44e Mon Sep 17 00:00:00 2001 From: jpenner Date: Thu, 16 Jun 2005 15:25:45 +0000 Subject: [PATCH] Added error checking for front-end network code, and a menu for the multiple single-player modes. Multi-line widgets never cleared their text -- fixed. Fixed up py2exe script to automatically copy proper fonts, and ignore the CVS directory. --- TennisForTwo.leo | 62 +++++------------------------------ TennisForTwo.py | 84 ++++++++++++++++++++++++++++++++++-------------- pygame2exe.py | 16 ++++----- widgets.py | 2 ++ 4 files changed, 78 insertions(+), 86 deletions(-) diff --git a/TennisForTwo.leo b/TennisForTwo.leo index e36e92d..9cdc8a0 100644 --- a/TennisForTwo.leo +++ b/TennisForTwo.leo @@ -10,12 +10,12 @@ Files @thin TennisForTwo.py +expanded="jpenner.20050601180947,jpenner.20050305124252,jpenner.20050319143816,jpenner.20050604112932,jpenner.20050305121157,jpenner.20050305120654,jpenner.20050320112219,jpenner.20050306103246,jpenner.20050305122430,">@thin TennisForTwo.py @thin widgets.py +expanded="jpenner.20050604112932.41,jpenner.20050604112932.47,">@thin widgets.py @thin widgetsdemo.py -@thin pygame2exe.py +@thin pygame2exe.py @thin pygame2app.py Tasks @@ -26,8 +26,6 @@ expanded="jpenner.20050604113053.2,">@thin widgetsdemo.py Utilities @run TennisForTwo.py -@run TennisForTwo.py client localhost 7554 -@run widgetsdemo.py @run PyGame2Exe.py py2exe @run python2.4 pygame2app.py py2app @@ -35,52 +33,8 @@ expanded="jpenner.20050604113053.2,">@thin widgetsdemo.py -@ignore -@language python -#make standalone, needs at least pygame-1.5.3 and py2exe-0.3.1 - -from distutils.core import setup -import sys, os, pygame, shutil, glob -import py2exe - -#setup the project variables here. -#i can't claim these will cover all the cases -#you need, but they seem to work for all my -#projects, just change as neeeded. - - -script = "TennisForTwo.py" #name of starting .PY -icon_file = "" #ICO file for the .EXE (not working well) -optimize = 2 #0, 1, or 2; like -O and -OO -dos_console = 0 #set to 0 for no dos shell when run -extra_data = ['data'] #extra files/dirs copied to game -extra_modules = ['pygame.locals'] #extra python modules not auto found - - - - - - -#use the default pygame icon, if none given -if not icon_file: - path = os.path.split(pygame.__file__)[0] - icon_file = '"' + os.path.join(path, 'pygame.ico') + '"' -#unfortunately, this cool icon stuff doesn't work in current py2exe :( -#icon_file = '' - -project_name = os.path.splitext(os.path.split(script)[1])[0] - - -#this will create the executable and all dependencies -setup(#name=project_name, - windows=[script], - data_files=[("data", glob.glob("data\\*"))] - ) - - - def __init__( self ): """Initialize Demo Class""" # instead of pygame.init(), initialize modules manually to @@ -130,17 +84,17 @@ setup(#name=project_name, self.animline.width = 5 self.animline.left = self.animrect.left - self.addwidget(TextClass(self, (120, 40, 400, 30), "Tennis For Two", 36)) self.addwidget(ButtonClass(self, self.startSingle, (120, 120, 400, 30), "Start Single-Player Game")) +self.addwidget(ButtonClass(self, self.startAI, (120, 155, 400, 30), "Start Game Vs. Tennis-O-Tron")) -self.addwidget(TextClass(self, (120, 190, 400, 20), "Your IP Address: " + getMyIP())) -self.addwidget(TextClass(self, (120, 215, 60, 20), "Port:")) -self.serverPort = EditClass(self, None, (180, 215, 60, 20), "7554") +self.addwidget(TextClass(self, (120, 220, 450, 20), "Your IP Address: " + getMyIP())) +self.addwidget(TextClass(self, (120, 245, 60, 20), "Port:")) +self.serverPort = EditClass(self, None, (180, 245, 60, 20), "7554") self.addwidget(self.serverPort) -self.addwidget(ButtonClass(self, self.startServer, (120, 240, 400, 30), "Start Server")) +self.addwidget(ButtonClass(self, self.startServer, (120, 270, 400, 30), "Start Server")) self.addwidget(TextClass(self, (120, 310, 160, 20), "Server Address:")) self.clientAddr = EditClass(self, None, (280, 310, 240, 20)) diff --git a/TennisForTwo.py b/TennisForTwo.py index 7de787b..ddc1169 100644 --- a/TennisForTwo.py +++ b/TennisForTwo.py @@ -28,6 +28,8 @@ class Game: AIPlayer = 0 SeverPort = 7554 Port = None + + logfile = None #@nonl #@-node:jpenner.20050310195953:Globals #@+node:jpenner.20050424164431:Logging @@ -35,7 +37,8 @@ def startLogging(fn): Game.logfile = open(fn, 'wt') def log(text): - Game.logfile.write(str(text) + '\n') + if Game.logfile <> None: + Game.logfile.write(str(text) + '\n') def stopLogging(): Game.logfile.close() @@ -58,13 +61,16 @@ def getMyIP(): try: f = urllib.urlopen('http://checkip.dyndns.org') s = f.read() - m = re.search('([\d]*\.[\d]*\.[\d]*\.[\d]*)', s) + log("checkip: " + s) + m = re.search('Current IP Address: ([\d]*\.[\d]*\.[\d]*\.[\d]*)', s) outsideip = m.group(0) + log("outside ip: " + outsideip) except: outsideip = None try: insideip = socket.gethostbyname(socket.gethostname()) + log("inside ip: " + insideip) except: insideip = None @@ -72,7 +78,7 @@ def getMyIP(): ip = "Unknown" else: if (outsideip == None): - ip = insideip + " (No internet?)" + ip = insideip + " (Firewalled / Proxied?)" else: ip = outsideip if (insideip <> None) and (insideip <> outsideip): @@ -268,12 +274,13 @@ class MainMenu(BaseMenu): self.addwidget(TextClass(self, (120, 40, 400, 30), "Tennis For Two", 36)) self.addwidget(ButtonClass(self, self.startSingle, (120, 120, 400, 30), "Start Single-Player Game")) + self.addwidget(ButtonClass(self, self.startAI, (120, 155, 400, 30), "Start Game Vs. Tennis-O-Tron")) - self.addwidget(TextClass(self, (120, 190, 400, 20), "Your IP Address: " + getMyIP())) - self.addwidget(TextClass(self, (120, 215, 60, 20), "Port:")) - self.serverPort = EditClass(self, None, (180, 215, 60, 20), "7554") + self.addwidget(TextClass(self, (120, 220, 450, 20), "Your IP Address: " + getMyIP())) + self.addwidget(TextClass(self, (120, 245, 60, 20), "Port:")) + self.serverPort = EditClass(self, None, (180, 245, 60, 20), "7554") self.addwidget(self.serverPort) - self.addwidget(ButtonClass(self, self.startServer, (120, 240, 400, 30), "Start Server")) + self.addwidget(ButtonClass(self, self.startServer, (120, 270, 400, 30), "Start Server")) self.addwidget(TextClass(self, (120, 310, 160, 20), "Server Address:")) self.clientAddr = EditClass(self, None, (280, 310, 240, 20)) @@ -286,13 +293,17 @@ class MainMenu(BaseMenu): #@nl def startSingle(self): -# Game.myplayer = SINGLE_PLAYER - Game.myplayer = 1 + Game.myplayer = SINGLE_PLAYER Game.isClient = False -# Game.rules.infinitehits = True - Game.AIPlayer = 2 + Game.rules.infinitehits = True Game.gameMgr.changeState(Game.gameMgr.STATE_SINGLE_PLAYER) + def startAI(self): + Game.myplayer = 1 + Game.isClient = False + Game.AIPlayer = 2 + Game.gameMgr.changeState(Game.gameMgr.STATE_SINGLE_PLAYER) + def startServer(self): Game.myplayer = 1 Game.isClient = False @@ -352,6 +363,21 @@ class ClientWait(BaseMenu): Game.network.sendEvent(ConnectEvent()) #@-node:jpenner.20050605180040:Client Wait Screen +#@+node:jpenner.20050616085506:Failure Screen +class FailScreen(BaseMenu): + def menuLayout(self): + self.errText = MultiLineTextClass(self, (120, 60, 400, 270), "", 24) + self.addwidget(self.errText) + self.addwidget(ButtonClass(self, self.ok, (120, 360, 400, 30), "OK")) + + def ok(self): + Game.gameMgr.changeState(Game.gameMgr.STATE_MENU) + + def onEnter(self): + BaseMenu.onEnter(self) + self.errText.settext(Game.failure) +#@nonl +#@-node:jpenner.20050616085506:Failure Screen #@-others #@-node:jpenner.20050604112932:Menu #@+node:jpenner.20050305121157:Game @@ -683,7 +709,6 @@ class InputManager: def sdl_event(self, event): if event.type == MOUSEBUTTONUP: angle = makeAngle(event.pos) - log("userangle: " + str(math.degrees(angle))) Game.evMgr.postEvent( ClickEvent(velocityFromAngle(angle), Game.myplayer) ) if event.type == KEYUP: @@ -750,21 +775,24 @@ class GameMgr (StateMachine): self.STATE_SINGLE_PLAYER = 2 self.STATE_WAIT_FOR_CLIENT = 3 self.STATE_CONNECT = 4 - + self.STATE_FAILURE = 5 + inputMgr = InputManager() self.graphicsMgr = TFTGraphicsMgr() self.physicsMgr = PhysicsMgr() mainMenu = MainMenu() + failScreen = FailScreen() self.serverWait = ServerWait() self.clientWait = ClientWait() StateMachine.__init__(self, - [GameState(MainMenu(), mainMenu.onEnter), + [GameState(mainMenu, mainMenu.onEnter), GameState(GameLoop([inputMgr, Game.evMgr, self.physicsMgr, self.graphicsMgr]), self.gameEnter), GameState(GameLoop([inputMgr, AIPlayer(), Game.evMgr, PhysicsEngine(), self.graphicsMgr]), self.gameEnter), GameState(GameLoop([Game.evMgr, self.serverWait]), self.serverEnter, self.networkExit), - GameState(GameLoop([Game.evMgr, self.clientWait]), self.clientEnter, self.networkExit) + GameState(GameLoop([Game.evMgr, self.clientWait]), self.clientEnter, self.networkExit), + GameState(failScreen, failScreen.onEnter, self.networkExit) ]) def gameEnter(self): @@ -772,23 +800,31 @@ class GameMgr (StateMachine): self.physicsMgr.onEnter() def clientEnter(self): + self.clientWait.onEnter() + Game.network = TFTProtocol() def onResolve(ip): Game.network.address = (ip, Game.ServerPort) Game.port = reactor.listenUDP(0, Game.network) - reactor.resolve(Game.ServerIP).addCallback(onResolve) - self.clientWait.onEnter() + def onFail(err): + Game.failure = err.getErrorMessage() + self.changeState(self.STATE_FAILURE) + reactor.resolve(Game.ServerIP).addCallback(onResolve).addErrback(onFail) def serverEnter(self): + self.serverWait.onEnter() + Game.network = TFTProtocol() - Game.port = reactor.listenUDP(Game.ServerPort, Game.network) - log ("Listening on " + str(Game.ServerPort)) - self.serverWait.onEnter() + try: + Game.port = reactor.listenUDP(Game.ServerPort, Game.network) + log ("Listening on " + str(Game.ServerPort)) + except: + Game.failure = "Unable to listen on UDP port " + str(Game.ServerPort) + ". Make sure nothing else is using that port, and you have the proper permissions to create a server on it." + self.changeState(self.STATE_FAILURE) def networkExit(self): - if (self.newstate == self.STATE_MENU) and (Game.port <> None): # cancelled + if ((self.newstate == self.STATE_MENU) or (self.newstate == self.STATE_FAILURE)) and (Game.port <> None): # cancelled Game.port.stopListening() - #@-node:jpenner.20050606072251.1:Game Manager #@-others @@ -799,7 +835,7 @@ def main(): random.seed() pygame.init() - startLogging('tennis.log') +# startLogging('tennis.log') Game.screen = pygame.display.set_mode(SCREENRECT.size, DOUBLEBUF, 16) @@ -813,7 +849,7 @@ def main(): reactor.run() #cleanup - stopLogging() +# stopLogging() diff --git a/pygame2exe.py b/pygame2exe.py index 7bb6155..c49264f 100644 --- a/pygame2exe.py +++ b/pygame2exe.py @@ -1,8 +1,11 @@ +#@+leo-ver=4-thin +#@+node:jpenner.20050319120621:@thin pygame2exe.py +#@@language python #make standalone, needs at least pygame-1.5.3 and py2exe-0.3.1 from distutils.core import setup import sys, os, pygame, shutil, glob -import py2exe +import py2exe #setup the project variables here. #i can't claim these will cover all the cases @@ -17,11 +20,6 @@ dos_console = 0 #set to 0 for no dos shell when run extra_data = ['data'] #extra files/dirs copied to game extra_modules = ['pygame.locals'] #extra python modules not auto found - - - - - #use the default pygame icon, if none given if not icon_file: path = os.path.split(pygame.__file__)[0] @@ -31,10 +29,12 @@ if not icon_file: project_name = os.path.splitext(os.path.split(script)[1])[0] - #this will create the executable and all dependencies setup(#name=project_name, windows=[script], - data_files=[("data", glob.glob("data\\*"))] + data_files=[("data", glob.glob("data\\*.wav")),(".", ["C:\\python24\\lib\\site-packages\\pygame\\freesansbold.ttf"])] ) + +#@-node:jpenner.20050319120621:@thin pygame2exe.py +#@-leo diff --git a/widgets.py b/widgets.py index 795f6e7..a19b4cf 100644 --- a/widgets.py +++ b/widgets.py @@ -1006,6 +1006,8 @@ class MultiLineTextClass: #@+node:jpenner.20050604112932.50:settext def settext( self, newtext ): """Replace the text of the widget""" + + self.lines = [] # clear current text # expand tabs newtext = newtext.expandtabs() # append each line separately