Exemple #1
0
    def _handle_tile_state_click(self, x, y, button):
        """Handle a click in tile-editing state."""
        add = (button == sdl2.SDL_BUTTON_LEFT)
        tile = self._level.screen_coords_to_tile(vector.Vector(x, y))

        if tile:
            tile_coords = tile.coords
            height = tile.height + (1 if add else -1)
            colour = tile.colour
        else:
            tile_coords = self._level.screen_coords_to_tile_coords(
                vector.Vector(x, y))
            height = 1 if add else 0
            colour = self.colour

        if self._level.tile_coords_valid(tile_coords):
            index = self._level.tile_coords_to_array_index(tile_coords)
            if height > 0:
                self._level.tiles[index.y, index.x] = typingdefense.level.Tile(
                    self._app,
                    self._level.cam,
                    tile_coords,
                    height,
                    colour)
            else:
                self._level.tiles[index.y, index.x] = None
Exemple #2
0
    def _setup_move(self, timer):
        if self.next_tile:
            self._start_pos = vector.Vector(self.current_tile.x,
                                            self.current_tile.y,
                                            self.current_tile.top)
            self._end_pos = vector.Vector(self.next_tile.x,
                                          self.next_tile.y,
                                          self.next_tile.top)
            distance = (self._end_pos - self._start_pos).magnitude


            self._move_start = timer.time + self._scaled_pause()
            self._move_end = self._move_start + distance / self._scaled_speed()
Exemple #3
0
    def _build_paths(self):
        """Calculate paths from each tile to the base."""
        # Clear any previous path info
        for _, tile in numpy.ndenumerate(self.tiles):
            if tile:
                tile.path_next = None

        # TODO: Start a 0,0 for now, but eventually will have to work out where
        # the base is and start there.
        start = self.lookup_tile(vector.Vector(0, 0))
        if not start:
            return

        # TODO: consider height

        frontier = deque([start])
        visited = set([start])
        while len(frontier) > 0:
            tile = frontier.popleft()

            for nxt in [
                    t for t in self.tile_neighbours(tile)
                    if t.empty and t not in visited
            ]:
                frontier.append(nxt)
                visited.add(nxt)
                nxt.path_next = tile
Exemple #4
0
    def _handle_wave_state_click(self, x, y, button):
        """Handle a click in wave-editing state."""
        add = (button == sdl2.SDL_BUTTON_LEFT)
        tile = self._level.screen_coords_to_tile(vector.Vector(x, y))

        if add and tile:
            if self.phase not in tile.waves:
                wave = enemy.Wave(self._app, self._level, tile,
                                  enemy_type=self.enemy_type)

                # Extend the wave list if it is not long enough.
                self._level.waves += [[]] * (self.phase + 1 -
                                             len(self._level.waves))
                self._level.waves[self.phase].append(wave)
                tile.waves[self.phase] = wave

                self.selected_wave = wave
            else:
                self.selected_wave = tile.waves[self.phase]

        if not add and tile and self.phase in tile.waves:
            wave = tile.waves[self.phase]

            self._level.waves[self.phase].remove(wave)
            del(tile.waves[self.phase])
Exemple #5
0
    def __init__(self, app, level, tile):
        super().__init__(app, level, tile, SlowTower._COLOUR)
        self._level = level
        self._coords = vector.Vector(tile.x, tile.y)

        for t in level.tile_neighbours(tile):
            t.slow = True
Exemple #6
0
    def __init__(self, app, cam, coords, height, colour):
        """Construct a (hexagonal) tile.

        coords is a vector containing the horizontal coordinates of the tile,
        using axial coordinates.
        height is the number of stacks in the tile.
        """
        self.coords = coords
        self.height = height
        self.colour = colour
        self.path_next = None
        self.tower = None

        self._shader = glutils.ShaderInstance(
            app, 'level.vs', 'level.fs',
            [('transMatrix', GL.GL_FLOAT_MAT4, cam.trans_matrix_as_array()),
             ('colourIn', GL.GL_FLOAT_VEC4, None)])
        self._hex = glutils.Hex(vector.Vector(self.x, self.y, 0), Tile.SIZE,
                                Tile.DEPTH, height)

        self.outline_colour = colour
        self.face_colour = copy.copy(self.outline_colour)
        self.face_colour.s = self.face_colour.s / 2

        # Dictionary of waves, keyed by the level phase in which they appear.
        self.waves = {}

        # Whether the tile is a 'slow movement' tile.
        self.slow = False
Exemple #7
0
    def world_to_tile_coords(world_coords):
        """Convert world (x, y) coordinates to tile (q, r) coordinates.

        Note that this is a 2D conversion only."""
        q = (world_coords.x * math.sqrt(3) / 3 -
             world_coords.y / 3) / Tile.SIZE
        r = (world_coords.y * 2 / 3) / Tile.SIZE
        return _hex_round(vector.Vector(q, r))
