| action | function | fields | description |
|---|---|---|---|
| join | add player | username,
password, | adds new player to gameboard |
| update | update player |
player, password, | updates player velocity |
| status | show status | none required | gets player status, including player name, color, position, and velocity |
| move | play | none required | calculates player position since the last update |
| remove | remove player | player, password | removes player from gameboard |
All actions return HTML content.
The join action uses the following HTML form: join.html.
The function looks up the user in the table of users. The color and location of the player is also taken from this table.
The update action takes form input (either GET or POST). The URL can be entered manually as:
https://johnloomis.org/python/db/gameboard.py?action=update&player=name&password=***&vx=vx&vy=vy
The status action returns a list of data fields for each player. The URL can be entered manually as:
https://johnloomis.org/python/db/gameboard.py?action=status
Follow this link
Example output:
"2008-04-05 18:24:48" "one" 1 255 0 0 94.29 334.66 -40 -10 "update" "2008-04-05 18:24:48" "two" 2 0 255 0 45.64 64.46 20 30 "move" "2008-04-05 18:24:48" "three" 4 0 0 255 38.82 125.64 10 20 "update"
The move action returns a list of data fields for each player. The URL can be entered manually as:
https://johnloomis.org/python/db/gameboard.py?action=move
Follow this link
Example output:
Datetime: 2008-04-05 19:49:22 id 1 94.29 334.66 -40 -10 id 2 45.64 64.46 20 30 id 4 38.82 125.64 10 20
The status and move actions are used by
GameBoard.java to display player positions, updated
every couple of seconds.
See the GameBoard program documentation.
gameboard.pygame.pylogon.pygameboard.pyThis Python CGI script manages the database interaction.
001: #!/usr/bin/python
002: import cgi, cgitb, sys, math
003: import MySQLdb
004: import dbname
005: import logon
006: import game
007:
008:
009: def add_player(form,cur):
010: uid = logon.logon(form,cur)
011: if not uid:
012: print '<p>login failed.'
013: print '</html>'
014: sys.exit()
015:
016: try:
017: cur.execute("SELECT red, green, blue, xloc, yloc FROM users WHERE uid = %d" % uid)
018: rows = cur.fetchall()
019: if cur.rowcount==0:
020: print '<p>user data not found'
021: print '</html>'
022: sys.exit()
023: row = rows[0]
024: username = form["username"].value
025: password = form["password"].value
026: player = form["player"].value
027: if not player: player="player"
028: xpos = row[3]
029: ypos = row[4]
030: if xpos<0 or xpos>400: xpos=200
031: if ypos<0 or ypos>400: ypos=200
032: rs = (username, password, player, row[0], row[1], row[2], xpos, ypos)
033: cur.execute("""INSERT INTO gameboard ( username, password, player, modified,
034: red, green, blue, px, py, vx, vy, status )
035: VALUES (
036: '%s',
037: '%s',
038: '%s',
039: now(),
040: %d, %d, %d,
041: %g, %g, 20, 30, 'join'
042: )""" % rs )
043: print '<p>player <b>%s</b> has been added to the gameboard.' % player
044: except MySQLdb.Error, e:
045: print e
046: print '</html>'
047: sys.exit()
048:
049: def remove_player(form,cur):
050: try:
051: player = form['player'].value
052: password = form['password'].value
053: cur.execute("DELETE FROM gameboard WHERE player='%s' AND password='%s'" %
054: (player,password) )
055: print 'player <b>%s</b> removed from gameboard' % player
056: except MySQLdb.Error, e:
057: print e
058:
059:
060: def update_player(form,cur):
061: try:
062: player = form['player'].value
063: password = form['password'].value
064: vx=float(form['vx'].value)
065: vy=float(form['vy'].value)
066: # limit velocity to 140
067: vn = math.hypot(vx,vy)/140.0
068: if (vn>1.0):
069: vx = vx/vn
070: vy = vy/vn
071: rs = (vx,vy,player,password)
072: cur.execute ("UPDATE gameboard SET vx=%g, vy=%g, status='update', modified=now() where player='%s' and password='%s'" % rs)
073: print '<p>player <b>%s</b> velocity set to (%s, %s)' % (player, vx, vy)
074: print '</html>'
075: except MySQLdb.Error, e:
076: print e
077:
078: def show_status(cur):
079: try:
080: cur.execute ("SELECT modified, player, red, green, blue, px, py, vx, vy, status, id FROM gameboard")
081: except MySQLdb.Error, e:
082: print e
083:
084: rows = cur.fetchall()
085: print '<pre>'
086: for row in rows:
087: modified = row[0]
088: player = row[1]
089: red = int(row[2])
090: green = int(row[3])
091: blue = int(row[4])
092: px = float(row[5])
093: py = float(row[6])
094: vx = float(row[7])
095: vy = float(row[8])
096: status = row[9]
097: id = int(row[10])
098: rs = (modified, player, id, red, green, blue, px, py, vx, vy, status)
099: print '"%s" "%s" %d %d %d %d %g %g %g %g "%s"' % rs
100: print '</pre>'
101:
102: def move_player(cur, rs):
103: try:
104: cur.execute("""UPDATE gameboard SET modified='%s',
105: px=%g, py=%g, vx=%g, vy=%g WHERE id=%d""" % rs)
106: except MySQLdb.Error, e:
107: print e
108: print '</html>'
109: sys.exit()
110:
111:
112: def play(cur):
113: import time
114: try:
115: cur.execute("SELECT now()")
116: except MySQLdb.Error, e:
117: print e
118: print '</html>'
119: sys.exit()
120: rows = cur.fetchall()
121: now = rows[0][0];
122: fmt = '%Y-%m-%d %H:%M:%S'
123: d = time.strptime(now,fmt)
124: sn = (d[3]*60+d[4])*60+d[5]
125: #dtn = datetime.datetime(*d[0:6])
126:
127: print '<p>Datetime: '
128: print now
129:
130: try:
131: cur.execute("SELECT modified, id, px, py, vx, vy FROM gameboard")
132: except MySQLdb.Error, e:
133: print e
134: print '</html>'
135: sys.exit()
136: rows = cur.fetchall()
137: print '<p><pre>'
138: for row in rows:
139: modified = row[0]
140: d = time.strptime(modified,fmt)
141: s = (d[3]*60+d[4])*60+d[5]
142: #dt = datetime.datetime(*d[0:6])
143: diff = max(sn - s,1.0)
144: id = int(row[1])
145: #print '%d %s' % (diff,player)
146: px = float(row[2])
147: py = float(row[3])
148: vx = float(row[4])
149: vy = float(row[5])
150: ball = game.Ball(17,px,py,vx,vy)
151: game.update_ball(ball,diff)
152: rs = (now, ball.x, ball.y, ball.vx, ball.vy, id)
153: move_player(cur,rs)
154: print 'id %d %g %g %g %g' % (id, px, py, vx, vy)
155:
156: print '</pre>'
157:
158:
159:
160:
161: #-------main program
162: cgitb.enable() # formats errors in HTML
163:
164: sys.stderr = sys.stdout
165: print "Content-type: text/html"
166: print
167: print '<html>'
168:
169:
170: form = cgi.FieldStorage()
171: db = dbname.dbopen()
172: cur = db.cursor()
173:
174: if form.has_key("action"): action = form["action"].value
175: else: action = 'status'
176:
177: #print '<p>action: <b>%s</b>' % action
178:
179:
180: if action=='status': show_status(cur)
181: elif action=='join': add_player(form,cur)
182: elif action=='update': update_player(form,cur)
183: elif action=='move': play(cur)
184: elif action=='remove': remove_player(form,cur)
185: else: print '<p>action <b>%s</b> not recognized' % action
186: print '</html>'
187: cur.close()
188: db.close()
game.pygame.py defines the Ball class to
represent players.
intersect window calculates the time required to strike the closest window border in the direction of travel.
wall collision changes the ball velocity after collision.
update ball calculates, in order, the wall collisions during the specified interval and advances the ball to its final position (which is then used by move player in updating the gameboard database.)
01: #!/usr/bin python 02: 03: tscale = 0.5 04: 05: class Ball(object): 06: 'bouncing ball objects' 07: def __init__(self, radius, px, py, vx, vy): 08: self.radius = radius 09: self.x = px 10: self.y = py 11: self.vx = vx 12: self.vy = vy 13: def __str__(self): 14: rs = (self.x, self.y, self.vx, self.vy) 15: str = 'pos (%g, %g) vel (%g, %g)' % rs 16: return str 17: def move(self,tstep): 18: dt = tstep*tscale; 19: self.x = self.x + self.vx*dt; 20: self.y = self.y + self.vy*dt; 21: 22: 23: left=0 24: right=400 25: bottom=0 26: top=400 27: 28: def intersect_window(ball,tstep): 29: 'find nearest wall intersection for times < tstep' 30: tx = tstep 31: idx = -1 32: if ball.vx<0: 33: t = (ball.x-ball.radius - left)/(-ball.vx) 34: if t<tx: 35: tx = t 36: idx = 0 37: if ball.vx>0: 38: t = (right-ball.x - ball.radius)/(ball.vx) 39: if t<tx: 40: tx = t 41: idx = 1 42: if ball.vy<0: 43: t = (ball.y-ball.radius - bottom)/(-ball.vy) 44: if t<tx: 45: tx = t 46: idx = 2 47: if ball.vy>0: 48: t = (top - ball.y - ball.radius)/(ball.vy) 49: if t<tx: 50: tx = t 51: idx = 3 52: tx = tx/tscale; 53: if tx>tstep: return 54: return [tx, idx] 55: 56: def wall_collision(ball,idx): 57: if idx<2: ball.vx = -ball.vx 58: else: ball.vy = -ball.vy 59: 60: 61: def update_ball(ball,tstep): 62: tmore = tstep 63: while tmore>0: 64: c = intersect_window(ball,tmore) 65: if c: 66: ball.move(c[0]) 67: wall_collision(ball,c[1]) 68: tmore = tmore - c[0] 69: else: 70: ball.move(tmore) 71: tmore = 0.0 72: 73: 74: #if __name__ == '__main__': 75: def test(): 76: ball = Ball(7,100,100,20,30) 77: for n in range(1,20): 78: update_ball(ball,1) 79: print ball
logon.py01: #!/usr/bin/python
02: import cgi
03: import MySQLdb
04:
05: def logon(form, cur):
06: fields = ["username", "password"]
07: for field in fields:
08: if not form.has_key(field): return
09: try:
10: cur.execute("""SELECT uid from users
11: where username='%s' and password='%s'""" % (form["username"].value, form["password"].value) )
12: rows = cur.fetchall()
13: if (cur.rowcount > 0): return rows[0]
14: except MySQLdb.Error, e:
15: print e
Maintained by John Loomis, updated Sat Apr 05 21:42:11 2008