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