Ejemplo n.º 1
0
    def __init__(self, arena):
        """
        Some arguments are needed to decide what arena should be initialized
        and how should the enemy tanks behave.
        """
        self.arena = arena
        self.enemies = []

        # to move the player's tank or turn it left/right, just change the state
        # so that it will behave accordingly at next update
        self.player = Tank(0, 0, Arena.DIR_SOUTH, self)

        self._missiles = []

        # a queue that store game events that provide information to the game
        # thread to produce game effects accordingly
        self.game_events = deque()
Ejemplo n.º 2
0
class GameModel(object):
    """
    Controls the game logic and records the game state.
    It initializes an arena with tanks and starts the game.
    The game is updated whenever the update method is called.
    """

    def __init__(self, arena):
        """
        Some arguments are needed to decide what arena should be initialized
        and how should the enemy tanks behave.
        """
        self.arena = arena
        self.enemies = []

        # to move the player's tank or turn it left/right, just change the state
        # so that it will behave accordingly at next update
        self.player = Tank(0, 0, Arena.DIR_SOUTH, self)

        self._missiles = []

        # a queue that store game events that provide information to the game
        # thread to produce game effects accordingly
        self.game_events = deque()

    def update(self):
        """
        Update the state of the enemy tanks according to their behaviors.
        Update the locations of the missiles if their new locations are valid.
        Update the list of tanks if any is hit by a missile.
        Update the list of missiles if any hits obstacles (tank/brick/iron).
        Update the game state if necessary.
        """
        self.player.update()
        for aTank in self.enemies:
            aTank.update()

        # iterate a copy so we can modify the original during iteration
        for aMissile in self._missiles[:]:
            aMissile.forward()
            tile_x = int(math.floor(aMissile.x))
            tile_y = int(math.floor(aMissile.y))

            # remove missile if it is out of the arena
            if not 0 <= tile_x < self.arena.get_width():
                if not 0 <= tile_y < self.arena.get_height():
                    self._missiles.remove(aMissile)
                    continue

            # check if the missile hit an obstacle
            terrain = self.arena.tiles.get_terrain(tile_x, tile_y)
            if terrain.obstacle == Tile.OBS_IRON:
                self._missiles.remove(aMissile)
                event = GameEvent(event_type=GameEvent.TYPE_IRON_HIT, source=terrain)
                self.game_events.put(event)
                continue
            if terrain.obstacle == Tile.OBS_BRICK:
                self._missiles.remove(aMissile)
                # brick disappear after being hit by a missile
                terrain.obstacle = None
                event = GameEvent(event_type=GameEvent.TYPE_BRICK_HIT, source=terrain)
                self.game_events.put(event)
                continue

            if aMissile.from_enemy:
                # game over if the player is hit
                if self.player.x < aMissile.x < self.player.x + 1:
                    if self.player.y < aMissile.y < self.player.y + 1:
                        event = GameEvent(event_type=GameEvent.TYPE_GAME_OVER, source=self.player)
                        self.game_events.put(event)
                        return
                continue

            # check whether the player's missile hit an enemy tank
            for aTank in self.enemies[:]:
                if aTank.x < aMissile.x < aTank.x + 1:
                    if aTank.y < aMissile.y < aTank.y + 1:
                        self.enemies.remove(aTank)
                        self._missile.remove(aMissile)
                        event = GameEvent(GameEvent.TYPE_TANK_HIT, aTank)
                        self.game_events.put(event)
                        break

    def add_missile(self, missile):
        """
        Add a missile to the missile list.
        """
        self._missiles.append(missile)
        return

    def get_tanks(self):
        """
        Return a copy of the tank list.
        """
        return self.enemies[:]

    def get_missiles(self):
        """
        Return a copy of the missile list.
        """
        return self._missiles[:]

    def is_valid_move(self, tank, next_x, next_y):
        """
        tank: the tank that is moving
        next_loc: the next location that the tank is moving into
        Return if the the move is valid (not blocking by terrain or other tanks
        etc.).
        """
        # not moving is always valid
        if (tank.x, tank.y) == (next_x, next_y):
            return True

        # a tank can only move forward or backward
        if tank.x + tank.base_dir[0] != next_x or tank.y + tank.base_dir[1] != next_y:
            if tank.x - tank.base_dir[0] != next_x or tank.y - tank.base_dir[1] != next_y:
                print "can only move forward or backward"
                return False

        # a tank cannot move to a location (going to be) occupied by another tank
        if (next_x, next_y) == (self.player.next_x, self.player.next_y):
            print "cannot move to a location (going to be) occupied by another tank"
            return False
        for aTank in self.enemies:
            # no need to check aTank == tank here
            if (next_x, next_y) == (aTank.next_x, aTank.next_y):
                print "cannot move to a location (going to be) occupied by another tank"
                return False

        move_dir = (next_x - tank.x, next_y - tank.y)
        return self.arena.can_move(from_x=tank.x, from_y=tank.y, move_dir=move_dir)