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.py
game.py
logon.py
gameboard.py
This 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.py
game.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.py
01: #!/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