Exemple #1
0
 def test_elem_wise(self):
     v1 = Vector(5, 2)
     v2 = Vector(1, 2)
     self.assertEqual(v1 + v2, v2 + v1)
     self.assertEqual(v1 + v2, (6, 4))
     self.assertEqual(v1.scale(*v2), (5, 4))
     v1 += v2
     self.assertEqual(v1, (6, 4))
Exemple #2
0
 def test_cmp(self):
     v1 = Vector(4.3, 5.2)
     v2 = Vector(6.1, 2.8)
     self.assertFalse(v1 == v2)
     self.assertTrue(v1 != v2)
     self.assertTrue(Vector(2.0, 1.0) == Vector(2, 1))
     self.assertTrue(v1 > v2)
     self.assertTrue(v1 == (4.3, 5.2))
 def test_quad_damage(self):
     survivor = Survivor(0, 0)
     bullet = Bullet(Vector(0, 0), Vector(3, 0), 0, survivor)
     bullet.pos += bullet.vel
     before_4x = bullet.calc_dmg()
     Drop.actives["4x"] = 1
     after4x = bullet.calc_dmg()
     self.assertEqual(after4x / before_4x, 4.0)
     self.assertTrue(after4x > before_4x)
Exemple #4
0
    def __init__(self, x, y, width=None, height=None):

        if width is None and height is None:
            self.width, self.height = Tile.length, Tile.length
        else:
            self.width, self.height = width, height
        self._size = Vector(self.width, self.height)
        self.to = None
        self.pos = Vector(x, y)
Exemple #5
0
 def test_get_and_setitem(self):
     v = Vector(3, 5.3)
     self.assertEqual(v.x, v[0], v["x"])
     self.assertEqual(v.y, v[1], v["y"])
     v.x = 3.2
     v.y = 5
     self.assertEqual(v.x, v[0], v["x"])
     self.assertEqual(v.y, v[1], v["y"])
     v[0] = 0.9
     self.assertEqual(v.x, v[0], v["x"])
     v["x"] = 4.6
     self.assertEqual(v.x, v[0], v["x"])
Exemple #6
0
    def reset(self):
        self.r = 0  # rotation in radians
        self.p = Vector()  # position
        self.v = Vector()  # velocity
        self.a = Vector()  # acceleration

        self.reset_time()

        self.t.up()
        self._update_t()
        self.t.down()

        self.t.clear()