Exemple #8
0
    def __init__(self, app, cam, tile, origin, z):
        self.health = Base.START_HEALTH
        self.tile = tile

        self._shader = glutils.ShaderInstance(
            app, 'level.vs', 'level.fs',
            [('transMatrix', GL.GL_FLOAT_MAT4, cam.trans_matrix_as_array())])
        self._hex = glutils.Hex(vector.Vector(tile.x, tile.y, 0),
                                Tile.SIZE * 0.8, Tile.DEPTH, 2)
Exemple #9
0
    def screen_coords_to_tile(self, coords):
        """Work out which tile a given point in screen coordinates is in."""
        pixel_info = self._picking_texture.read(coords.x, coords.y)

        # The blue value will be 0 if no tile was hit
        if pixel_info[2] == 0:
            return None

        # The q and r coordinates are stored in the r and g values, respectively
        return self.lookup_tile(vector.Vector(pixel_info[0], pixel_info[1]))
Exemple #10
0
    def __init__(self, app, level, tile, speed, move_pause, value, damage,
                 colour, health=1, words=1,
                 wordlength=phrasebook.PhraseBook.SHORT_PHRASE):
        # TODO:temp
        self.prev_time = 0
        self.prev_origin = vector.Vector(0, 0, 0)

        self._app = app
        self._level = level
        self._tile = tile

        # Phrase variables
        self._words = words
        self._wordlength = wordlength
        self.phrase = None

        # Movement variables
        self.origin = vector.Vector(tile.x, tile.y, tile.top)
        self.prev_tile = None
        self.current_tile = tile
        self.next_tile = tile.path_next
        self._speed = speed
        self._move_pause = move_pause
        self._start_pos = None
        self._end_pos = None
        self._move_start = 0
        self._move_end = 0

        # Graphics variables
        self._shader = glutils.ShaderInstance(
            app, 'level.vs', 'level.fs',
            [('transMatrix', GL.GL_FLOAT_MAT4, None),
             ('colourIn', GL.GL_FLOAT_VEC4, colour)])
        self._hex = glutils.Hex(vector.Vector(0, 0, 0), 0.5, 1)

        self.health = health
        self.damage = damage
        self.unlink = False
        self.value = value

        # Initial setup
        self._setup_move(level.timer)
        self._setup_phrase()
Exemple #11
0
 def __init__(self, app, level, tile, colour):
     self._shader = glutils.ShaderInstance(
         app, 'level.vs',
         'level.fs', [('transMatrix', GL.GL_FLOAT_MAT4,
                       level.cam.trans_matrix_as_array()),
                      ('colourIn', GL.GL_FLOAT_VEC4, colour)])
     self._hex = glutils.Hex(vector.Vector(tile.x, tile.y, tile.top),
                             0.5,
                             2,
                             stacks=4)
Exemple #12
0
    def __init__(self, app, editor):
        self._editor = editor
        self._colourbutton = _ColourButton(app, vector.Vector(10, 10))

        font = app.resources.load_font('menufont.fnt')
        self._enemy_type_text = text.Text2D(app, font, '', 0, 0, 24)
        self._enemy_count_text = text.Text2D(app, font, '', 0, 24, 24)
        self._start_time_text = text.Text2D(app, font, '', 0, 48, 24)
        self._spawn_gap_text = text.Text2D(app, font, '', 0, 72, 24)
        self._phase_text = text.Text2D(app, font, '', 0, app.window_height - 24,
                                       24)
Exemple #13
0
    def draw(self):
        coords = vector.Vector(self.origin.x, self.origin.y, self.origin.z)
        t = util.Transform(coords)
        m = self._level.cam.trans_matrix * t.matrix
        self._shader.set_uniform('transMatrix',
                                 numpy.asarray(m).reshape(-1),
                                 download=False)
        with self._shader.use():
            self._hex.draw()

        self.phrase.draw(coords)
Exemple #14
0
    def tile_neighbours(self, tile):
        """Find the neighbouring tiles for a given tile.

        Takes a Tile and returns a list of Tiles.
        Does not consider whether a given tile is empty or not.
        """
        dirs = [(+1, 0), (+1, -1), (0, -1), (-1, 0), (-1, 1), (0, 1)]
        neighbours = []
        for d in dirs:
            neighbour_coords = vector.Vector(tile.q + d[0], tile.r + d[1])
            neighbour = self.lookup_tile(neighbour_coords)
            if neighbour:
                neighbours.append(neighbour)
        return neighbours
