#! /usr/bin/env python #-------------------------------------------# #GeoStrike.pyw - a geometrical space shooter# #By PyMike in May, 2008 # #Released under the GNU LGPL # #-------------------------------------------# import pygame, math, random, os from pygame.locals import * os.environ["SDL_VIDEO_CENTERED"] = "1" NO_POINTS = [] SHIP_POINTS = [(0, -10), (-15, 20), (0, 15), (15, 20)] SHOT_POINTS = [(0, -7), (-2, 7), (0, 4), (2, 7)] def __lineCollision(a, b): s1 = a[0] s2 = b[0] e1 = a[1] e2 = b[1] A = e1[0] - s1[0] B = e1[1] - s1[1] C = e2[0] - s2[0] D = e2[1] - s2[1] E = s1[1] - s2[1] F = s1[0] - s2[0] denom = (D*A)-(C*B) if denom == 0: return False numA = C*E - D*F numB = A*E - B*F Ta = numA / float(denom) Tb = numB / float(denom) if (Ta >= -0.5 and Ta <= 1) and (Tb >= -0.5 and Tb <= 1): return True return False def Collision(obj1, obj2): lines1 = [] lines2 = [] for n in xrange(len(obj1)): lines1.append([obj1[n-1], obj1[n]]) for n in xrange(len(obj2)): lines2.append([obj2[n-1], obj2[n]]) for line1 in lines1: for line2 in lines2: if __lineCollision(line1, line2): return True return False class Group(pygame.sprite.Group): def draw(self, surface): for s in self.sprites(): s.draw(surface) class VectorObject(pygame.sprite.Sprite): def __init__(self, points=NO_POINTS, pos=(0, 0), numpoints=None): pygame.sprite.Sprite.__init__(self, self.containers) self.points = points self.scale = 1.0 self.angle = 0 self.drawpoints = [] self.pos = list(pos) self.velocity = [0, 0] self.color = (255, 255, 255) self.numpoints = numpoints self.rect = Rect(0, 0, 64, 64) self.rotate_points() def update(self): self.rect.center = self.pos self.pos[0] -= self.velocity[0] self.pos[1] -= self.velocity[1] def move(self, dx, dy): self.pos[0] += dx self.pos[1] += dy def rotate_points(self): if self.numpoints: self.drawpoints = [] for i in range(self.numpoints): self.drawpoints.append([0,0]) numpoints = self.numpoints for i in range(numpoints): angle = i*2*math.pi/numpoints self.drawpoints[i][0]=math.cos(angle - math.radians(self.angle))*25*self.scale + self.pos[0] self.drawpoints[i][1]=math.sin(angle - math.radians(self.angle))*25*self.scale + self.pos[1] else: self.drawpoints = [] for p in self.points: newX = int(p[0]*math.cos(math.radians(-self.angle))*self.scale - p[1]*math.sin(math.radians(-self.angle))*self.scale + self.pos[0]) newY = int(p[0]*math.sin(math.radians(-self.angle))*self.scale + p[1]*math.cos(math.radians(-self.angle))*self.scale + self.pos[1]) self.drawpoints.append((newX,newY)) def draw(self, surface): self.rotate_points() pygame.draw.polygon(surface,self.color,self.drawpoints) pygame.draw.aalines(surface,self.color,1,self.drawpoints) class Ship(VectorObject): def __init__(self): VectorObject.__init__(self, points=SHIP_POINTS, pos=(320, 450)) self.color = (0, 255, 0) self.timer = 0 self.level = 1 def update(self): key = pygame.key.get_pressed() self.timer += 1 if key[K_LEFT]: self.move(-6, 0) if key[K_RIGHT]: self.move(6, 0) if self.pos[0] < 0: self.pos[0] = 0 if self.pos[0] > 480: self.pos[0] = 480 if key[K_SPACE]: if self.timer > 4: if self.level > 1: Shot(self.pos, -8, -3) Shot(self.pos, 8, 3) Shot(self.pos) else: Shot(self.pos, -8) Shot(self.pos, 8) self.timer = 0 class Shot(VectorObject): def __init__(self, pos, offset=0, speedoffset=0): VectorObject.__init__(self, points=SHOT_POINTS, pos=pos) self.move(offset, -10) self.vx = speedoffset def update(self): self.move(self.vx, -14) if self.pos[1] <= 0: self.kill() class Tri(VectorObject): hp = 5 def __init__(self, pos): VectorObject.__init__(self, numpoints=3, pos=pos) self.color = (0, 200, 255) self.vx = random.choice([0.25, 0.5, 0.75, 1.0])*2*random.choice([-1, 1]) self.vy = random.choice([0.25, 0.5, 0.75, 1.0])*5 def update(self): self.move(self.vx, self.vy) self.angle += 5*self.vx if self.pos[1] > 480: self.kill() def get_hit(self): self.hp -= 1 if self.hp <= 0: self.kill() for i in range(15): Particle(self.pos) class Hex(VectorObject): hp = 3 def __init__(self, pos): VectorObject.__init__(self, numpoints=6, pos=pos) self.color = (255, 0, 255) self.vy = random.choice([0.25, 0.5, 0.75])*6 self.frame = 0 def update(self): self.move(0, self.vy) self.angle += math.sin(math.radians(self.frame))*5 if self.pos[1] > 480: self.kill() self.frame += 5 self.pos[0] += math.sin(math.radians(self.frame))*5 def get_hit(self): self.hp -= 1 if self.hp <= 0: self.kill() for i in range(15): Particle(self.pos) class Square(VectorObject): hp = 3 def __init__(self, pos): VectorObject.__init__(self, numpoints=4, pos=pos) self.color = (255, 255, 0) self.vy = random.choice([0.25, 0.5, 0.75])*6 self.vx = self.vy self.frame = 0 def update(self): self.angle += self.vx self.vx += random.choice([0.25, 0.5])*random.choice([-1, 1]) self.vy += random.choice([0.25, 0.5])*random.choice([-1, 1]) self.move(self.vx, self.vy) if self.pos[1] > 480: self.kill() if self.pos[0] > 480: self.kill() if self.pos[0] < 0: self.kill() def get_hit(self): self.hp -= 1 if self.hp <= 0: self.kill() for i in range(15): Particle(self.pos) class Octo(VectorObject): hp = 5 def __init__(self, pos, target): VectorObject.__init__(self, numpoints=8, pos=pos) self.color = (255, 150, 0) self.vy = random.choice([0.25, 0.5, 0.75])*6 self.vx = 0 self.target = target def update(self): if self.pos[0] < self.target.pos[0] and self.vx < 5: self.vx += 0.25 if self.pos[0] > self.target.pos[0] and self.vx > -5: self.vx -= 0.25 self.move(self.vx, self.vy) self.angle += self.vx if self.pos[1] > 480: self.kill() def get_hit(self): self.hp -= 1 if self.hp <= 0: self.kill() for i in range(15): Particle(self.pos) class Particle(VectorObject): def __init__(self, pos): VectorObject.__init__(self, numpoints=10, pos=pos) self.size = random.randrange(1, 7) self.image = pygame.Surface((self.size, self.size)) self.image.fill((255, 200, 0)) self.angle = random.randrange(360) self.velocity = random.choice([0.1, 0.2, 0.3, 0.4, 0.5])*10 self.alpha = 255 def update(self): self.alpha -= 7 if self.alpha <= 0: self.kill() self.move(math.sin(math.radians(self.angle))*self.velocity, math.cos(math.radians(self.angle))*self.velocity) self.image.set_alpha(self.alpha) def draw(self, surface): surface.blit(self.image, self.pos) class Star(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self, self.containers) self.size = random.randrange(1, 4) self.image = pygame.Surface((self.size, self.size)) self.pos = [random.randrange(480), random.randrange(480)] self.speed = random.choice([0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5])*3 self.color = (self.speed*75, self.speed*75, self.speed*75) self.image.fill(self.color) def update(self): self.pos[1] += self.speed if self.pos[1] >= 480: self.pos[1] = 0 def draw(self, surface): surface.blit(self.image, self.pos) def Game(screen): stars = Group() all = Group() shots = Group() enemies = Group() particles = Group() Ship.containers = all Shot.containers = all, shots Tri.containers = all, enemies Hex.containers = all, enemies Square.containers = all, enemies Octo.containers = all, enemies Star.containers = stars Particle.containers = all, particles clock = pygame.time.Clock() ship = Ship() Tri((320, 0)) Hex((200, 0)) score = 0 level = 1 lives = 5 font = pygame.font.Font(None, 30) font2 = pygame.font.Font(None, 60) for i in range(75): Star() while 1: clock.tick(60) stars.update() for e in pygame.event.get(): if e.type == QUIT: pygame.quit() return if e.type == KEYDOWN: if e.key == K_ESCAPE: pygame.quit() return level = int(score/500) + 1 if not random.randrange(75 - (level*5)): Tri((random.randrange(480), 0)) if not random.randrange(80 - (level*5)): Hex((random.randrange(480), 0)) if not random.randrange(100 - (level*5)): Square((random.randrange(480), 0)) if not random.randrange(120 - (level*5)): Octo((random.randrange(480), 0), ship) for s in all.sprites(): s.update() if isinstance(s, Tri) or isinstance(s, Square) or isinstance(s, Octo) or isinstance(s, Hex): e = s for s in shots: if e.rect.colliderect(s.rect): if Collision(e.drawpoints, s.drawpoints): s.kill() e.get_hit() Particle(s.pos) score += 5 if ship.rect.colliderect(e.rect): if Collision(e.drawpoints, ship.drawpoints) and ship.alive(): ship.kill() lives -= 1 for i in range(200): Particle(ship.pos) if not ship.alive() and lives > 0 and not particles: for s in all.sprites(): pygame.sprite.Sprite.kill(s) ship = Ship() screen.fill((0, 0, 0)) stars.draw(screen) all.draw(screen) ren = font.render("Score: %06d" % score, 1, (255, 255, 255)) screen.blit(ren, (10, 10)) ren = font.render("Lives x%d" % lives, 1, (255, 255, 255)) screen.blit(ren, (10, 35)) ren = font.render("Level: %d" % level, 1, (255, 255, 255)) screen.blit(ren, (240, 10)) ren = font.render("FPS: %d" % clock.get_fps(), 1, (255, 255, 255)) screen.blit(ren, (10, 450)) if lives <= 0: ren = font2.render("Game Over!", 1, (255, 255, 255)) screen.blit(ren, (240-ren.get_width()/2, 240-ren.get_height()/2)) pygame.display.flip() def main(): pygame.init() pygame.display.set_caption("GeoStrike - A geometrical shooter by PyMike") screen = pygame.display.set_mode((480, 480)) pygame.mouse.set_visible(0) Game(screen) if __name__ == "__main__": main()