def run_title(): class Title: pass run.quit = False game = run.game title = Picture("title.png") subtitle = Picture("subtitle.png") menu = Picture("menu.png") menu2 = Picture("menu2.png") menu3 = Picture("menu3.png") menu3hl = Picture("menu3hl.png") cursor = Picture("mouse.png") if not run.config.nomusic: pygame.mixer.music.load(data.filepath("loop/menu.ogg")) pygame.mixer.music.play(-1) def button_ng(): run.run_game() if not run.config.nomusic: pygame.mixer.music.load(data.filepath("loop/menu.ogg")) pygame.mixer.music.play(-1) title.next = pygame.time.get_ticks() + 1000.0 / run.FPS def button_next(): if run.last_level < run.config.level: run.last_level += 1 def button_prev(): if run.last_level > 1: run.last_level -= 1 def button_fs(): run.config.fullscreen = not run.config.fullscreen run.config.save() main.main() def button_nm(): run.config.nomusic = not run.config.nomusic if not run.config.nomusic: pygame.mixer.music.load(data.filepath("loop/menu.ogg")) pygame.mixer.music.play(-1) else: pygame.mixer.music.stop() run.config.save() def button_q(): run.quit = True rects = ( (220, 274, 417, 323, button_ng), (170, 344, 320, 400, button_fs), (340, 344, 470, 400, button_nm), (283, 417, 358, 466, button_q), (130, 260, 210, 286, button_next), (130, 301, 210, 326, button_prev), ) selected = None t = 0 title.next = pygame.time.get_ticks() + 1000 / run.FPS while not run.quit: for e in pygame.event.get(): if e.type == pygame.QUIT: run.quit = True elif e.type == pygame.KEYDOWN: if e.key == pygame.K_ESCAPE: rects[3][4]() if e.key == pygame.K_RETURN: rects[0][4]() elif e.type == pygame.MOUSEBUTTONUP: x, y = e.pos if e.button == 1: if selected != None: selected[4]() mx, my = pygame.mouse.get_pos() glClearColor(1, 0.6, 0.4, 1) glClear(GL_COLOR_BUFFER_BIT) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glEnable(GL_TEXTURE_2D) glEnable(GL_BLEND) glBlendFunc(GL_ONE, GL_ONE) t += 1 tt = (t * 4) % (480 + 512) game.background1.draw_centered(0, 0) game.background1.draw_centered(640, 480) game.background1.draw_centered(320, tt) game.background1.draw_centered(320, tt - 512 - 480) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) selected = None black = {"red" : 0, "green" : 0, "blue" : 0} beat = (t % 30) if beat < 20: beat = 0 else: if beat < 25: beat = (beat - 20) / 5.0 else: beat = 1 - (beat - 25) / 5.0 d = (t / 30) % 3 a, b, c = ((0.5, 0.5, 0), (0.5, 0, 0.5), (0, 0.5, 0.5))[d] flash = {"red" : beat * a, "green" : beat * b, "blue" : beat * c} d = 160.0 if t < d: tt = 1 - t / d title.draw(0, 0 - tt * 480, **flash) subtitle.draw(0, 0 + tt * 480, **black) menu.draw(0 + tt * 640, 0, **black) menu2.draw(0 - tt * 640, 0, **black) elif t < d * 2: tt = t - d tt = tt / d title.draw(0, 0, **flash) subtitle.draw(0, -tt * 220, **black) menu.draw(240 * tt, 80 * tt, **black) menu2.draw(-80 * tt, 80 * tt, **black) else: tt = (t - d * 2) / d if tt > 1.0: tt = 1.0 title.draw(0, 0, **flash) subtitle.draw(0, -220, **black) glPushMatrix() glTranslate(240 + 550, 80 + 350, 0) glRotate(10 * math.sin(1 * 2 * math.pi * (t - d * 2) / 60), 0, 0, 1) glTranslate(-550, -350, 0) menu.draw(0, 0, **black) glPopMatrix() menu2.draw(-80, 80, **black) menu3.draw(0, 0, red = 0, green = 0, blue = 0, alpha = tt) for r in rects: if mx >= r[0] and my >= r[1] and mx <= r[2] and my <= r[3]: selected = r glBlendFunc(GL_SRC_ALPHA, GL_ONE) menu3hl.draw_part(r[0] - 8, r[1] - 8, r[0] - 8, r[1] - 8, r[2] + 8, r[3] + 8) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) menu3.draw_part(r[0] - 8, r[1] - 8, r[0] - 8, r[1] - 8, r[2] + 8, r[3] + 8, red = 1, green = 0.5, blue = 0, alpha = 0.5) selected = r glBlendFunc(GL_SRC_ALPHA, GL_ONE) x, y = 395 + 230 * (run.last_level - 1) / 7, 245 menu3hl.draw_part(x, y, x, y, 395 + 230 * run.last_level / 7, 290) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) menu3hl.draw_part(x, y, x, y, 395 + 230 * run.last_level / 7, 290, red = 1, green = 0.5, blue = 0, alpha = 0.5) cursor.draw_centered(mx, my) pygame.display.flip() ft = pygame.time.get_ticks() pygame.time.wait(int(title.next - ft)) ft = title.next title.next = ft + 1000.0 / run.FPS
class Game: def __init__(self, vw, vh): self.vw = vw self.vh = vh self.level = 0 self.background1 = Picture("clock.jpg") def restart(game): game.spatialhash = SpatialHash(64, 64, 64, 64) game.orbs = [] game.decohash = SpatialHash(64, 64, 64, 64) game.deco = [] game.active = [] game.lasers = {} game.dragged = None game.drag = (0, 0) game.selected = None game.new_size = 10 game.twist = 0 cx = 64 * 32 cy = 64 * 32 game.x = cx game.y = cy game.radius = 1000 game.view = View() game.view.x = 0 game.view.y = 0 game.view.angle = 0 game.coins = 0 game.rider = None def script1(game): game.player = Allefant(game.x, game.y + game.radius - 50, 20) game.player.spawn(game.spatialhash) game.orbs.append(game.player) game.active.append(game.player) outside = InverseOrb(game.x, game.y, game.radius) outside.spawn(game.spatialhash) game.orbs.append(outside) def script2(game): # ai = 360 / n # ao = 180 - ai = 180 - 360 / n # h*h + s2*s2 = r*r # s = 2 * r * sin(ai / 2) # h = 2 * r * cos(ai / 2) # c = n * s game.place(game.x, game.y, 30, 0, RoundBlock1) outerr = game.radius - 80 vdist = 220 a = 0 while 1: r = outerr - vdist * a / (2 * math.pi) if r < vdist: break x = game.x + math.sin(a) * r y = game.y + math.cos(a) * r b = game.place(x, y, 30, -a * 180 / math.pi + 90, RoundBlock1) a += 122 / r def script3(game): r = game.radius + 20 a = 0 while a < math.pi * 2: x = game.x + math.sin(a) * r y = game.y + math.cos(a) * r b = game.placedeco(x, y, 18, 180 * -a / math.pi, Block1) a += 118.7 / r def script4(game, x, y, dx, dy): prev = None r = game.new_size for i in range(40): orb = Orb(x, y, r) orb.spawn(game.spatialhash) game.orbs.append(orb) x += dx * game.new_size * 2 y += dy * game.new_size * 2 if prev: orb.append(prev) prev = orb def script5(game): r = game.radius + 20 a = 0 while a < math.pi * 2: x = game.x + math.sin(a) * r y = game.y + math.cos(a) * r b = game.placedeco(x, y, 18, 180 * -a / math.pi - 90, Wall) a += 118.7 / r def script6(game): r = 400 game.player = Allefant(game.x, game.y + r - 21, 20) game.player.spawn(game.spatialhash) game.orbs.append(game.player) game.active.append(game.player) outside = InverseOrb(game.x, game.y, r) outside.spawn(game.spatialhash) game.orbs.append(outside) a = 0 r += 20 while a < math.pi * 2: x = game.x + math.sin(a) * r y = game.y + math.cos(a) * r b = game.placedeco(x, y, 18, 180 * -a / math.pi, Block1) a += 118.7 / r def script7(game): for orb in game.orbs[:]: if orb.__class__ == Orb: game.remove(orb) elif orb.__class__ == Wall: a = orb.angle * math.pi / 180.0 x = orb.x y = orb.y ax = math.sin(a) ay = -math.cos(a) game.place(x + 42 * ax, y + 42 * ay, 19, a, Orb) game.place(x - 42 * ax, y - 42 * ay, 19, a, Orb) game.place(x + 21 * ax, y + 21 * ay, 19, a, Orb) game.place(x - 21 * ax, y - 21 * ay, 19, a, Orb) elif orb.__class__ == Block1: a = orb.angle * math.pi / 180.0 x = orb.x y = orb.y ax = math.cos(a) ay = math.sin(a) game.place(x + 42 * ax, y + 42 * ay, 19, a, Orb) game.place(x - 42 * ax, y - 42 * ay, 19, a, Orb) game.place(x + 21 * ax, y + 21 * ay, 19, a, Orb) game.place(x - 21 * ax, y - 21 * ay, 19, a, Orb) def colliders(self, x, y, r): orb = Orb(x, y, r) orb.hash = self.spatialhash return [x for x in orb.colliders() if not x.__class__ == InverseOrb] def render(self): px = (self.player.x - self.x) * 0.25 py = (self.player.y - self.y) * 0.25 glPushMatrix() glScalef(1 + 0.01 * math.cos(self.twist * math.pi * 2 / 120.0), 1 + 0.01 * math.sin(self.twist * math.pi * 2 / 120.0), 1) self.background1.draw_centered(self.view.x - px, self.view.y - py) glPopMatrix() drawn = 0 diagonal = (self.vw ** 2 + self.vh ** 2) ** 0.5 x, y = self.player.x, self.player.y pvs = self.decohash.get_in_circle(x, y, diagonal / 2) for orb in pvs: orb.draw() drawn += 1 pvs = self.spatialhash.get_in_circle(x, y, diagonal / 2) for layer in [-1, 0, 1]: for orb in pvs: if orb.layer() == layer: orb.draw() drawn += 1 if run.run.debugging: for layer in [-1, 0, 1]: for orb in pvs: if orb.layer() == layer: orb.draw_debug() glLoadIdentity() run.run.font.write(0, 443, "Level %d/6" % self.level, alpha = 0.8) run.run.font.write(320, 443, "Health %.f" % self.player.health, red = 1, green = 0, blue = 0, alpha = 0.8, center = True) run.run.font.write(640, 443, "Coins %d/%d" % (self.player.coins, self.coins), red = 1, green = 0.8, blue = 0.1, alpha = 0.8, right = True) if self.rider: if not self.rider.dead: run.run.font.write(320, 400, "Boss %.f" % self.rider.lifes, red = 1, green = 0.5, blue = 0, alpha = 0.8, center = True) def tick(self): for orb in self.active: if not orb.dead: d = (orb.x - self.player.x) ** 2 + (orb.y - self.player.y) ** 2 if d < orb.activity_radius * orb.activity_radius: orb.tick() self.view.x = self.player.x - 320 self.view.y = self.player.y - 240 self.twist += 1 def insert_action(game, x, y): orb = Orb(x, y, game.new_size) orb.spawn(game.spatialhash) game.orbs.append(orb) def place(game, x, y, r, a, what): orb = what(x, y, r) orb.angle = a orb.spawn(game.spatialhash) game.orbs.append(orb) return orb def insert_stuff(game, x, y, what): r = {"Wall" : 20, "Python" : 15, "Rider" : 50, "Spikes" : 20, "RoundBlock1" : 30, "Coin" : 10, "Leprechaun" : 15, "Lever" : 15, "Laser" : 40, "Portal" : 20} orb = game.place(x, y, r[what], 0, getattr(sprites, what)) orb.align() if orb.is_active(): game.active.append(orb) return orb def remove(game, orb): if not orb: return orb.disappear() if orb in game.orbs: game.orbs.remove(orb) if orb in game.deco: game.deco.remove(orb) if orb in game.active: game.active.remove(orb) def placedeco(game, x, y, r, a, what): orb = what(x, y, r) orb.angle = a orb.spawn(game.decohash) game.deco.append(orb) return orb def insert_block1(game, x, y): a = -game.view.angle b = game.place(x, y, 19, a, Block1) def insert_rotated_block1(game, x, y): a = -game.view.angle + 90 b = game.place(x, y, 19, a, Block1) def insert_wall(game, x, y): a = -game.view.angle b = game.place(x, y, 19, a, Wall) def place_moving_ball(game, x, y, a, dx, dy): orb = Ball1(x, y, 30) orb.angle = a orb.spawn(game.spatialhash) orb.movex = dx orb.movey = dy game.orbs.append(orb) game.active.append(orb) def place_moving_cogwheel(game, x, y, a): orb = Cogwheel(x, y, 25) orb.angle = a orb.spawn(game.spatialhash) orb.movex = 1 game.orbs.append(orb) game.active.append(orb) def place_moving_spring(game, x, y): orb = Spring(x, y, 10) orb.align() orb.spawn(game.spatialhash) orb.movey = 1 game.orbs.append(orb) game.active.append(orb) def save_level(self, num): fp = data.savepath("levels/%d" % num) f = open(fp, "w") for orb in self.deco: f.write("deco " + orb.__class__.__name__ + orb.as_string() + "\n") for orb in self.orbs: f.write("orbs " + orb.__class__.__name__ + orb.as_string() + "\n") f.close() def load_level(old, num): game = Game(old.vw, old.vh) game.restart() game.level = num fp = data.loadblock("levels/%d" % num) for line in fp: layername, classname, remainder = line.split(None, 2) if layername == "orbs": layer = game.orbs hash = game.spatialhash elif layername == "deco": layer = game.deco hash = game.decohash if classname == "Allefant": o = Allefant.from_string(remainder) o.spawn(hash) layer.append(o) game.player = o elif classname == "InverseOrb": o = InverseOrb.from_string(remainder) o.spawn(hash) layer.append(o) else: o = globals()[classname].from_string(remainder) o.spawn(hash) layer.append(o) if classname == "Laser": game.lasers[o.id] = o if classname == "Coin": game.coins += 1 if classname == "Rider": game.rider = o if o.is_active(): game.active.append(o) return game
def run_game(): game = run.game = run.game.load_level(run.last_level) clock = pygame.time.Clock() debug_no_render = False if not run.config.nomusic: pygame.mixer.music.load(data.filepath("loop/level1.ogg")) pygame.mixer.music.set_volume(0.8) pygame.mixer.music.play(-1) cursor = Picture("mouse.png") if run.first_time: run.message = Message(["Move: Left/Right or A/D", "Jump: Up or W", "Interact: Down or S"]) run.first_time = False fps = [] quit = False next = pygame.time.get_ticks() + 1000.0 / run.FPS while not quit: p = game.player gx = p.x - game.x gy = p.y - game.y gd = (gx ** 2 + gy ** 2) ** 0.5 if gd > 1: downx = gx / gd downy = gy / gd else: downx = 0 downy = 1 rightx = downy righty = -downx #gx /= game.radius #gy /= game.radius if gd > 30: gx = downx gy = downy else: gx = 0 gy = 0 mx, my = pygame.mouse.get_pos() rx = mx - game.vw / 2 ry = my - game.vh / 2 x = p.x + rightx * rx + downx * ry y = p.y + righty * rx + downy * ry game.reloaded = False for e in pygame.event.get(): if e.type == pygame.QUIT: quit = True elif e.type == pygame.KEYDOWN: if e.key == pygame.K_ESCAPE: quit = True if e.key == pygame.K_RETURN: if e.mod & pygame.KMOD_ALT: pygame.display.toggle_fullscreen() if e.key == pygame.K_DOWN or e.key == ord("s"): if run.message: if not run.message.showfull: run.message.showfull = True else: run.message = None if e.key == ord("p"): run.paused = not run.paused if run.debugging: if e.key == pygame.K_F12: debug_no_render = not debug_no_render if run.editing: edit.run = run edit.game = game edit.x = x edit.y = y edit.rightx = rightx edit.righty = righty for i in range(0, len(edit.commands), 2): com, func = edit.commands[i : i + 2] if (type(com) == str and e.key == ord(com)) or \ e.key == com: func() elif e.type == pygame.MOUSEBUTTONUP and run.editing: if e.button == 1: game.selected = game.dragged game.dragged = None if game.selected: game.new_size = game.selected.r elif e.type == pygame.MOUSEBUTTONDOWN and run.editing: mx, my = e.pos if e.button == 1: o = game.colliders(x, y, 10) if o: game.dragged = o[0] game.drag = (x, y) if e.button == 3: pass if game.reloaded: game = run.game continue if game.dragged: drx, dry = game.drag dro = game.dragged game.dragged.teleport_to(x + dro.x - drx, y + dro.y - dry) game.drag = (x, y) kx, ky = 0, 0 k = pygame.key.get_pressed() if not run.editing: if k[pygame.K_a] and not k[pygame.K_d]: kx = -1 if k[pygame.K_d] and not k[pygame.K_a]: kx = 1 if k[pygame.K_w] and not k[pygame.K_s]: ky = -1 if k[pygame.K_s] and not k[pygame.K_w]: ky = 1 if k[pygame.K_LEFT] and not k[pygame.K_RIGHT]: kx = -1 if k[pygame.K_RIGHT] and not k[pygame.K_LEFT]: kx = 1 if k[pygame.K_UP] and not k[pygame.K_DOWN]: ky = -1 if k[pygame.K_DOWN] and not k[pygame.K_UP]: ky = 1 b1, b2, b3 = pygame.mouse.get_pressed() game.gravityx = gx * 2 game.gravityy = gy * 2 game.downx = downx game.downy = downy game.rightx = rightx game.righty = righty if run.paused: pass elif run.message: run.message.tick() elif run.game_over: run.game_over = False quit = True elif run.level_done: run.level_done = False run.last_level += 1 game = run.game = game.load_level(run.last_level) if run.last_level > run.config.level: run.config.level = run.last_level run.config.save() continue else: p.kx = kx p.ky = ky game.tick() glClearColor(0, 0, 0, 1) glClear(GL_COLOR_BUFFER_BIT) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) game.view.angle = 180 * math.atan2(downx, downy) / math.pi p.angle = -game.view.angle game.view.x = p.x game.view.y = p.y glTranslate(game.vw / 2, game.vh / 2, 0) glRotate(game.view.angle, 0, 0, 1) glTranslate(-game.view.x, -game.view.y, 0) if not debug_no_render: game.render() glLoadIdentity() def show_fps(): now = pygame.time.get_ticks() while fps and fps[0] <= now - 1000: fps.pop(0) ds = [] for i in range(1, len(fps)): ds.append(1.0 * fps[i] - fps[i - 1]) if ds: avg = sum(ds) / len(ds) avg = 1000.0 / avg a = 1000.0 / min(ds) b = 1000.0 / max(ds) else: avg = a = b = 0 run.font.write(640, 0, "FPS: %.1f (%.1f - %.1f)" % (avg, b, a), right = True) #show_fps() if run.help: helptext = "\n" x = 0 pos = 0 for i in range(0, len(edit.commands), 2): func = edit.commands[i + 1] if func.__doc__: helptext += func.__doc__ + "\n" else: helptext += "?\n" pos += 1 if pos == 10: run.font.write(x, 0, helptext) x += 150 pos = 0 helptext = "\n" run.font.write(x, 0, helptext) if run.message: run.message.display() if run.editing: cursor.draw_centered(mx, my) pygame.display.flip() t = pygame.time.get_ticks() fps.append(t) w = int(next - t) if w > 0: pygame.time.wait(w) # If we're lagging behind, we can either skip rendering some frames, # or slow down. We choose the latter. if w < -500: next = t next += 1000.0 / run.FPS