Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/spacetag.py
diff options
context:
space:
mode:
Diffstat (limited to 'spacetag.py')
-rw-r--r--spacetag.py667
1 files changed, 667 insertions, 0 deletions
diff --git a/spacetag.py b/spacetag.py
new file mode 100644
index 0000000..bc99f28
--- /dev/null
+++ b/spacetag.py
@@ -0,0 +1,667 @@
+#! /usr/bin/env python
+'''Copyright 2008 Nolan Baker'''
+
+'''Welcome to my code. Everything should be pretty straight foreward. If you
+find anything in the code that needs to be fixed, or if there's anything that
+you don't understand, feel free to email me at nbaker@centenary.edu with the
+subject "Space Tag". Remember, the object here is to learn, so stay focused,
+and be safe out there.'''
+
+
+import math, random, pygame, logging, olpcgames
+from olpcgames import mesh, eventwrap
+
+from pygame.locals import *
+
+
+# interestingly enough, the log.debug function is just a print statement
+
+log = logging.getLogger( 'Thor vs. Demon run' )
+
+log.setLevel( logging.DEBUG )
+
+
+################################################################################
+# Load Images
+################################################################################
+red = pygame.image.load("red.gif")
+red.set_colorkey((255,255,255))
+yellow = pygame.image.load("yellow.gif")
+yellow.set_colorkey((255,255,255))
+
+################################################################################
+# Buttons
+################################################################################
+UP = pygame.K_w
+LEFT = pygame.K_a
+RIGHT = pygame.K_d
+DOWN = pygame.K_s
+CLIMB = pygame.K_DOWN
+DROP = pygame.K_UP
+BOOST = pygame.K_TAB
+
+################################################################################
+
+# Object Functions
+
+################################################################################
+
+
+
+def Distance(self, x, y):
+
+ # finds distance between self and a given location on a 2D plane
+
+ d = math.sqrt((x - self.s[0]) ** 2 + (y - self.s[1]) ** 2)
+
+ if d == 0:
+
+ return .0000000001
+
+ # returns a distance (not a displacement)
+
+ else:
+
+ return d
+
+
+
+def Angle(self, x, y):
+ # this finds an angle from an object to a point
+
+ distance = Distance(self, x, y)
+
+ angle = math.acos(float(self.s[0] - x) / float(distance))
+
+ angle *= 180.0 / math.pi # pygame likes degrees
+
+ angle -= 90 # adjustment for the orientation of the character
+
+
+ # now we have to make some changes because math is silly
+ # just remember, pygame only likes 0-359 (Go, go gadget modulo!)
+ if (y < self.s[1]):
+
+ angle = (-angle) % 360
+
+ elif(y > self.s[1]):
+
+ angle = (angle + 180) % 360
+
+ else:
+
+ if (x <= self.s[0]):
+
+ angle = 90
+
+ elif (x > self.s[0]):
+
+ angle = 270
+
+ return angle
+
+
+
+def Transform(self, angle):
+
+ center = self.rect.center
+
+ change = 200 * self.dt
+
+ self.ang_diff = int(self.angle - angle)
+
+ if (180 > self.ang_diff > 0) or (-180 >= self.ang_diff > -360):
+
+ self.angle = (self.angle - change) % 360
+
+ if (-180 < self.ang_diff < 0) or (180 <= self.ang_diff < 360):
+
+ self.angle = (self.angle + change) % 360
+
+ # rotozoom is used here because you always want to do your transformations
+ # on the original image, otherwise you end up with heavy distortion
+ # eventually, I'll make the switch to vector graphics
+ self.image = pygame.transform.rotozoom(self.original,
+
+ self.angle,
+
+ .25 * (self.s[2] / 100 + 1))
+
+ self.rect = self.image.get_rect(center = center)
+
+
+
+################################################################################
+
+# Sprites
+
+################################################################################
+
+
+class It(pygame.sprite.Sprite):
+ def __init__(self, game, owner = None):
+ pygame.sprite.Sprite.__init__(self)
+ self.owner = owner
+ self.game = game
+ self.wait = 200
+
+ self.angle = 0
+ self.original = pygame.image.load("it.gif")
+ self.original.set_colorkey((255,255,255))
+ self.original.convert()
+
+ self.waiting = pygame.image.load("waiting.gif")
+ self.waiting.set_colorkey((255,255,255))
+ self.waiting.convert()
+
+
+ self.image = self.waiting
+ self.rect = self.image.get_rect()
+ self.s = [self.game.res[0] / 2, self.game.res[1] / 2, 100]
+
+ def setOwner(self, owner):
+ self.owner = owner
+
+ def dist(self, other):
+ d = math.sqrt((self.s[0] - other.s[0]) ** 2 +
+ (self.s[1] - other.s[1]) ** 2 +
+ (self.s[2] - other.s[2]) ** 2)
+ return d
+
+ def touching(self, other):
+ d = self.dist(other)
+ r_self = self.rect.width / 2.0
+ r_other = other.rect.width / 2.0
+ # if the distance between the 2 objects is <= the sum of their radii
+ log.debug(str(d) + " " + str(r_self + r_other))
+ if d <= (r_self + r_other):
+ # a legal tag has been made
+ return True
+ return False
+
+ def update(self):
+ self.dt = self.game.clock.get_rawtime() / 1000.0
+ self.rect.center = (self.s[0], self.s[1])
+ if self.wait <= 0:
+ log.debug("It owner: " + str(self.owner))
+ if (self.owner == None):
+ self.owner = self.game.avatar
+ elif (self.owner == self.game.avatar):
+ log.debug("I'm it!")
+ for other in self.game.others.sprites():
+ if self.touching(other):
+ if self.owner != None:
+ print 'here'
+ self.owner.it = False
+ other.it = True
+ self.owner = other
+ log.debug("You're it! " + other.handle)
+ olpcgames.mesh.broadcast("tag|" + mesh.my_handle() + ";" + other.handle)
+
+ else:
+ log.debug("Waiting..." + str(self.wait))
+ self.wait -=1
+
+ if self.owner != None:
+ self.angle += 7
+ self.angle %= 360
+ self.s = self.owner.s
+ Transform(self, self.angle)
+
+
+class Character(pygame.sprite.Sprite):
+
+ def __init__(self, game, image, x, y, z, mass):
+
+ pygame.sprite.Sprite.__init__(self)
+
+
+ self.game = game
+ self.it = False
+
+
+ self.original = image
+ self.original.set_colorkey((255,255,255))
+ self.original.convert()
+
+ self.image = self.original
+
+ self.rect = self.image.get_rect()
+
+
+
+ self.area = pygame.display.get_surface().get_rect()
+
+ self.rect.center = (x,y)
+
+ self.angle = 0
+
+
+
+ # physical variables
+
+ self.s = [x, y, z] # position
+
+ self.v = [0, 0, 0] # velocity
+
+ self.a = [0, 0, 0] # acceleration
+
+ self.f = [0, 0, 0] # sum of forces
+
+ self.m = mass
+
+ self.forces = [[],[],[]] # list of forces
+
+
+
+ def SumForces(self):
+
+ for i in range(0, 3):
+
+ total = 0
+
+ for j in range(0, len(self.forces[i])):
+
+ total += self.forces[i][j]
+
+ self.f[i] = total
+
+
+ def WrapScreen(self):
+ # if you go off the screen, come out on the otherside
+ self.s[0] %= self.game.res[0]
+ self.s[1] %= self.game.res[1]
+
+ def ConstrainHeight(self):
+ # we also don't want you flying too high or too low
+ if self.s[2] > 400: self.s[2] = 400
+ if self.s[2] < 0: self.s[2] = 0
+
+
+ def Move(self):
+ # Think back to calculus...
+ self.dt = self.game.clock.get_rawtime() / 1000.0
+
+ # let's move the Newton way
+
+ for i in range(0, 3):
+
+ self.a[i] = self.f[i] / float(self.m)
+
+ self.v[i] += self.a[i] * self.dt
+
+ self.s[i] += self.v[i] * self.dt
+
+ # just in case we want to go off screen or fly too high
+ self.WrapScreen()
+ self.ConstrainHeight()
+
+
+ # once the right spot has been found set the sprite there
+ self.rect.centerx = int(self.s[0])
+
+ self.rect.centery = int(self.s[1])
+
+ # since we've put this frame's forces to good use
+ # we must now clear out the list, so we can do it again
+
+ self.forces = [[],[],[]]
+
+ def FaceHeading(self):
+ # if you're moving, turn to face where you're going
+
+ if (pygame.key.get_pressed()[UP] or
+
+ pygame.key.get_pressed()[DOWN] or
+
+ pygame.key.get_pressed()[LEFT] or
+
+ pygame.key.get_pressed()[RIGHT]):
+
+ heading_x = self.s[0] + self.v[0] * self.dt
+
+ heading_y = self.s[1] + self.v[1] * self.dt
+
+ angle = Angle(self, heading_x, heading_y)
+
+ else:
+
+ angle = self.angle
+
+ Transform(self, angle)
+
+
+
+ def getSpeed(self):
+
+ return int(math.sqrt(self.v[0] ** 2 + self.v[1] ** 2 + self.v[2] ** 2))
+
+ def update(self):
+ # if you're it and the game doesn't know it yet
+ if self.it and self.game.it.sprites()[0].owner != self:
+ # let it know
+ self.game.it.sprites()[0].setOwner(self)
+
+class Dummy(Character):
+ def update(self):
+ Character.update(self)
+ self.Move()
+
+ Transform(self, self.angle)
+
+
+
+class Human(Character):
+
+ def update(self):
+ Character.update(self)
+
+ # boost, because every spaceman could use one
+
+ boost = 1
+
+ if pygame.key.get_pressed()[BOOST]:
+
+ boost = 2
+
+
+ # this speed cap is unnecessary when friction is added
+ # however, this is Space Tag, not Earth Tag
+ if self.getSpeed() < 600:
+ # here's how to move
+ if pygame.key.get_pressed()[UP]:
+
+ self.forces[1].append(-200 * boost) # up
+ if pygame.key.get_pressed()[DOWN]:
+
+ self.forces[1].append(200 * boost) # down
+ if pygame.key.get_pressed()[LEFT]:
+
+ self.forces[0].append(-200 * boost) # left
+ if pygame.key.get_pressed()[RIGHT]:
+
+ self.forces[0].append(200 * boost) # right
+
+ if pygame.key.get_pressed()[DROP]:
+ self.forces[2].append(-200 * boost) # away from you
+
+ if pygame.key.get_pressed()[CLIMB]:
+ self.forces[2].append(200 * boost) # towards you
+
+
+ # since space doesn't have a lot of things to slow you down
+ # the space ship does it automatically
+ if ((int(self.v[2]) < 0) and
+
+ (not pygame.key.get_pressed()[DROP])):
+
+ self.forces[2].append(200)
+
+ if ((int(self.v[2]) > 0) and
+
+ (not pygame.key.get_pressed()[CLIMB])):
+
+ self.forces[2].append(-200)
+ if ((int(self.v[1]) < 0) and
+
+ (not pygame.key.get_pressed()[UP])):
+
+ self.forces[1].append(200)
+
+ if ((int(self.v[1]) > 0) and
+
+ (not pygame.key.get_pressed()[DOWN])):
+
+ self.forces[1].append(-200)
+
+ if ((int(self.v[0]) < 0) and
+
+ (not pygame.key.get_pressed()[LEFT])):
+
+ self.forces[0].append(200)
+
+ if ((int(self.v[0]) > 0) and
+
+ (not pygame.key.get_pressed()[RIGHT])):
+
+ self.forces[0].append(-200)
+
+ #let everyone else know where you are and what you're doing
+ connections = len(olpcgames.mesh.pygametubes)
+ if connections != 0:
+ # this is just a big, nasty instant message
+ s = "%s,%s,%s" % (self.s[0], self.s[1], self.s[2]) + ";"
+ ang = str(self.angle)
+ olpcgames.mesh.broadcast("pos|" + s + ang)
+
+
+ # order is super important here
+
+ self.SumForces()
+ self.Move()
+
+ self.FaceHeading()
+
+
+
+################################################################################
+
+# Game
+
+################################################################################
+
+class Game():
+
+
+
+ def __init__(self, resolution = (1200,900)):
+
+ pygame.init()
+
+ self.res = resolution
+
+
+
+ self.screen = pygame.display.set_mode(self.res)
+ # this makes the mouse invisible
+ pygame.mouse.set_visible(0)
+
+
+
+ # this gives our game a sense of time
+ self.clock = pygame.time.Clock()
+
+
+
+ def pauseImage(self):
+ self.pausescreen = pygame.image.load("pausescreen.gif")
+ self.pausescreen.convert()
+
+
+
+ def backgroundImage(self):
+
+ self.background = pygame.image.load("background.gif")
+
+ self.background.convert()
+
+
+
+ def makeSprites(self):
+ # Name_of_Character = Character(game, image, x, y, z, mass)
+ x = random.randint(50, self.res[0] - 50)
+ y = random.randint(50, self.res[1] - 50)
+
+ self.avatar = Human(self, yellow, x, y, 100, 2)
+ self.me = pygame.sprite.Group((self.avatar))
+ self.others = pygame.sprite.Group()
+ self.handle_dict = {}
+ self.itit = It(self)
+ self.it = pygame.sprite.Group((self.itit))
+
+
+ def pauseScreen(self):
+ # this loop starts when ESC is pressed in the mainloop
+
+ self.paused = True
+
+ while self.paused:
+
+ self.clock.tick()
+
+
+ # check to see if anything happened
+
+ for event in pygame.event.get():
+ # make sure you can quit your game from here too
+
+ if event.type == QUIT:
+
+ self.running, self.paused = False, False
+
+ if event.type == KEYDOWN:
+ # ESC puts you back in the mainloop
+
+ if event.key == K_ESCAPE:
+
+ self.paused, self.running = False, True
+ # 'q' quits the game (imagine that)
+
+ if event.key == K_q:
+
+ self.running, self.paused = False, False
+
+ # draw the pausescreen
+ self.screen.blit(self.pausescreen, (0, 0))
+
+ # refresh the monitor
+
+ pygame.display.flip()
+
+
+
+ def mainloop(self):
+ # load your images, so you don't have to do it later
+ self.pauseImage()
+ self.backgroundImage()
+
+ # now make your avatar and create some groups
+ self.makeSprites()
+
+ # then lather, rinse, and repeat
+
+ self.running = True
+ while self.running:
+ self.clock.tick()
+
+ # draw the background first
+ self.screen.blit(self.background, (0, 0))
+
+
+ # then see if anything happened since last you checked
+
+ for event in pygame.event.get([QUIT, KEYDOWN,
+ olpcgames.PARTICIPANT_ADD,
+ olpcgames.MESSAGE_MULTI]):
+
+ # here's how to quit
+ if event.type == QUIT:
+
+ self.running = False
+
+ # here's how to pause the game
+
+ if event.type == KEYDOWN and event.key == K_ESCAPE:
+
+ self.pauseScreen()
+
+ # make a dummy sprite and put it in a dictionary
+ if (event.type == olpcgames.PARTICIPANT_ADD and
+ event.handle != olpcgames.mesh.my_handle()):
+ dummy = Dummy(self, red, -30, -30, 0, 2)
+ dummy.handle = event.handle
+ self.handle_dict[event.handle] = dummy
+ if (self.itit.owner == self.avatar):
+ olpcgames.mesh.broadcast("tag|None;" + mesh.my_handle())
+
+ # Incoming! Those messages are hitting everyone...
+ if (event.type == olpcgames.MESSAGE_MULTI and
+ event.handle != olpcgames.mesh.my_handle()):
+ # this part takes a global message and converts it to data
+ mes, content = event.content.split("|")
+ if mes == "pos":
+ s, angle = content.split(";")
+ s1, s2, s3 = s.split(",") # position
+ s1, s2, s3 = float(s1), float(s2), float(s3)
+ angle = float(angle)
+
+ # this part inserts the data into the dummy character
+ try:
+ dummy = self.handle_dict[event.handle]
+ dummy.s = [s1, s2, s3]
+ dummy.angle = angle
+ self.handle_dict[event.handle] = dummy
+ except:
+ log.debug('something bad happened')
+
+ elif mes == "tag":
+ tagger, tagee = content.split(";")
+ if tagger != "None":
+ self.handle_dict[tagger].it = False
+ if tagee != mesh.my_handle():
+ self.handle_dict[tagee].it = True
+ self.itit.owner = self.handle_dict[tagee]
+ else:
+ self.avatar.it = True
+ self.itit.owner = self.avatar
+ self.itit.wait = 2 * self.clock.get_fps()
+
+
+ # if the dummy isn't already grouped, do it
+ for dummy in self.handle_dict.values():
+ if dummy not in self.others.sprites():
+ self.others.add(dummy)
+
+ # keep the sprites up to date
+ self.me.update()
+ self.others.update()
+ self.it.update()
+
+ # draw them to the screen
+ self.me.draw(self.screen)
+ self.others.draw(self.screen)
+ self.it.draw(self.screen)
+
+
+ # then refresh the monitor
+ pygame.display.flip()
+ # log.debug(str(int(self.clock.get_fps())) + " fps")
+
+
+
+################################################################################
+
+# Now for the show...
+
+################################################################################
+
+
+
+def main():
+
+ spacetag = Game()
+
+ spacetag.mainloop()
+
+
+
+if __name__ == "__main__":
+
+ logging.basicConfig()
+
+ main()
+
+
+
+pygame.quit ()
+'''Stay tuned, more games are on their way.'''