Esempio n. 1
0
class Game(object):
    player1_cam = Vector2f(0, -11)
    player2_cam = Vector2f(94, -11)
    proj_spawn = [Vector2f(6, -10), Vector2f(125, -10)]

    def __init__(self):
        self._running = False
        self.camera = Vector2f(0,-11)

        self.camera_targets = [Game.player1_cam, Game.player2_cam]

    def init(self, size, fullscreen=False):
        flags = OPENGL|DOUBLEBUF
        if fullscreen:
            flags |= FULLSCREEN

        pygame.display.set_mode(size.xy, flags)
        pygame.display.set_caption('Ancient Earth')

        i = pygame.display.Info()
        self.size = Vector2i(i.current_w, i.current_h)

        glMatrixMode(GL_MODELVIEW)
        glEnable(GL_TEXTURE_2D)
        glDisable(GL_CULL_FACE)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)

        image.setup()

        self.stage = 1
        self.projection = Matrix.perspective(75, self.size, 0.1, 100)
        self.ortho = Matrix.ortho(self.size)

        v = np.array([
                0,0,0, 0,0,
                1,0,0, 1,0,
                1,1,0, 1,1,
                0,1,0, 0,1,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.quad = VBO(GL_QUADS, v, i)

        # parallax
        self.parallax_rep = 10
        v = np.array([
                0,0,0, 0,1,
                1,0,0, self.parallax_rep, 1,
                1,1,0, self.parallax_rep, 0,
                0,1,0, 0,0,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.repquad = VBO(GL_QUADS, v, i)
        self.parallax = Image('texture/sky.png', wrap=GL_REPEAT)
        self.hudbg = Image('texture/hud_bottom.png')

        self.fbo = FBO(self.size, format=GL_RGB8, depth=True)

        self.shader = Shader.load('default')
        self.shader_hud = Shader.load('hud')
        self.post = Shader.load('post')
        self.windmax = 1.0
        self.random_wind()

        self.ambient_light = (1.0, 1.0, 1.0)

        fontsize = 16 + int(self.res_hack() * 14)

        self.map = Map('map.json')
        self.clock = pygame.time.Clock()
        self.hud_msgbox = HUD(Vector2i(500,100), 'msgbox')
        self.hud_ui = HUD(Vector2i(self.size.x, self.size.x * (160./800)), 'ui')
        self.scrollbar = HUD(Vector2i(self.size.x,28), 'scrollbar')
        self.font = self.hud_msgbox.create_font(size=fontsize)
        self.font_ui = self.hud_ui.create_font(size=fontsize, font='Comic Sans MS')
        self.camera_max = self.map.width - 38
        self.catapults = [self.map.get_named_item('Catapult 1'), self.map.get_named_item('Catapult 2')]

        self.reset()

        with self.hud_msgbox:
            self.hud_msgbox.clear((0,1,1,1))

    def res_hack(self):
        """ return [0..1] based on resolution where 800 gives 0 and 1920 gives 1 """
        a = float(self.size.x) - 800.
        b = 1920. - 800.
        return clamp(a/b, 0.0, 1.0)

    def running(self):
        return self._running

    def time(self):
        """ Get current time as float """
        return float(pygame.time.get_ticks()) / 1000.0

    def reset(self):
        self.projectile = DummyProjectile()
        self.angle = [60, 60]
        self.force = [150, 150]
        self.player = 0
        self.firing = False
        self.sweep = None
        self.miss = False
        self.follow_cam = None
        self.is_over = False
        self.textbuf = []
        self.texttime = -10.0
        self.catapults[0].set_loaded(True)
        self.random_wind()

    @event(pygame.QUIT)
    def quit(self, event=None):
        self._running = False

    def over(self):
        self.is_over = True

    def random_wind(self):
        r = float(random.randint(0, 10000)) / 10000 # [0..1]
        r = r * 2.0 - 1.0 # [-1..1]
        self.wind = r * self.windmax

    @event(pygame.KEYDOWN)
    def on_keypress(self, event):
        if event.key == 113 and event.mod & KMOD_CTRL: # ctrl+q
            return self.quit()
        if event.key == 27: # esc
            if not self.is_over:
                return self.quit()
            else:
                self.reset()
                return True
        if event.key == 13: # enter
            if not self.firing and not self.sweep:
                self.projectile_fire()

    @event(pygame.MOUSEBUTTONDOWN)
    def on_button(self, event):
        if not self.firing:
            if event.button == 4: self.camera.x += 5
            if event.button == 5: self.camera.x -= 5

    def next_player(self):
        self.player = 1 - self.player
        self.sweep = CameraSweep(src=self.follow_cam, dst=self.camera_targets[self.player])
        self.follow_cam = None
        self.firing = False
        self.random_wind()

    def projectile_fire(self):
        if not self.firing:
            self.firing = True

            a = math.radians(self.angle[self.player])
            f = self.force[self.player] * 5
            force = Vector2f(math.cos(a), math.sin(a)) * f

            if self.player == 1:
                force.x *= -1

            p = Game.proj_spawn[self.player]
            self.catapults[self.player].set_loaded(False)
            self.projectile = item.create('projectile', name='projectile', x=p.x, y=p.y, flip=self.player==0)
            self.projectile.impulse(force, 0.1)

    def projectile_miss(self, projectile):
        self.miss = True # defer so the projectile is rendered one more frame

    def projectile_hit(self, hit):
        # hack: remove all other message
        self.textbuf = []

        # hack: directly inject message
        if self.player != hit:
            self.text = 'Player %d hit the other player and won!' % (self.player+1)
        else:
            self.text = 'Player %d hit himself and lost...' % (self.player+1)
        self.text += '\n\nPress ESC to restart.'

        if hit == self.player:
            self.catapults[self.player].set_broken()
        else:
            self.catapults[1-self.player].set_broken()

        game.over()

    def poll(self):
        global event_table
        for event in pygame.event.get():
            func = event_table.get(event.type, None)
            if func is None:
                continue
            func(self, event)

    def update(self):
        if self.is_over:
            self.clock.tick(60)
            return

        key = pygame.key.get_pressed()

        if self.miss:
            self.message('Player %d missed the target' % (self.player+1,))
            self.old_projectile = self.projectile
            self.projectile = DummyProjectile(4)
            self.miss = False

        if not self.firing and not self.sweep:
            if key[260]: self.camera.x -= 1
            if key[262]: self.camera.x += 1

            if key[273]: self.angle[self.player] += 0.3
            if key[274]: self.angle[self.player] -= 0.3
            if key[275]: self.force[self.player] += 1
            if key[276]: self.force[self.player] -= 1

            self.camera.x = min(max(self.camera.x, 0), self.camera_max)
            self.angle[self.player] = min(max(self.angle[self.player], 0), 90)
            self.force[self.player] = min(max(self.force[self.player], 0), 3000)

        dt = 1.0 / self.clock.tick(60)
        self.map.update()

        # fixed step for better physics "simulation"
        self.projectile.update(self.map, 0.05)

        if self.sweep:
            self.camera, self.sweep = self.sweep.update(dt)
            if not self.sweep:
                self.catapults[self.player].set_loaded(True)

    def render_hud(self, camera):
        with self.hud_msgbox as hud:
            hud.clear((0,0,0,0))
            hud.cr.identity_matrix()

            t = pygame.time.get_ticks() / 1000.0
            s = (t - self.texttime) / 1.8

            if self.is_over:
                s = 0

            if s > 1.0:
                if len(self.textbuf) > 0:
                    self.texttime = pygame.time.get_ticks() / 1000.0
                    self.text = self.textbuf.pop(0)
            else:
                a = min(1.0-s, 0.2) * 5
                textcolor = (0,0,0,a)
                hud.cr.translate(0,25)
                hud.text(self.text, self.font, color=textcolor, width=hud.width, alignment=ALIGN_CENTER)

        visible = 34. / self.camera_max
        offset = camera.x / float(self.camera_max + 42.0)
        with self.scrollbar as hud:
            w = self.wind / self.windmax * 0.49
            hud.clear((1,0,1,0))
            hud.rectangle(self.size.x * offset, 10, self.size.x * visible, 8, (0,1,1,1))
            hud.rectangle(self.size.x * (0.5+w) - 4, 0, 8, hud.height, (1,0,0,0.8))

        with self.hud_ui as hud:
            hack = self.res_hack() * 20

            hud.clear((1,1,1,0))
            hud.cr.identity_matrix()
            hud.cr.translate(30 + hack, 30 + hack)
            hud.text('Player %d' % (self.player+1,), self.font_ui)

            hud.cr.identity_matrix()
            hud.cr.translate(30 + hack, 70 + hack)
            hud.text('Angle: %3.0f' % self.angle[self.player], self.font_ui)

            hud.cr.identity_matrix()
            hud.cr.translate(30 + hack, 100 + hack)
            hud.text('Force: %3.0f' % self.force[self.player], self.font_ui)

    def render_world(self, camera):
        view = Matrix.lookat(
            camera.x + 19, camera.y, 15,
            camera.x + 19, camera.y, 0,
            0,1,0)

        with self.fbo as frame:
            frame.clear(0,0.03,0.15,1)

            Shader.upload_projection_view(self.projection, view)
            Shader.upload_game(None)
            Shader.upload_light(self.ambient_light, self.cull_lights())

            # parallax background
            pm = Matrix.transform(
                0.75 * camera.x, camera.y * 0.5 - 12, 0,
                (19*4) * self.parallax_rep, 19, 0
            )
            self.shader_hud.bind()
            self.parallax.texture_bind()
            Shader.upload_model(pm)
            self.repquad.draw()

            Shader.upload_projection_view(self.projection, view)

            self.shader.bind()
            self.map.draw()

            # entities
            for obj in self.map.obj:
                obj.draw()
            if not self.is_over:
                self.projectile.draw()

    def render(self):
        glClearColor(1,0,1,1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

        camera = self.camera.copy()
        if self.projectile:
            camera.x = min(max(self.projectile.pos.x - 19, 0), self.camera_max)
            self.follow_cam = camera
        elif self.follow_cam:
            camera = self.follow_cam

        self.render_hud(camera)
        self.render_world(camera)

        mat = Matrix.scale(self.size.x, self.size.y)
        Shader.upload_projection_view(self.ortho, Matrix.identity())
        Shader.upload_model(mat)

        self.fbo.bind_texture()
        self.post.bind()
        self.quad.draw()

        y = self.size.x * (160./800)

        # hud background
        pm = Matrix.transform(
            0, y, 0,
            self.size.x, -y, 1
        )
        self.shader_hud.bind()
        self.hudbg.texture_bind()
        Shader.upload_model(pm)
        self.quad.draw()

        # ui
        pm = Matrix.transform(
            0, self.hud_ui.height, 0,
            self.hud_ui.width, -self.hud_ui.height, 1
        )
        self.hud_ui.draw()
        self.shader_hud.bind()
        Shader.upload_model(pm)
        self.quad.draw()

        # messagebox
        mat = Matrix.translate(self.size.x / 2 - self.hud_msgbox.width / 2, self.size.y - self.hud_msgbox.height)
        Shader.upload_model(mat)
        self.hud_msgbox.draw()

        # scrollbar
        mat = Matrix.translate(0, y-22)
        Shader.upload_model(mat)
        self.scrollbar.draw()

        pygame.display.flip()

    def cull_lights(self):
        return self.map.objects['Lights']

    def run(self):
        self._running = True
        while self.running():
            try:
                self.poll()
                self.update()
                self.render()
            except:
                traceback.print_exc()

    def message(self, text):
        self.textbuf.append(text)
Esempio n. 2
0
 def next_player(self):
     self.player = 1 - self.player
     self.sweep = CameraSweep(src=self.follow_cam, dst=self.camera_targets[self.player])
     self.follow_cam = None
     self.firing = False
     self.random_wind()