diff options
Diffstat (limited to 'spacetag.py')
-rw-r--r-- | spacetag.py | 667 |
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.''' |