Beispiel #1
0
class ComputerTank(Tank):
    image_file = 'ai-tank.png'
    
    def __init__(self, id, pos, app):
        Tank.__init__(self, id, pos, app)
        self.path = None
        self.dest = (10,10)
        self.idest = None
        self.rot_dest = None
        self.rotation_signum = 0
        self.driving_signum = 0
        self.previous_state = None
        self.pathfinder = Pathfinder(self.is_valid_cell)
        dx, dy = self.dest
        dcell = self.app.current_map.get_at_pixel(dx, dy)
        x,y = self.position
        cell = self.app.current_map.get_at_pixel(x, y)
        self.pathfinder.setupPath(cell.i, cell.j, dcell.i, dcell.j)
    
    def update(self, dt):
        '''If there is a path follow it, otherwise calculate one'''
        if self.path is not None:
            self.do_move(dt)
        elif self.pathfinder is not None:
            self.find_path()
    
    def do_move(self, dt):
        '''Does all the moving logic of the AI tank'''
        if self.idest is None:
            self.next_dest()
        if abs(self.idest[0] - self.position[0]) < 10 and abs(self.idest[1] - self.position[1]) < 10:
            self.next_dest()
        else:
            # calculate new rot_dest
            self.calc_rotate()
            if self.rot_dest == self.rotation:
                # do the moving
                self.speed = 50
                self.move(dt)
            else:
                # rotate some more
                self.do_rotate()
            self.send_state(dt)
    
    def calc_rotate(self):
        '''Calculate the new rotation to the destination'''
        x, y = self.position
        dest_x, dest_y = self.idest
        # calculate the angle
        dx = abs(x - dest_x)
        dy = abs(y - dest_y)
        h = math.sqrt(dx**2 + dy**2)
        delta_rot = math.degrees(math.asin(dx / h))

        # we now have the delta, but we need to compensate for the quadrant it is in
        # eg. right top(0), right bottom(90), left bottom(180) and left top(270)

        # find the quadrant
        right = top = True
        if x > dest_x:
            right = False
        if y > dest_y:
            top = False
        
        # correct the angle to rotation
        if right and not top:
            delta_rot += 90
        if not right and not top:
            delta_rot += 180
        if top and not right:
            delta_rot += 270
        
        # save the calculated new rotation in the class
        self.rot_dest = delta_rot

    def do_rotate(self):
        '''Rotates the Tank (max 5 degrees per update)'''
        rot = min(abs(self.rotation - self.rot_dest), 5)
        if self.rotation > self.rot_dest:
            self.rotation -= rot # rotate left
        else:
            self.rotation += rot # rotate right
    
    def next_dest(self):
        '''Pick the next destination from the path queue (if present)'''
        if len(self.path) > 0:
            dest_xy = self.path.pop(0)
            self.idest = dest_xy
            self.rot_dest = None
        else:
            self.path = None
    
    def find_path(self):
        '''Do pathfinding stuff'''
        result = Pathfinder.NOT_DONE
        while result is Pathfinder.NOT_DONE:
            result = self.pathfinder.iteratePath()
        if result is Pathfinder.FOUND_GOAL:
            self.path = self.pathfinder.finishPath()
            self.path = map(self.ij_to_xy, self.path)
            self.pathfinder = None
        if result is Pathfinder.IMPOSSIBLE:
            self.pathfinder = None
    
    def is_valid_cell(self, i,j):
        '''Checks if the tile is blocked (used by pathfinding code)'''
        cell = self.app.current_map.get_cell(i,j)
        if cell is None or 'blocked' in cell.tile.properties:
            return False
        return True

    def ij_to_xy(self, ij):
        return self.app.current_map.get_cell(*ij).center

    def xy_to_ij(self, xy):
        cell = self.app.current_map.get_at_pixel(*xy)
        return (cell.i, cell.j)

    def is_valid_move(self, (x,y)):
        return True