Exemple #15
0
    def on_click(self, x, y, button):
        """Handle a mouse click."""

        if self.state == Level.State.build:
            hit_hud = self._hud.on_click(x, y)

            if not hit_hud:
                tile = self.screen_coords_to_tile(vector.Vector(x, y))
                if tile and tile.empty:
                    # TODO: Check if the tower ends up leaving no route to the
                    # base
                    if (self.tower_creator is not None
                            and self.money >= self.tower_creator.COST):
                        tower = self.tower_creator(self._app, self, tile)
                        self._towers.append(tower)
                        tile.tower = tower
                        self.money -= tower.COST
Exemple #16
0
    def load(self):
        """Load the level."""
        self._min_coords = vector.Vector(-100, -100)
        self._max_coords = vector.Vector(100, 100)

        width = self._max_coords.x - self._min_coords.x + 1
        height = self._max_coords.y - self._min_coords.y + 1
        self.tiles = numpy.empty([height, width], dtype=object)
        try:
            with open('resources/levels/test_level.tdl', 'r') as f:
                lvl_info = json.load(f)
                # Load tiles
                for tile_info in lvl_info['tiles']:
                    coords = vector.Vector(tile_info['q'], tile_info['r'])
                    colour = util.Colour(tile_info['colour']['r'],
                                         tile_info['colour']['g'],
                                         tile_info['colour']['b'],
                                         tile_info['colour']['a'])
                    idx = self.tile_coords_to_array_index(coords)
                    self.tiles[idx.y,
                               idx.x] = Tile(self._app, self.cam, coords,
                                             tile_info['height'], colour)

                # Load Waves
                phase_idx = 0
                if 'waves' in lvl_info:
                    for phase_info in lvl_info['waves']:
                        waves = []
                        for wave_info in phase_info:
                            coords = vector.Vector(wave_info['q'],
                                                   wave_info['r'])
                            tile = self.lookup_tile(coords)
                            wave = enemy.Wave(
                                self._app,
                                self,
                                tile,
                                enemy_count=wave_info['enemy_count'],
                                start_time=wave_info['start_time'],
                                spawn_gap=wave_info['spawn_gap'],
                                enemy_type=wave_info['enemy_type'])
                            tile.waves[phase_idx] = wave
                            waves.append(wave)
                        self.waves.append(waves)
                        phase_idx += 1

        except FileNotFoundError:
            pass

        tile = self.lookup_tile(vector.Vector(0, 0))
        self.base = Base(self._app, self.cam, tile, vector.Vector(0, 0),
                         Tile.HEIGHT)

        self.money = 500
Exemple #17
0
def _cube_round(fc):
    """Round fractional cube-format hex coordinates."""
    rx = round(fc.x)
    ry = round(fc.y)
    rz = round(fc.z)

    x_diff = abs(rx - fc.x)
    y_diff = abs(ry - fc.y)
    z_diff = abs(rz - fc.z)

    if x_diff > y_diff and x_diff > z_diff:
        rx = -ry - rz
    elif y_diff > z_diff:
        ry = -rx - rz
    else:
        rz = -rx - ry

    return vector.Vector(rx, ry, rz)
Exemple #18
0
    def unproject(self, screen_coords, world_z):
        # Convert from screen coords to NDCs
        x = screen_coords.x * 2 / self.screen_width - 1
        y = screen_coords.y * 2 / self.screen_height - 1

        inv_trans = np.linalg.inv(self.trans_matrix)
        near_coords = np.array([[x], [y], [0], [1]])
        far_coords = np.array([[x], [y], [1], [1]])

        world_near = inv_trans * near_coords
        world_far = inv_trans * far_coords

        # Perspective divide
        world_near /= world_near[3, 0]
        world_far /= world_far[3, 0]

        world_neartofar = world_far - world_near
        ratio = (world_z - world_near[2, 0]) / world_neartofar[2, 0]

        return vector.Vector(
            world_near[0, 0] + (world_neartofar[0, 0] * ratio),
            world_near[1, 0] + (world_neartofar[1, 0] * ratio),
            world_near[2, 0] + (world_neartofar[2, 0] * ratio))
Exemple #19
0
def _cube_to_hex(c):
    """Convert cube-format hex coordinates to hex."""
    return vector.Vector(c.x, c.z)
Exemple #20
0
def _hex_to_cube(h):
    """Convert axial-format hex coordinates to cube-format."""
    return vector.Vector(h.q, -h.q - h.r, h.r)
Exemple #21
0
 def tile_coords_to_array_index(self, coords):
     """Work out the array slot for a given set of axial tile coords."""
     return vector.Vector(coords.q - self._min_coords.q,
                          coords.r - self._min_coords.r)
Exemple #22
0
 def __init__(self, app, level, tile):
     super().__init__(app, level, tile, MoneyTower._COLOUR)
     self._level = level
     self._tile = tile
     self._coords = vector.Vector(tile.x, tile.y)
     self._last_fire = 0