Exemple #7
0
class BaseClass:
    """The Baseclass for the Survivor, Zombie, Bullet and PickUp classes
    Params:
    x: The x coordinate
    y: The y coordinate
    width: (Optional) Used by the Bullet Class as it has another size. Defaults to Tile.length
    height: (Optional) Used by the Bullet Class as it has another size. Defaults to Tile.length"""
    def __init__(self, x, y, width=None, height=None):

        if width is None and height is None:
            self.width, self.height = Tile.length, Tile.length
        else:
            self.width, self.height = width, height
        self._size = Vector(self.width, self.height)
        self.to = None
        self.pos = Vector(x, y)

    def get_centre(self):
        return self.pos + self._size.scale(1 / 2)

    centre = property(get_centre,
                      doc="""Return a vector of the pos in the middle of self
                                         >>> a = BaseClass(x=0, y=0, width=10, height=10)
                                         >>> a.centre
                                         Vector(x=5, y=5)""")

    def get_number(self):
        """Return the index of tile that self is on"""

        return int(self.pos.x // Tile.length +
                   self.pos.y // Tile.length * Options.tiles_x)

    def get_tile(self):
        """Return the tile on which self is"""
        return Tile.instances[self.get_number()]
Exemple #8
0
 def set_target(self, next_tile):
     self.to = next_tile.pos
     angle = angle_between(*self.pos, *next_tile.pos)
     assert angle % (math.pi /
                     2) == 0., "angle: %s to: %s pos: %s mod %s" % (
                         angle, self.to, self.pos, angle % math.pi / 2)
     self.vel = Vector(*self.angle_to_vel[angle])
Exemple #9
0
 def __init__(self, x, y):
     self.current_gun = 0
     self.direction = pi * 3 / 1 / 2
     self.img = Survivor.imgs[dir2chr[self.direction]]
     super().__init__(x, y)
     self.health = 100 << 10 * Options.debug  # 100 if not debug, 10*2**10 if debug
     self.vel = Vector(0, 0)
     self.init_ammo_count = 100, 50, 150, 50
     self.ammo_count = list(self.init_ammo_count)
Exemple #10
0
def shooting(survivor, keys):

    if keys[pygame.K_LEFT]:
        survivor.rotate(pi)
        Bullet(survivor.centre, Vector(-Options.bullet_vel, 0),
               survivor.current_gun, survivor)
    elif keys[pygame.K_RIGHT]:
        survivor.rotate(0)
        Bullet(survivor.centre, Vector(Options.bullet_vel, 0),
               survivor.current_gun, survivor)
    elif keys[pygame.K_UP]:
        survivor.rotate(pi / 2)
        Bullet(survivor.centre, Vector(0, -Options.bullet_vel),
               survivor.current_gun, survivor)
    elif keys[pygame.K_DOWN]:
        survivor.rotate(pi * 3 / 2)
        Bullet(survivor.centre, Vector(0, Options.bullet_vel),
               survivor.current_gun, survivor)
Exemple #11
0
 def __init__(self, x, y, is_solid):
     self.parent = None
     self.h, self.g, self.f = 0, 0, 0
     self.walkable = not is_solid
     self.pos = Vector(x, y)
     self.number = Tile.amnt_tiles
     Tile.amnt_tiles += 1
     if is_solid:
         Tile.solids_list.append(self)
     else:
         Tile.opens.add(self)
     Tile.instances.append(self)
Exemple #12
0
def walking(survivor, keys):
    if survivor.to is not None:  # If the survivor is between two tiles
        return
    if keys[pygame.K_w]:  # North
        future_tile_num = survivor.get_number() - Options.tiles_x
        if Tile.on_screen(0, future_tile_num):
            future_tile = Tile.instances[future_tile_num]
            if future_tile.walkable or "trans" in Drop.actives:
                survivor.set_target(future_tile)
                survivor.rotate(pi / 2)
                survivor.vel = Vector(0, -Options.speed)

    if keys[pygame.K_s]:  # South
        future_tile_num = survivor.get_number() + Options.tiles_x
        if Tile.on_screen(1, future_tile_num):
            future_tile = Tile.instances[future_tile_num]
            if future_tile.walkable or "trans" in Drop.actives:
                survivor.set_target(future_tile)
                survivor.rotate(pi * 3 / 2)
                survivor.vel = Vector(0, Options.speed)

    if keys[pygame.K_d]:  # East
        future_tile_num = survivor.get_number() + 1
        if Tile.on_screen(2, future_tile_num):
            future_tile = Tile.instances[future_tile_num]
            if future_tile.walkable or "trans" in Drop.actives:
                survivor.set_target(future_tile)
                survivor.rotate(0)
                survivor.vel = Vector(Options.speed, 0)

    if keys[pygame.K_a]:  # West
        future_tile_num = survivor.get_number() - 1
        if Tile.on_screen(3, future_tile_num):
            future_tile = Tile.instances[future_tile_num]
            if future_tile.walkable or "trans" in Drop.actives:
                survivor.set_target(future_tile)
                survivor.rotate(pi)
                survivor.vel = Vector(-Options.speed, 0)
Exemple #13
0
 def __init__(self, x, y):
     self.direction = math.pi
     type_ = randint(0, 3)
     self.type = type_
     self.org_img = Zombie.imgs[type_]
     self.img = self.org_img
     self.speed = Zombie.speed_tuple[type_]
     self.health_func = Zombie.health_func_tuple[type_]
     self.health = self.health_func(Zombie.base_health)
     self.org_health = self.health
     self.angle_to_vel = {
         0: (self.speed, 0),
         math.pi / 2: (0, -self.speed),
         math.pi: (-self.speed, 0),
         math.pi * 3 / 2: (0, self.speed)
     }
     self.vel = Vector(0, 0)
     super().__init__(x, y)
     Zombie.instances.add(self)
     self.path = []
     self.last_angle = 0.
     self.path_colour = Colours.random(s=(0.5, 1))
     logging.debug("speed: %s type. %s", self.speed, self.type)
Exemple #14
0
 def test_funcs(self):
     v1 = Vector(5.3, 2.0)
     self.assertEqual(v1.as_ints(), Vector(5, 2))
     v2 = v1.copy()
     v2.x = 4.7
     self.assertNotEqual(v1.x, 4.7)
     v = Vector(6, 8)
     self.assertEqual(abs(v), v.magnitude(), 10.0)
     self.assertEqual(v.magnitude_squared(), v.magnitude()**2)
     self.assertEqual(abs(v), math.sqrt(v.magnitude_squared()))
     v.y = -5.3
     self.assertEqual(v.signs(), (1, -1))
     v.x = 0
     self.assertEqual(v.signs(), (0, -1))
     v1 = Vector(4.0, 2.0)
     v2 = Vector(3.0, 1.0)
     self.assertEqual((v1 - v2).manhattan_dist(), 2)
     v2.x = 2.0
     self.assertEqual((v1 - v2).manhattan_dist(), 3)
     self.assertEqual((v1 - v1).manhattan_dist(), 0)
Exemple #15
0
class Tile:
    """Create a tile
    Tile.create() creates all tiles that fit in the map
    Should not be created seperately only through Tile.create()
    Params:
    x: x coordinate of the tile
    y: y coordinate of the tile
    is_solid: True if the tile is not walkable else False
    idx: the index of the tile starting at 0 in the topleft like this:
    012
    345
    678"""
    instances, solids, opens, solids_list, loop_set = [], set(), set(), [], set()
    length = Options.tile_length
    size = Vector(length, length)
    amnt_tiles = 0  # Incremented when a tile is created

    with open(Options.mappath) as file:
        file_str = file.read()
        map_ = [x == "#" for x in file_str.replace("\n", "")]

    solid_nums = {i for i, x in enumerate(map_) if x}
    # Set of the indices of all solid tiles

    @classmethod
    def create(cls):
        """Create tiles and set some class variables when finished"""
        error_msg = """len(cls.map_) is not equal to the amount of
        tiles vertically multiplied by the amount of tiles horizontally.

        This is usually caused by tile.py being initiated before
        init_screen.py or options.py.
        note that tile.py is initiated by e.g. miscellaneous.py
        
        It could also be caused by the map file having a blank line at
        the end, or some lines are longer than others."""
        assert len(cls.map_) == Options.tiles_x * Options.tiles_y, dedent(error_msg)
        map_gen = iter(cls.map_)
        for y in range(0, Options.height, cls.length):
            for x in range(0, Options.width, cls.length):
                cls(x, y, next(map_gen))
        cls.solids = set(cls.solids_list)
        cls.loop_set = cls.compress_solids()

    @classmethod
    def delete(cls):
        cls.instances = []
        cls.solids_list = []
        cls.solids = set()
        cls.opens = set()
        cls.loop_set = set()
        cls.amnt_tiles = 0

    @classmethod
    def compress_solids(cls):
        """returns a comressed cls.solids to be used when drawing
        It returns a list of a tuple with the first tile in a long line of solids and
        then how many solids are after it in the line for all lines on the map.
        This makes the drawing much faster,
        example:
        ##..###
        ####.#.
           |
           v
        {(tile.Tile object at 0x0..., 2), (tile.Tile ..., 3), (tile.Tile ..., 4), (tile.Tile ..., 1)}
        It ignores open tiles
        It is not necessary to compress opens since they are drawn by
        filling the screen.

        NOTE: A new group starts at a newline
        TODO: Make it so the loop_list is the type of tile with the fewest intances
        rtype: set
        """

        splitted_map = zip(*([iter(cls.map_)] * Options.tiles_x))
        # Split map on every newline

        compressed_map = []
        # A compressed list with True if solid and False if open
        # Looks something like this -> [(True, 5), (False, 2), (True, 9), ...]
        for row in splitted_map:
            for group in groupby(row):
                compressed_map.append((group[0], len(list(group[1]))))

        filtered_opens = (j for i, j in compressed_map if i)  # filter open tiles and remove the "True"
        solids_iter = iter(cls.solids_list)
        # Map solids onto compressed map
        loop_set = set()
        for length, tile in zip(filtered_opens, solids_iter):
            loop_set.add((tile, length))
            for _ in range(length - 1):
                next(solids_iter)
        return loop_set

    def __init__(self, x, y, is_solid):
        self.parent = None
        self.h, self.g, self.f = 0, 0, 0
        self.walkable = not is_solid
        self.pos = Vector(x, y)
        self.number = Tile.amnt_tiles
        Tile.amnt_tiles += 1
        if is_solid:
            Tile.solids_list.append(self)
        else:
            Tile.opens.add(self)
        Tile.instances.append(self)

    def __hash__(self):
        return self.number

    def __lt__(self, other):
        """Necesary for the heapq in astar for determeting what path to take if two tiles
        have equal cost. Current implementation favours the tile with the lowest number.
        In other words the tile furthest up, and then the one furthest to the left."""
        return self.number < other.number

    def __eq__(self, other):
        return self is other

    def __str__(self):
        return "Tile: pos=%s, num=%s, walkable=%s" \
               % (self.pos, self.number, self.walkable)

    @classmethod
    def random_open_tile(cls):
        """:return: location of a random walkable tile"""
        return random.choice(tuple(cls.opens)).pos

    def get_centre(self):
        """Return a vector of the pos in the centre of the tile
        >>> Tile.length = 20
        >>> a = Tile(x=0, y=0, is_solid=0)
        >>> a.get_centre()
        Vector(x=10, y=10)"""
        return self.pos + Tile.length // 2

    def closest_open_tile(self):
        return min(Tile.opens,
                   key=lambda x: (self.pos - x.pos).magnitude_squared())

    @classmethod
    def on_screen(cls, direction, tile_num):
        """Return False if the tile is outside of the screen else True
        A direction is needed as a tile on the right border is outside
        if the direction is west
        Params:
        direction: int of direction in the list NSEW. For example South has index 1.
        tile_num: index of tile in Tile.instances"""
        if direction == 2:  # East
            return tile_num % Options.tiles_x != 0
        if direction == 3:
            return tile_num % Options.tiles_x != Options.tiles_x - 1  # West
        return 0 < tile_num < cls.amnt_tiles  # North and South

    @classmethod
    def draw_all(cls, screen):
        """Fill the screen in light tiles, then draws the solid tiles over"""
        screen.fill(Options.fillcolour)
        length, loopcolour, draw_rect = cls.length, Options.loopcolour, pygame.draw.rect
        for tile, i in cls.loop_set:
            draw_rect(screen, loopcolour, (*tile.pos, length * i, length))
Exemple #16
0
 def test_iter(self):
     v = Vector(2.0, 5.0)
     self.assertTrue(len(v) == 2)
     self.assertIsInstance(v, Container)
     self.assertIsInstance(v, Iterable)
     self.assertTrue(5.0 in v)
Exemple #17
0
 def test_creation(self):
     v = Vector(3, 5.3)
     self.assertTrue(isinstance(v.x, int))
     self.assertTrue(isinstance(v.y, float))
     v1 = Vector.from_pair([8.3, 1.3])
     self.assertTrue(hasattr(v1, "y"))