Initial check-in.
This commit is contained in:
commit
e904d0bf05
156
TennisForTwo.leo
Normal file
156
TennisForTwo.leo
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<leo_file>
|
||||||
|
<leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
|
||||||
|
<globals body_outline_ratio="0.603318250377">
|
||||||
|
<global_window_position top="25" left="10" height="734" width="1280"/>
|
||||||
|
<global_log_window_position top="0" left="0" height="0" width="0"/>
|
||||||
|
</globals>
|
||||||
|
<preferences/>
|
||||||
|
<find_panel_settings/>
|
||||||
|
<vnodes>
|
||||||
|
<v t="jpenner.20050319120705" a="E"><vh>Files</vh>
|
||||||
|
<v t="jpenner.20050305105206" a="E"
|
||||||
|
expanded="jpenner.20050601180947,jpenner.20050305124252,jpenner.20050319143816,jpenner.20050604112932,jpenner.20050605102056,jpenner.20050305121157,jpenner.20050306103246,jpenner.20050305122430,"><vh>@thin TennisForTwo.py</vh></v>
|
||||||
|
<v t="jpenner.20050604112932.1"
|
||||||
|
expanded="jpenner.20050604112932.6,jpenner.20050604112932.16,jpenner.20050604112932.30,jpenner.20050604112932.41,"><vh>@thin widgets.py</vh></v>
|
||||||
|
<v t="jpenner.20050604113053"
|
||||||
|
expanded="jpenner.20050604113053.2,"><vh>@thin widgetsdemo.py</vh></v>
|
||||||
|
<v t="jpenner.20050319120621"><vh>@thin pygame2exe.py</vh></v>
|
||||||
|
<v t="jpenner.20050604144534"><vh>@thin pygame2app.py</vh></v>
|
||||||
|
</v>
|
||||||
|
<v t="jpenner.20050605105545"><vh>Tasks</vh>
|
||||||
|
<v t="jpenner.20050605105545.1" a="E"><vh>Starting menu</vh>
|
||||||
|
<v t="jpenner.20050604113053.3"><vh>__init__</vh></v>
|
||||||
|
<v t="jpenner.20050605102056.1"><vh><< Menu layout >></vh></v>
|
||||||
|
</v>
|
||||||
|
</v>
|
||||||
|
<v t="jpenner.20050319120705.1" a="E"><vh>Utilities</vh>
|
||||||
|
<v t="jpenner.20050305121227" a="E"><vh>@run TennisForTwo.py</vh></v>
|
||||||
|
<v t="jpenner.20050320113047"><vh>@run TennisForTwo.py client localhost 7554</vh></v>
|
||||||
|
<v t="jpenner.20050604113053.7" a="E"><vh>@run widgetsdemo.py</vh></v>
|
||||||
|
<v t="jpenner.20050307190605"><vh>@run PyGame2Exe.py py2exe</vh></v>
|
||||||
|
<v t="jpenner.20050604144534.1"><vh>@run python2.4 pygame2app.py py2app</vh></v>
|
||||||
|
</v>
|
||||||
|
</vnodes>
|
||||||
|
<tnodes>
|
||||||
|
<t tx="jpenner.20050305121227"></t>
|
||||||
|
<t tx="jpenner.20050307190605"></t>
|
||||||
|
<t tx="jpenner.20050319120621">@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\\*"))]
|
||||||
|
)
|
||||||
|
|
||||||
|
</t>
|
||||||
|
<t tx="jpenner.20050319120705"></t>
|
||||||
|
<t tx="jpenner.20050319120705.1"></t>
|
||||||
|
<t tx="jpenner.20050320113047"></t>
|
||||||
|
<t tx="jpenner.20050604113053.3">def __init__( self ):
|
||||||
|
"""Initialize Demo Class"""
|
||||||
|
# instead of pygame.init(), initialize modules manually to
|
||||||
|
# avoid initing pygame.sound
|
||||||
|
pygame.display.init()
|
||||||
|
pygame.font.init()
|
||||||
|
|
||||||
|
# setup screen
|
||||||
|
screen = pygame.display.set_mode( (640, 480), DOUBLEBUF )
|
||||||
|
pygame.display.set_caption( 'WidgetsDemo' )
|
||||||
|
|
||||||
|
# request regular event for updating animation
|
||||||
|
self.DRAWEVENT = USEREVENT + 1
|
||||||
|
pygame.time.set_timer( self.DRAWEVENT, 33 ) #33 == 30fps
|
||||||
|
|
||||||
|
# filter events
|
||||||
|
badevents = [NOEVENT, ACTIVEEVENT, JOYAXISMOTION, JOYBALLMOTION, JOYHATMOTION, JOYBUTTONDOWN ,JOYBUTTONUP, VIDEORESIZE, SYSWMEVENT, NUMEVENTS]
|
||||||
|
goodevents = [self.DRAWEVENT, KEYDOWN, KEYUP, MOUSEMOTION, MOUSEBUTTONDOWN, MOUSEBUTTONUP, QUIT ]
|
||||||
|
pygame.event.set_blocked( badevents )
|
||||||
|
|
||||||
|
# initialize the WidgetWindow base class
|
||||||
|
WidgetWindow.__init__( self, screen )
|
||||||
|
|
||||||
|
# create special widgets
|
||||||
|
edit = EditClass( self, self.editaction, (325, 300, 265, 25), "text" )
|
||||||
|
self.page = PageClass( self, (325, 25, 265, 275), GRAY )
|
||||||
|
|
||||||
|
# put the widgets in the window
|
||||||
|
self.addwidget( MultiLineTextClass( self, (25, 25, 250, 145), "MultiLineTextClass\n(transparent)\nHas automatic word wrapping.", 36 ) )
|
||||||
|
self.addwidget( MultiLineTextClass( self, (25, 195, 250, 145), "MultiLineTextClass\n(with background)\nHas automatic word wrapping.", 36, WHITE, BLACK ) )
|
||||||
|
self.addwidget( EditClass( self, self.editaction, (25, 350, 150, 30), "second edit box" ), TABTARGET )
|
||||||
|
self.addwidget( TextClass( self, (25, 400, 590, 19), "TextClass (transparent)", 20 ) )
|
||||||
|
self.addwidget( TextClass( self, (25, 440, 590, 19), "TextClass (with background)", 20, WHITE, BLACK ) )
|
||||||
|
self.addwidget( self.page )
|
||||||
|
self.addwidget( edit, TABTARGET )
|
||||||
|
self.addwidget( ButtonClass( self, self.buttonaction, (205, 110, 200, 105), "This button overlaps" ) )
|
||||||
|
|
||||||
|
# set keyboard focus to the edit widget
|
||||||
|
edit.focus()
|
||||||
|
|
||||||
|
# initial screen draw
|
||||||
|
self.eventproc( pygame.event.Event( NOEVENT, {} ) )
|
||||||
|
|
||||||
|
# animation data
|
||||||
|
self.animrect = Rect( (325, 350, 265, 50) )
|
||||||
|
self.animline = Rect( self.animrect )
|
||||||
|
self.animline.width = 5
|
||||||
|
self.animline.left = self.animrect.left
|
||||||
|
</t>
|
||||||
|
<t tx="jpenner.20050604113053.7"></t>
|
||||||
|
<t tx="jpenner.20050604144534.1"></t>
|
||||||
|
<t tx="jpenner.20050605102056.1">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(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(self.serverPort)
|
||||||
|
self.addwidget(ButtonClass(self, self.startServer, (120, 240, 400, 30), "Start Server"))
|
||||||
|
|
||||||
|
self.addwidget(TextClass(self, (120, 310, 160, 20), "Server Address:"))
|
||||||
|
self.clientAddr = EditClass(self, None, (280, 310, 240, 20))
|
||||||
|
self.addwidget(self.clientAddr)
|
||||||
|
self.addwidget(TextClass(self, (120, 335, 60, 20), "Port:"))
|
||||||
|
self.clientPort = EditClass(self, None, (180, 335, 60, 20), "7554")
|
||||||
|
self.addwidget(self.clientPort)
|
||||||
|
self.addwidget(ButtonClass(self, self.startClient, (120, 360, 400, 30), "Start Client"))
|
||||||
|
</t>
|
||||||
|
<t tx="jpenner.20050605105545"></t>
|
||||||
|
<t tx="jpenner.20050605105545.1"></t>
|
||||||
|
</tnodes>
|
||||||
|
</leo_file>
|
814
TennisForTwo.py
Normal file
814
TennisForTwo.py
Normal file
|
@ -0,0 +1,814 @@
|
||||||
|
#@+leo-ver=4-thin
|
||||||
|
#@+node:jpenner.20050305105206:@thin TennisForTwo.py
|
||||||
|
#@@language python
|
||||||
|
|
||||||
|
import pygame, math, cPickle, sys, StringIO, socket, re, urllib
|
||||||
|
from pygame.locals import *
|
||||||
|
from twisted.internet import task, reactor, protocol, udp
|
||||||
|
from widgets import *
|
||||||
|
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050601180947:Helper / Misc
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050305105934:Constants
|
||||||
|
#constants
|
||||||
|
SCREENRECT = Rect(0, 0, 640, 480)
|
||||||
|
GRAVITY = 0.25
|
||||||
|
FRICTION = 4
|
||||||
|
BALL_STARTX = 100
|
||||||
|
BALL_STARTY = 350
|
||||||
|
|
||||||
|
SINGLE_PLAYER = 10
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050305105934:Constants
|
||||||
|
#@+node:jpenner.20050310195953:Globals
|
||||||
|
#globals
|
||||||
|
class Game:
|
||||||
|
currentplayer = 1
|
||||||
|
SeverPort = 7554
|
||||||
|
Port = None
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050310195953:Globals
|
||||||
|
#@+node:jpenner.20050424164431:Logging
|
||||||
|
def startLogging(fn):
|
||||||
|
Game.logfile = open(fn, 'wt')
|
||||||
|
|
||||||
|
def log(text):
|
||||||
|
Game.logfile.write(str(text) + '\n')
|
||||||
|
|
||||||
|
def stopLogging():
|
||||||
|
Game.logfile.close()
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050424164431:Logging
|
||||||
|
#@+node:jpenner.20050427175747:Angles
|
||||||
|
def makeAngle(pos):
|
||||||
|
xdist = pos[0] - Game.ball.rect.centerx
|
||||||
|
ydist = pos[1] - Game.ball.rect.centery
|
||||||
|
return math.atan2(ydist, xdist)
|
||||||
|
|
||||||
|
def anglePos(rect, angle, radius):
|
||||||
|
return( (rect.centerx + (math.cos(angle) * radius)), (rect.centery + (math.sin(angle) * radius)))
|
||||||
|
|
||||||
|
#@-node:jpenner.20050427175747:Angles
|
||||||
|
#@+node:jpenner.20050605110605:IP address
|
||||||
|
def getMyIP():
|
||||||
|
try:
|
||||||
|
f = urllib.urlopen('http://checkip.dyndns.org')
|
||||||
|
s = f.read()
|
||||||
|
m = re.search('([\d]*\.[\d]*\.[\d]*\.[\d]*)', s)
|
||||||
|
outsideip = m.group(0)
|
||||||
|
except:
|
||||||
|
outsideip = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
insideip = socket.gethostbyname(socket.gethostname())
|
||||||
|
except:
|
||||||
|
insideip = None
|
||||||
|
|
||||||
|
if (outsideip == None) and (insideip == None):
|
||||||
|
ip = "Unknown"
|
||||||
|
else:
|
||||||
|
if (outsideip == None):
|
||||||
|
ip = insideip + " (No internet?)"
|
||||||
|
else:
|
||||||
|
ip = outsideip
|
||||||
|
if (insideip <> None) and (insideip <> outsideip):
|
||||||
|
ip = ip + " (Firewalled?)"
|
||||||
|
return ip
|
||||||
|
#@-node:jpenner.20050605110605:IP address
|
||||||
|
#@-others
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050601180947:Helper / Misc
|
||||||
|
#@+node:jpenner.20050305124252:Events
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050305130011.1:Event Manager
|
||||||
|
class EventManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.queue = []
|
||||||
|
self.handlers = [[] for i in range(NUM_EVENTS)]
|
||||||
|
|
||||||
|
def postEvent(self,event):
|
||||||
|
self.queue.append(event);
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
for event in self.queue:
|
||||||
|
for handler in self.handlers[event.type]:
|
||||||
|
handler(event)
|
||||||
|
self.queue = []
|
||||||
|
|
||||||
|
def registerHandler(self, evtype, func):
|
||||||
|
if (evtype == NUM_EVENTS):
|
||||||
|
for i in range(NUM_EVENTS):
|
||||||
|
self.registerHandler(i, func)
|
||||||
|
else:
|
||||||
|
self.handlers[evtype].append(func)
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050305130011.1:Event Manager
|
||||||
|
#@+node:jpenner.20050305130011:Types
|
||||||
|
EV_HIT = 0
|
||||||
|
EV_SCORE = 1
|
||||||
|
EV_BOUNCE = 2
|
||||||
|
EV_PLAYER_UPDATE = 3
|
||||||
|
EV_SERVE = 4
|
||||||
|
EV_CLICK = 5
|
||||||
|
EV_BALLPOS = 6
|
||||||
|
EV_CONNECT = 7
|
||||||
|
EV_PLAYER_SWITCH = 8
|
||||||
|
EV_HELLO = 9
|
||||||
|
NUM_EVENTS = 10
|
||||||
|
|
||||||
|
class Event:
|
||||||
|
def __init__(self, type):
|
||||||
|
self.type = type
|
||||||
|
self.fromplayer = Game.myplayer
|
||||||
|
|
||||||
|
class ClickEvent (Event):
|
||||||
|
def __init__(self, xvel, yvel, player):
|
||||||
|
Event.__init__(self, EV_CLICK)
|
||||||
|
self.xvel = xvel
|
||||||
|
self.yvel = yvel
|
||||||
|
self.player = player
|
||||||
|
|
||||||
|
class HitEvent (Event):
|
||||||
|
def __init__(self, xvel, yvel):
|
||||||
|
Event.__init__(self, EV_HIT)
|
||||||
|
self.xvel = xvel
|
||||||
|
self.yvel = yvel
|
||||||
|
|
||||||
|
class ScoreEvent (Event):
|
||||||
|
def __init__(self, player):
|
||||||
|
Event.__init__(self, EV_SCORE)
|
||||||
|
self.player = player
|
||||||
|
|
||||||
|
class BounceEvent (Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, EV_BOUNCE)
|
||||||
|
|
||||||
|
class PlayerUpdateEvent (Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, EV_PLAYER_UPDATE)
|
||||||
|
|
||||||
|
class ServeEvent (Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, EV_SERVE)
|
||||||
|
|
||||||
|
class BallPosEvent (Event):
|
||||||
|
def __init__(self, x, y):
|
||||||
|
Event.__init__(self, EV_BALLPOS)
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
|
||||||
|
class ConnectEvent (Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, EV_CONNECT)
|
||||||
|
|
||||||
|
class PlayerSwitchEvent (Event):
|
||||||
|
lastseq = 0
|
||||||
|
def __init__(self, xvel, yvel, xpos, ypos, stopped):
|
||||||
|
Event.__init__(self, EV_PLAYER_SWITCH)
|
||||||
|
self.xvel = xvel
|
||||||
|
self.yvel = yvel
|
||||||
|
self.xpos = xpos
|
||||||
|
self.ypos = ypos
|
||||||
|
self.stopped = stopped
|
||||||
|
self.seq = PlayerSwitchEvent.lastseq
|
||||||
|
PlayerSwitchEvent.lastseq = PlayerSwitchEvent.lastseq + 1
|
||||||
|
|
||||||
|
class HelloEvent(Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, EV_HELLO)
|
||||||
|
|
||||||
|
#@-node:jpenner.20050305130011:Types
|
||||||
|
#@-others
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050305124252:Events
|
||||||
|
#@+node:jpenner.20050319143816:Networking
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050320120319:Message
|
||||||
|
class TFTMessage:
|
||||||
|
def __init__(self, sequence, event):
|
||||||
|
self.sequence = sequence
|
||||||
|
self.event = event
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050320120319:Message
|
||||||
|
#@+node:jpenner.20050424135832:Protocol
|
||||||
|
class TFTProtocol (protocol.DatagramProtocol):
|
||||||
|
def __init__(self):
|
||||||
|
self.mysequence = 0
|
||||||
|
self.hissequence = -1
|
||||||
|
self.address = None
|
||||||
|
Game.evMgr.registerHandler(EV_BALLPOS, self.sendEvent)
|
||||||
|
Game.evMgr.registerHandler(EV_SERVE, self.sendEvent)
|
||||||
|
Game.evMgr.registerHandler(EV_PLAYER_SWITCH, self.sendEvent)
|
||||||
|
Game.evMgr.registerHandler(EV_CONNECT, self.connectTransport)
|
||||||
|
|
||||||
|
def startProtocol(self):
|
||||||
|
if self.address <> None:
|
||||||
|
log (self.address)
|
||||||
|
|
||||||
|
def datagramReceived(self, data, address):
|
||||||
|
if self.address == None:
|
||||||
|
self.address = address
|
||||||
|
log(address)
|
||||||
|
msg = cPickle.Unpickler(StringIO.StringIO(data)).load()
|
||||||
|
|
||||||
|
if (msg.sequence > self.hissequence):
|
||||||
|
self.hissequence = msg.sequence
|
||||||
|
if msg.event <> None:
|
||||||
|
log ("get " + str(msg.event.type) + ": " + str(msg.event.fromplayer))
|
||||||
|
Game.evMgr.postEvent(msg.event)
|
||||||
|
|
||||||
|
def sendEvent(self, event):
|
||||||
|
if (self.address <> None) and (self.transport <> None) and (event.fromplayer == Game.myplayer):
|
||||||
|
log ("send " + str(event.type))
|
||||||
|
self.mysequence = self.mysequence + 1
|
||||||
|
s = StringIO.StringIO()
|
||||||
|
cPickle.Pickler(s).dump(TFTMessage(self.mysequence, event))
|
||||||
|
self.transport.write(s.getvalue(), self.address)
|
||||||
|
|
||||||
|
def connectTransport(self, event):
|
||||||
|
Game.evMgr.postEvent(HelloEvent())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050424135832:Protocol
|
||||||
|
#@-others
|
||||||
|
#@-node:jpenner.20050319143816:Networking
|
||||||
|
#@+node:jpenner.20050604112932:Menu
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050605142055:Base Menu
|
||||||
|
class BaseMenu(WidgetWindow):
|
||||||
|
def __init__(self):
|
||||||
|
WidgetWindow.__init__(self, Game.screen)
|
||||||
|
|
||||||
|
self.menuLayout()
|
||||||
|
|
||||||
|
def onEnter(self):
|
||||||
|
self.invalidaterect()
|
||||||
|
self.eventproc( pygame.event.Event( NOEVENT, {} ) )
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == QUIT:
|
||||||
|
reactor.stop()
|
||||||
|
try:
|
||||||
|
self.eventproc(event)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#@-node:jpenner.20050605142055:Base Menu
|
||||||
|
#@+node:jpenner.20050605102056:Main Menu
|
||||||
|
class MainMenu(BaseMenu):
|
||||||
|
def menuLayout(self):
|
||||||
|
#@ << Menu layout >>
|
||||||
|
#@+node:jpenner.20050605102056.1:<< Menu layout >>
|
||||||
|
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(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(self.serverPort)
|
||||||
|
self.addwidget(ButtonClass(self, self.startServer, (120, 240, 400, 30), "Start Server"))
|
||||||
|
|
||||||
|
self.addwidget(TextClass(self, (120, 310, 160, 20), "Server Address:"))
|
||||||
|
self.clientAddr = EditClass(self, None, (280, 310, 240, 20))
|
||||||
|
self.addwidget(self.clientAddr)
|
||||||
|
self.addwidget(TextClass(self, (120, 335, 60, 20), "Port:"))
|
||||||
|
self.clientPort = EditClass(self, None, (180, 335, 60, 20), "7554")
|
||||||
|
self.addwidget(self.clientPort)
|
||||||
|
self.addwidget(ButtonClass(self, self.startClient, (120, 360, 400, 30), "Start Client"))
|
||||||
|
#@-node:jpenner.20050605102056.1:<< Menu layout >>
|
||||||
|
#@nl
|
||||||
|
|
||||||
|
def startSingle(self):
|
||||||
|
Game.myplayer = SINGLE_PLAYER
|
||||||
|
Game.isClient = False
|
||||||
|
Game.rules.infinitehits = True
|
||||||
|
Game.gameMgr.changeState(Game.gameMgr.STATE_SINGLE_PLAYER)
|
||||||
|
|
||||||
|
def startServer(self):
|
||||||
|
Game.myplayer = 1
|
||||||
|
Game.isClient = False
|
||||||
|
Game.ServerPort = int(self.serverPort.text)
|
||||||
|
Game.gameMgr.changeState(Game.gameMgr.STATE_WAIT_FOR_CLIENT)
|
||||||
|
|
||||||
|
def startClient(self):
|
||||||
|
Game.myplayer = 2
|
||||||
|
Game.isClient = True
|
||||||
|
Game.ServerPort = int(self.clientPort.text)
|
||||||
|
Game.ServerIP = self.clientAddr.text
|
||||||
|
Game.gameMgr.changeState(Game.gameMgr.STATE_CONNECT)
|
||||||
|
#@-node:jpenner.20050605102056:Main Menu
|
||||||
|
#@+node:jpenner.20050605173506:Server Wait Screen
|
||||||
|
class ServerWait(BaseMenu):
|
||||||
|
def menuLayout(self):
|
||||||
|
self.addwidget(TextClass(self, (120, 180, 400, 40), "Waiting For Client...", 48))
|
||||||
|
self.addwidget(ButtonClass(self, self.cancel, (120, 360, 400, 30), "Cancel"))
|
||||||
|
|
||||||
|
self.connected = False
|
||||||
|
Game.evMgr.registerHandler(EV_HELLO, self.connect)
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
Game.gameMgr.changeState(Game.gameMgr.STATE_MENU)
|
||||||
|
|
||||||
|
def connect(self, ev):
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
BaseMenu.tick(self)
|
||||||
|
if self.connected:
|
||||||
|
self.connected = False
|
||||||
|
Game.gameMgr.changeState(Game.gameMgr.STATE_NETWORK_GAME)
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050605173506:Server Wait Screen
|
||||||
|
#@+node:jpenner.20050605180040:Client Wait Screen
|
||||||
|
class ClientWait(BaseMenu):
|
||||||
|
def menuLayout(self):
|
||||||
|
self.addwidget(TextClass(self, (120, 180, 400, 40), "Contacting Server...", 48))
|
||||||
|
self.addwidget(ButtonClass(self, self.cancel, (120, 360, 400, 30), "Cancel"))
|
||||||
|
|
||||||
|
self.connected = False
|
||||||
|
Game.evMgr.registerHandler(EV_BALLPOS, self.connect)
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
Game.gameMgr.changeState(Game.gameMgr.STATE_MENU)
|
||||||
|
|
||||||
|
def connect(self, ev):
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
BaseMenu.tick(self)
|
||||||
|
if self.connected:
|
||||||
|
self.connected = False
|
||||||
|
Game.gameMgr.changeState(Game.gameMgr.STATE_NETWORK_GAME)
|
||||||
|
else:
|
||||||
|
Game.network.sendEvent(ConnectEvent())
|
||||||
|
|
||||||
|
#@-node:jpenner.20050605180040:Client Wait Screen
|
||||||
|
#@-others
|
||||||
|
#@-node:jpenner.20050604112932:Menu
|
||||||
|
#@+node:jpenner.20050305121157:Game
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050604175241:Graphics
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050604192205:Generic Graphics Manager
|
||||||
|
class GameGraphicsMgr:
|
||||||
|
def __init__(self):
|
||||||
|
self.all = pygame.sprite.RenderUpdates()
|
||||||
|
|
||||||
|
self.bkg = pygame.Surface((SCREENRECT.width, SCREENRECT.height))
|
||||||
|
self.bkg.fill(pygame.color.Color("black"))
|
||||||
|
|
||||||
|
self.trackedSprites = []
|
||||||
|
|
||||||
|
def trackSprite(self, sprite, spriteToTrack):
|
||||||
|
self.trackedSprites.append({'sprite': sprite, 'spriteToTrack': spriteToTrack})
|
||||||
|
|
||||||
|
def clearScreen(self):
|
||||||
|
Game.screen.set_clip()
|
||||||
|
Game.screen.fill(pygame.color.Color("black"))
|
||||||
|
pygame.display.update()
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
for item in self.trackedSprites:
|
||||||
|
item['sprite'].rect.centerx = item['spriteToTrack'].rect.centerx
|
||||||
|
item['sprite'].rect.centery = item['spriteToTrack'].rect.centery
|
||||||
|
|
||||||
|
self.all.clear(Game.screen, self.bkg)
|
||||||
|
self.all.update()
|
||||||
|
dirty = self.all.draw(Game.screen)
|
||||||
|
pygame.display.update(dirty)
|
||||||
|
|
||||||
|
#@-node:jpenner.20050604192205:Generic Graphics Manager
|
||||||
|
#@+node:jpenner.20050604175241.1:TFT Graphics Manager
|
||||||
|
class TFTGraphicsMgr(GameGraphicsMgr):
|
||||||
|
def __init__(self):
|
||||||
|
GameGraphicsMgr.__init__(self)
|
||||||
|
Floor.containers = self.all
|
||||||
|
Net.containers = self.all
|
||||||
|
Ball.containers = self.all
|
||||||
|
ShotLine.containers = self.all
|
||||||
|
|
||||||
|
Game.ball = Ball(BALL_STARTX, BALL_STARTY)
|
||||||
|
Game.floor = Floor()
|
||||||
|
Game.net = Net()
|
||||||
|
self.shotLine = ShotLine()
|
||||||
|
|
||||||
|
self.trackSprite(self.shotLine, Game.ball)
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
self.shotLine.updateAngle()
|
||||||
|
GameGraphicsMgr.tick(self)
|
||||||
|
#@-node:jpenner.20050604175241.1:TFT Graphics Manager
|
||||||
|
#@+node:jpenner.20050305120654:Sprites
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050305112032:Floor
|
||||||
|
class Floor(pygame.sprite.Sprite):
|
||||||
|
def __init__(self):
|
||||||
|
pygame.sprite.Sprite.__init__(self, self.containers)
|
||||||
|
self.image = pygame.Surface((SCREENRECT.width - (SCREENRECT.width / 8), SCREENRECT.height / 96))
|
||||||
|
self.image.fill(pygame.color.Color("white"))
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.reloading = 0
|
||||||
|
self.rect.centerx = SCREENRECT.centerx
|
||||||
|
self.rect.bottom = SCREENRECT.bottom * 0.875
|
||||||
|
self.origtop = self.rect.top
|
||||||
|
self.facing = -1
|
||||||
|
|
||||||
|
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050305112032:Floor
|
||||||
|
#@+node:jpenner.20050305120626:Net
|
||||||
|
class Net(pygame.sprite.Sprite):
|
||||||
|
def __init__(self):
|
||||||
|
pygame.sprite.Sprite.__init__(self, self.containers)
|
||||||
|
self.image = pygame.Surface((SCREENRECT.width / 128, SCREENRECT.height / 12))
|
||||||
|
self.image.fill(pygame.color.Color("white"))
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.reloading = 0
|
||||||
|
self.rect.centerx = SCREENRECT.centerx
|
||||||
|
self.rect.bottom = SCREENRECT.bottom * 0.875
|
||||||
|
self.origtop = self.rect.top
|
||||||
|
self.facing = -1
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050305120626:Net
|
||||||
|
#@+node:jpenner.20050427175728:Ball
|
||||||
|
class Ball(pygame.sprite.Sprite):
|
||||||
|
def __init__(self, x, y):
|
||||||
|
pygame.sprite.Sprite.__init__(self, self.containers)
|
||||||
|
self.image = pygame.Surface((SCREENRECT.width / 128, SCREENRECT.height / 96))
|
||||||
|
self.image.fill(pygame.color.Color("white"))
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.reloading = 0
|
||||||
|
self.rect.centerx = x
|
||||||
|
self.rect.centery = y
|
||||||
|
self.origtop = self.rect.top
|
||||||
|
self.facing = -1
|
||||||
|
|
||||||
|
def currentPlayer(self):
|
||||||
|
if self.rect.centerx < Game.net.rect.centerx:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050427175728:Ball
|
||||||
|
#@+node:jpenner.20050305123236:Shot Line
|
||||||
|
class ShotLine(pygame.sprite.Sprite):
|
||||||
|
def __init__(self):
|
||||||
|
pygame.sprite.Sprite.__init__(self, self.containers)
|
||||||
|
self.image = pygame.Surface((SCREENRECT.width / 32, SCREENRECT.height / 24), SRCALPHA)
|
||||||
|
self.image.set_colorkey(pygame.color.Color("purple"))
|
||||||
|
self.rect = self.image.get_rect()
|
||||||
|
self.updateAngle()
|
||||||
|
self.reloading = 0
|
||||||
|
self.origtop = self.rect.top
|
||||||
|
self.facing = -1
|
||||||
|
|
||||||
|
def updateAngle(self):
|
||||||
|
angle = makeAngle(pygame.mouse.get_pos())
|
||||||
|
self.image.fill(pygame.color.Color("purple")) # clear
|
||||||
|
pygame.draw.line(self.image, pygame.color.Color("white"),
|
||||||
|
anglePos(self.image.get_rect(), angle, 6), anglePos(self.image.get_rect(),angle,12))
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050305123236:Shot Line
|
||||||
|
#@-others
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050305120654:Sprites
|
||||||
|
#@-others
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050604175241:Graphics
|
||||||
|
#@+node:jpenner.20050320112219:Physics
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050424152556:Physics Manager
|
||||||
|
class PhysicsMgr:
|
||||||
|
def __init__(self):
|
||||||
|
self.gamePhysics = PhysicsEngine()
|
||||||
|
self.netPhysics = NetworkPhysicsEngine()
|
||||||
|
|
||||||
|
Game.evMgr.registerHandler(EV_PLAYER_UPDATE, self.switchEngines)
|
||||||
|
Game.evMgr.registerHandler(EV_PLAYER_SWITCH, self.switchToGame)
|
||||||
|
|
||||||
|
def onEnter(self):
|
||||||
|
if Game.currentplayer == Game.myplayer:
|
||||||
|
self.current = self.gamePhysics
|
||||||
|
else:
|
||||||
|
self.current = self.netPhysics
|
||||||
|
self.lastSeq = -1
|
||||||
|
|
||||||
|
def switchEngines(self, ev):
|
||||||
|
if Game.ball.currentPlayer() <> Game.myplayer:
|
||||||
|
self.current = self.netPhysics
|
||||||
|
self.current.switchStarted = True
|
||||||
|
else:
|
||||||
|
self.current = self.gamePhysics
|
||||||
|
|
||||||
|
def switchToGame(self, ev):
|
||||||
|
if ev.fromplayer <> Game.myplayer:
|
||||||
|
if ev.seq > self.lastSeq:
|
||||||
|
self.lastSeq = ev.seq
|
||||||
|
self.gamePhysics.resync(ev)
|
||||||
|
Game.evMgr.postEvent(PlayerUpdateEvent())
|
||||||
|
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
self.current.tick()
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050424152556:Physics Manager
|
||||||
|
#@+node:jpenner.20050306103246:Game Physics
|
||||||
|
class PhysicsEngine:
|
||||||
|
def __init__(self):
|
||||||
|
Game.evMgr.registerHandler(EV_HIT, self.hitHandler)
|
||||||
|
Game.evMgr.registerHandler(EV_SERVE, self.serveHandler)
|
||||||
|
|
||||||
|
self.xvel = 0
|
||||||
|
self.yvel = 0
|
||||||
|
self.stopped = True
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
# only do gravity / collision detection if ball is moving
|
||||||
|
if not self.stopped:
|
||||||
|
# Gravity
|
||||||
|
self.yvel += GRAVITY
|
||||||
|
|
||||||
|
#@ << Floor collision >>
|
||||||
|
#@+node:jpenner.20050310185348:<< Floor collision >>
|
||||||
|
if (Game.ball.rect.bottom + self.yvel) > Game.floor.rect.top:
|
||||||
|
self.yvel = -abs(self.yvel) + FRICTION
|
||||||
|
if self.yvel > 0:
|
||||||
|
self.yvel = 0
|
||||||
|
self.xvel = 0
|
||||||
|
self.stopped = True
|
||||||
|
|
||||||
|
Game.evMgr.postEvent(BounceEvent())
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050310185348:<< Floor collision >>
|
||||||
|
#@nl
|
||||||
|
#@ << Net collision >>
|
||||||
|
#@+node:jpenner.20050310185348.1:<< Net collision >>
|
||||||
|
if (( ((Game.ball.rect.right < Game.net.rect.left) and ((Game.ball.rect.right + self.xvel) >= Game.net.rect.left) ) or
|
||||||
|
((Game.ball.rect.left > Game.net.rect.right) and ((Game.ball.rect.left + self.xvel) <= Game.net.rect.right) ) ) and
|
||||||
|
((Game.ball.rect.bottom + self.yvel) > Game.net.rect.top)):
|
||||||
|
self.xvel = -self.xvel
|
||||||
|
|
||||||
|
#@-node:jpenner.20050310185348.1:<< Net collision >>
|
||||||
|
#@nl
|
||||||
|
#@ << Switch players >>
|
||||||
|
#@+node:jpenner.20050310185414:<< Switch players >>
|
||||||
|
if ((Game.ball.rect.centerx < Game.net.rect.centerx) and ((Game.ball.rect.centerx + self.xvel) >= Game.net.rect.centerx) or
|
||||||
|
(Game.ball.rect.centerx >= Game.net.rect.centerx) and ((Game.ball.rect.centerx + self.xvel) < Game.net.rect.centerx)):
|
||||||
|
Game.evMgr.postEvent(PlayerUpdateEvent())
|
||||||
|
|
||||||
|
#@-node:jpenner.20050310185414:<< Switch players >>
|
||||||
|
#@nl
|
||||||
|
|
||||||
|
Game.ball.rect.centerx += self.xvel
|
||||||
|
Game.ball.rect.centery += self.yvel
|
||||||
|
|
||||||
|
Game.evMgr.postEvent(BallPosEvent(Game.ball.rect.centerx, Game.ball.rect.centery))
|
||||||
|
Game.switchEv = PlayerSwitchEvent(self.xvel, self.yvel, Game.ball.rect.centerx, Game.ball.rect.centery, self.stopped)
|
||||||
|
|
||||||
|
def hitHandler(self,hitEvent):
|
||||||
|
self.xvel = hitEvent.xvel
|
||||||
|
self.yvel = hitEvent.yvel
|
||||||
|
self.stopped = False
|
||||||
|
|
||||||
|
def serveHandler(self, ev):
|
||||||
|
self.stopped = True
|
||||||
|
|
||||||
|
def resync(self, ev):
|
||||||
|
self.xvel = ev.xvel
|
||||||
|
self.yvel = ev.yvel
|
||||||
|
Game.ball.rect.centerx = ev.xpos
|
||||||
|
Game.ball.rect.centery = ev.ypos
|
||||||
|
self.stopped = ev.stopped
|
||||||
|
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050306103246:Game Physics
|
||||||
|
#@+node:jpenner.20050320112219.1:Network Physics
|
||||||
|
class NetworkPhysicsEngine:
|
||||||
|
def __init__(self):
|
||||||
|
Game.evMgr.registerHandler(EV_BALLPOS, self.updatePos)
|
||||||
|
self.switchStarted = False
|
||||||
|
|
||||||
|
def updatePos(self, ev):
|
||||||
|
if (ev.fromplayer <> Game.myplayer):
|
||||||
|
self.switchStarted = False
|
||||||
|
Game.ball.rect.centerx = ev.x
|
||||||
|
Game.ball.rect.centery = ev.y
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
log ("netphysics")
|
||||||
|
if self.switchStarted:
|
||||||
|
Game.evMgr.postEvent(Game.switchEv)
|
||||||
|
|
||||||
|
#@-node:jpenner.20050320112219.1:Network Physics
|
||||||
|
#@-others
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050320112219:Physics
|
||||||
|
#@+node:jpenner.20050307180329:Sound
|
||||||
|
class SoundEngine:
|
||||||
|
def __init__(self):
|
||||||
|
f = { EV_HIT: 'hit.wav',
|
||||||
|
EV_BOUNCE: 'bounce.wav',
|
||||||
|
EV_SCORE: 'score.wav',
|
||||||
|
EV_HELLO: 'connect.wav' }
|
||||||
|
|
||||||
|
self.sound = {}
|
||||||
|
for evtype, filename in f.iteritems():
|
||||||
|
try:
|
||||||
|
self.sound[evtype] = pygame.mixer.Sound('data/' + filename)
|
||||||
|
Game.evMgr.registerHandler(evtype, self.noise)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def noise(self, ev):
|
||||||
|
self.sound[ev.type].play()
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050307180329:Sound
|
||||||
|
#@+node:jpenner.20050312135503:Rules
|
||||||
|
class RuleManager:
|
||||||
|
def __init__(self):
|
||||||
|
Game.evMgr.registerHandler(EV_CLICK, self.clickHandler)
|
||||||
|
Game.evMgr.registerHandler(EV_SERVE, self.serveHandler)
|
||||||
|
Game.evMgr.registerHandler(EV_PLAYER_UPDATE, self.updateHandler)
|
||||||
|
self.playerhit = False
|
||||||
|
self.infinitehits = False
|
||||||
|
Game.currentplayer = 1
|
||||||
|
|
||||||
|
def clickHandler(self, ev):
|
||||||
|
if not self.playerhit and (ev.player == Game.currentplayer or ev.player == SINGLE_PLAYER):
|
||||||
|
Game.evMgr.postEvent(HitEvent(ev.xvel, ev.yvel))
|
||||||
|
if not self.infinitehits:
|
||||||
|
self.playerhit = True
|
||||||
|
|
||||||
|
def updateHandler(self, ev):
|
||||||
|
self.playerhit = False
|
||||||
|
Game.currentplayer = Game.ball.currentPlayer()
|
||||||
|
|
||||||
|
def serveHandler(self, ev):
|
||||||
|
Game.ball.rect.centerx = BALL_STARTX
|
||||||
|
Game.ball.rect.centery = BALL_STARTY
|
||||||
|
Game.evMgr.postEvent(PlayerUpdateEvent())
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050312135503:Rules
|
||||||
|
#@+node:jpenner.20050310200258:Input
|
||||||
|
class InputManager:
|
||||||
|
def tick(self):
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == QUIT:
|
||||||
|
reactor.stop()
|
||||||
|
self.sdl_event(event)
|
||||||
|
|
||||||
|
def sdl_event(self, event):
|
||||||
|
if event.type == MOUSEBUTTONUP:
|
||||||
|
angle = makeAngle(event.pos)
|
||||||
|
Game.evMgr.postEvent( ClickEvent(math.cos(angle) * 12, math.sin(angle) * 9, Game.myplayer) )
|
||||||
|
|
||||||
|
if event.type == KEYUP:
|
||||||
|
Game.evMgr.postEvent( ServeEvent() )
|
||||||
|
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050310200258:Input
|
||||||
|
#@+node:jpenner.20050305122430:Game Loop
|
||||||
|
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050606072251:State Machine
|
||||||
|
class GameState:
|
||||||
|
def __init__(self, manager, onenter = None, onexit = None):
|
||||||
|
def doNothing(): pass
|
||||||
|
|
||||||
|
if manager <> None:
|
||||||
|
self.tick = manager.tick
|
||||||
|
else:
|
||||||
|
self.tick = doNothing
|
||||||
|
|
||||||
|
if onenter <> None:
|
||||||
|
self.enter = onenter
|
||||||
|
else:
|
||||||
|
self.enter = doNothing
|
||||||
|
|
||||||
|
if onexit <> None:
|
||||||
|
self.exit = onexit
|
||||||
|
else:
|
||||||
|
self.exit = doNothing
|
||||||
|
|
||||||
|
class StateMachine:
|
||||||
|
def __init__(self, states, initialState = 0):
|
||||||
|
self.state = initialState
|
||||||
|
self.states = states
|
||||||
|
self.states[self.state].enter()
|
||||||
|
self.newstate = -1
|
||||||
|
|
||||||
|
def changeState(self, newstate):
|
||||||
|
# Don't change states in the middle of a tick!
|
||||||
|
self.newstate = newstate
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
if self.newstate >= 0:
|
||||||
|
self.states[self.state].exit()
|
||||||
|
self.state = self.newstate
|
||||||
|
self.states[self.state].enter()
|
||||||
|
self.newstate = -1
|
||||||
|
|
||||||
|
self.states[self.state].tick()
|
||||||
|
|
||||||
|
class GameLoop:
|
||||||
|
def __init__(self, managers):
|
||||||
|
self.managers = managers
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
for manager in self.managers:
|
||||||
|
manager.tick()
|
||||||
|
#@-node:jpenner.20050606072251:State Machine
|
||||||
|
#@+node:jpenner.20050606072251.1:Game Manager
|
||||||
|
class GameMgr (StateMachine):
|
||||||
|
def __init__(self):
|
||||||
|
self.STATE_MENU = 0
|
||||||
|
self.STATE_NETWORK_GAME = 1
|
||||||
|
self.STATE_SINGLE_PLAYER = 2
|
||||||
|
self.STATE_WAIT_FOR_CLIENT = 3
|
||||||
|
self.STATE_CONNECT = 4
|
||||||
|
|
||||||
|
inputMgr = InputManager()
|
||||||
|
self.graphicsMgr = TFTGraphicsMgr()
|
||||||
|
self.physicsMgr = PhysicsMgr()
|
||||||
|
|
||||||
|
mainMenu = MainMenu()
|
||||||
|
self.serverWait = ServerWait()
|
||||||
|
self.clientWait = ClientWait()
|
||||||
|
|
||||||
|
StateMachine.__init__(self,
|
||||||
|
[GameState(MainMenu(), mainMenu.onEnter),
|
||||||
|
GameState(GameLoop([inputMgr, Game.evMgr, self.physicsMgr, self.graphicsMgr]), self.gameEnter),
|
||||||
|
GameState(GameLoop([inputMgr, 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)
|
||||||
|
])
|
||||||
|
|
||||||
|
def gameEnter(self):
|
||||||
|
self.graphicsMgr.clearScreen()
|
||||||
|
self.physicsMgr.onEnter()
|
||||||
|
|
||||||
|
def clientEnter(self):
|
||||||
|
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 serverEnter(self):
|
||||||
|
Game.network = TFTProtocol()
|
||||||
|
Game.port = reactor.listenUDP(Game.ServerPort, Game.network)
|
||||||
|
log ("Listening on " + str(Game.ServerPort))
|
||||||
|
self.serverWait.onEnter()
|
||||||
|
|
||||||
|
def networkExit(self):
|
||||||
|
if (self.newstate == self.STATE_MENU) and (Game.port <> None): # cancelled
|
||||||
|
Game.port.stopListening()
|
||||||
|
|
||||||
|
#@-node:jpenner.20050606072251.1:Game Manager
|
||||||
|
#@-others
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050305122430:Game Loop
|
||||||
|
#@+node:jpenner.20050319125841:Setup
|
||||||
|
def main():
|
||||||
|
pygame.init()
|
||||||
|
|
||||||
|
startLogging('tennis.log')
|
||||||
|
|
||||||
|
Game.screen = pygame.display.set_mode(SCREENRECT.size, DOUBLEBUF, 16)
|
||||||
|
|
||||||
|
Game.evMgr = EventManager()
|
||||||
|
Game.sound = SoundEngine()
|
||||||
|
Game.rules = RuleManager()
|
||||||
|
Game.gameMgr = GameMgr()
|
||||||
|
|
||||||
|
task.LoopingCall(Game.gameMgr.tick).start(0.03)
|
||||||
|
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
#cleanup
|
||||||
|
stopLogging()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050319125841:Setup
|
||||||
|
#@-others
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050305121157:Game
|
||||||
|
#@-others
|
||||||
|
|
||||||
|
if __name__ == '__main__': main()
|
||||||
|
#@nonl
|
||||||
|
#@-node:jpenner.20050305105206:@thin TennisForTwo.py
|
||||||
|
#@-leo
|
BIN
data/bounce.wav
Normal file
BIN
data/bounce.wav
Normal file
Binary file not shown.
BIN
data/connect.wav
Normal file
BIN
data/connect.wav
Normal file
Binary file not shown.
BIN
data/hit.wav
Normal file
BIN
data/hit.wav
Normal file
Binary file not shown.
BIN
data/score.wav
Normal file
BIN
data/score.wav
Normal file
Binary file not shown.
46
pygame2app.py
Normal file
46
pygame2app.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#@+leo-ver=4-thin
|
||||||
|
#@+node:jpenner.20050604144534:@thin pygame2app.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 py2app
|
||||||
|
|
||||||
|
#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,
|
||||||
|
app=[script],
|
||||||
|
data_files=[("data", glob.glob("data\\*"))]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#@-node:jpenner.20050604144534:@thin pygame2app.py
|
||||||
|
#@-leo
|
40
pygame2exe.py
Normal file
40
pygame2exe.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#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\\*"))]
|
||||||
|
)
|
||||||
|
|
1113
widgets.py
Normal file
1113
widgets.py
Normal file
File diff suppressed because it is too large
Load diff
131
widgetsdemo.py
Normal file
131
widgetsdemo.py
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
#@+leo-ver=4-thin
|
||||||
|
#@+node:jpenner.20050604113053:@thin widgetsdemo.py
|
||||||
|
#@@language python
|
||||||
|
#@<< widgetsdemo declarations >>
|
||||||
|
#@+node:jpenner.20050604113053.1:<< widgetsdemo declarations >>
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# WidgetsDemo.py demonstrates the usage Widgets.py
|
||||||
|
# Copyright (C) 2003 Michael Leonhard
|
||||||
|
# http://tamale.net/
|
||||||
|
#
|
||||||
|
# version 1.0 RC1 (2003/07/06 00:42)
|
||||||
|
|
||||||
|
import pygame, pygame.display, pygame.event, pygame.time, pygame.font, pygame.draw
|
||||||
|
from pygame.locals import *
|
||||||
|
import math, string
|
||||||
|
from widgets import *
|
||||||
|
|
||||||
|
#@-node:jpenner.20050604113053.1:<< widgetsdemo declarations >>
|
||||||
|
#@nl
|
||||||
|
#@+others
|
||||||
|
#@+node:jpenner.20050604113053.2:class WidgetsDemo
|
||||||
|
class WidgetsDemo( WidgetWindow ):
|
||||||
|
#@ @+others
|
||||||
|
#@+node:jpenner.20050604113053.3:__init__
|
||||||
|
def __init__( self ):
|
||||||
|
"""Initialize Demo Class"""
|
||||||
|
# instead of pygame.init(), initialize modules manually to
|
||||||
|
# avoid initing pygame.sound
|
||||||
|
pygame.display.init()
|
||||||
|
pygame.font.init()
|
||||||
|
|
||||||
|
# setup screen
|
||||||
|
screen = pygame.display.set_mode( (640, 480), DOUBLEBUF )
|
||||||
|
pygame.display.set_caption( 'WidgetsDemo' )
|
||||||
|
|
||||||
|
# request regular event for updating animation
|
||||||
|
self.DRAWEVENT = USEREVENT + 1
|
||||||
|
pygame.time.set_timer( self.DRAWEVENT, 33 ) #33 == 30fps
|
||||||
|
|
||||||
|
# filter events
|
||||||
|
badevents = [NOEVENT, ACTIVEEVENT, JOYAXISMOTION, JOYBALLMOTION, JOYHATMOTION, JOYBUTTONDOWN ,JOYBUTTONUP, VIDEORESIZE, SYSWMEVENT, NUMEVENTS]
|
||||||
|
goodevents = [self.DRAWEVENT, KEYDOWN, KEYUP, MOUSEMOTION, MOUSEBUTTONDOWN, MOUSEBUTTONUP, QUIT ]
|
||||||
|
pygame.event.set_blocked( badevents )
|
||||||
|
|
||||||
|
# initialize the WidgetWindow base class
|
||||||
|
WidgetWindow.__init__( self, screen )
|
||||||
|
|
||||||
|
# create special widgets
|
||||||
|
edit = EditClass( self, self.editaction, (325, 300, 265, 25), "text" )
|
||||||
|
self.page = PageClass( self, (325, 25, 265, 275), GRAY )
|
||||||
|
|
||||||
|
# put the widgets in the window
|
||||||
|
self.addwidget( MultiLineTextClass( self, (25, 25, 250, 145), "MultiLineTextClass\n(transparent)\nHas automatic word wrapping.", 36 ) )
|
||||||
|
self.addwidget( MultiLineTextClass( self, (25, 195, 250, 145), "MultiLineTextClass\n(with background)\nHas automatic word wrapping.", 36, WHITE, BLACK ) )
|
||||||
|
self.addwidget( EditClass( self, self.editaction, (25, 350, 150, 30), "second edit box" ), TABTARGET )
|
||||||
|
self.addwidget( TextClass( self, (25, 400, 590, 19), "TextClass (transparent)", 20 ) )
|
||||||
|
self.addwidget( TextClass( self, (25, 440, 590, 19), "TextClass (with background)", 20, WHITE, BLACK ) )
|
||||||
|
self.addwidget( self.page )
|
||||||
|
self.addwidget( edit, TABTARGET )
|
||||||
|
self.addwidget( ButtonClass( self, self.buttonaction, (205, 110, 200, 105), "This button overlaps" ) )
|
||||||
|
|
||||||
|
# set keyboard focus to the edit widget
|
||||||
|
edit.focus()
|
||||||
|
|
||||||
|
# initial screen draw
|
||||||
|
self.eventproc( pygame.event.Event( NOEVENT, {} ) )
|
||||||
|
|
||||||
|
# animation data
|
||||||
|
self.animrect = Rect( (325, 350, 265, 50) )
|
||||||
|
self.animline = Rect( self.animrect )
|
||||||
|
self.animline.width = 5
|
||||||
|
self.animline.left = self.animrect.left
|
||||||
|
#@-node:jpenner.20050604113053.3:__init__
|
||||||
|
#@+node:jpenner.20050604113053.4:loop
|
||||||
|
def loop( self ):
|
||||||
|
"""Program loop"""
|
||||||
|
while 1:
|
||||||
|
# get the next event
|
||||||
|
event = pygame.event.wait()
|
||||||
|
# Redraw the animation
|
||||||
|
if event.type == self.DRAWEVENT:
|
||||||
|
# get all pending DRAWEVENTs
|
||||||
|
pending = pygame.event.get( self.DRAWEVENT )
|
||||||
|
# number of events we are doing
|
||||||
|
num = len( pending ) + 1
|
||||||
|
|
||||||
|
# reset the clipping region
|
||||||
|
self.screen.set_clip()
|
||||||
|
# erase the animation
|
||||||
|
self.screen.fill( self.background, self.animline )
|
||||||
|
|
||||||
|
# update the animation
|
||||||
|
self.animline.left += 1 * num
|
||||||
|
# line is outside the region
|
||||||
|
while not self.animline.colliderect( self.animrect ):
|
||||||
|
# move it back to the left
|
||||||
|
self.animline.left -= self.animrect.width
|
||||||
|
# draw the animation
|
||||||
|
self.screen.fill( RED, self.animline )
|
||||||
|
# flip the display
|
||||||
|
pygame.display.update()
|
||||||
|
|
||||||
|
# user pressed the X button to close the window
|
||||||
|
elif event.type == QUIT: break
|
||||||
|
# pass the even to the widgets
|
||||||
|
else: self.eventproc( event )
|
||||||
|
|
||||||
|
#clean up
|
||||||
|
pygame.time.set_timer( self.DRAWEVENT, 0 )
|
||||||
|
pygame.quit()
|
||||||
|
#@-node:jpenner.20050604113053.4:loop
|
||||||
|
#@+node:jpenner.20050604113053.5:editaction
|
||||||
|
def editaction( self, widget ):
|
||||||
|
"""Function called when enter key is pressed"""
|
||||||
|
self.page.append( widget.text )
|
||||||
|
widget.settext( "" )
|
||||||
|
#@-node:jpenner.20050604113053.5:editaction
|
||||||
|
#@+node:jpenner.20050604113053.6:buttonaction
|
||||||
|
def buttonaction( self ):
|
||||||
|
"""Function called when button is pressed"""
|
||||||
|
self.page.append( "ACTION" )
|
||||||
|
#@-node:jpenner.20050604113053.6:buttonaction
|
||||||
|
#@-others
|
||||||
|
#@-node:jpenner.20050604113053.2:class WidgetsDemo
|
||||||
|
#@-others
|
||||||
|
|
||||||
|
demo = WidgetsDemo()
|
||||||
|
demo.loop()
|
||||||
|
#@-node:jpenner.20050604113053:@thin widgetsdemo.py
|
||||||
|
#@-leo
|
Loading…
Reference in a new issue