def __init__(self, *args): _range_of_action, x, y = args super(ProximityObject, self).__init__(x, y) self.pos_row, self.pos_col = utils.norm_to_cell(x), utils.norm_to_cell(y) self.geometric_point = Point(x, y) # This will be used to compute intersections with the players' vision polygon self.range_of_action = _range_of_action self.weapon = None # has to be overwritten by children
def __move_player(self, player, dx, dy): """ Moves the given player using the given dx nd dy deltas for x and y axis taking into account collisions with obstacles :param player: Instance of Player class, the player we want to move :param dx: float, the x coordinate difference we want to apply to the current player (may or may not be pplied depending on wether there are collisions) :param dy: float, the y coordinate difference we want to apply to the current player (may or may not be pplied depending on wether there are collisions) :return None """ x_to_be, y_to_be = player.posx + dx, player.posy + dy # Do not go out of the map please : if x_to_be > self.slmap.max_x: x_to_be = self.slmap.max_x if y_to_be > self.slmap.max_y: y_to_be = self.slmap.max_y if x_to_be < 0: x_to_be = 0 if y_to_be < 0: y_to_be = 0 row, col = utils.norm_to_cell(player.posy), utils.norm_to_cell(player.posx) row_to_be, col_to_be = utils.norm_to_cell(y_to_be), utils.norm_to_cell(x_to_be) is_obs_by_dx = self.slmap.is_obstacle_from_cell_coords(row, col_to_be) is_obs_by_dy = self.slmap.is_obstacle_from_cell_coords(row_to_be, col) if is_obs_by_dx is False and is_obs_by_dy is False: # no collision player.posx = x_to_be player.posy = y_to_be elif is_obs_by_dx is False: # no collision only for x displacement player.posx = x_to_be player.posy = row_to_be * const.CELL_SIZE - 1 # maximum possible posy before colliding elif is_obs_by_dy is False: # no collision only for y displacement player.posy = y_to_be player.posx = col_to_be * const.CELL_SIZE - 1 # maximum possible posx before colliding else: # collision along all axis player.posx = col_to_be * const.CELL_SIZE - 1 # maximum possible posx before colliding player.posy = row_to_be * const.CELL_SIZE - 1 # maximum possible posy before colliding player.compute_hitbox() return player # allow chaining
def __for_obstacle_in_range(self, vector, callback, **callback_args): """ Finds the obstacle in the given range (range = a distance range + an angle (factorized in the "vector" argument)) and executes the callback for each found obstacle :param vector: range/direction vector, of the form ((x_orig, y_orig), (x_end, y_end)) in real map coordinates :param callback: callback function, signature must be func([self, ]vector, row, col, **kwargs) :param callback_args: Additional arguments that will be passed to the callback function when executed /!\ Important /!\ Returns: - None either if the callback was never called or if it never returned anything else than None - the callback value, if a callback call returns anything that is not None """ col_orig = utils.norm_to_cell(vector[0][0]) # x origin, discretize to respect map's tiles (as, we will needs the true coordinates of the obstacle, when we'll find one) _logger.info("__shoot_collide_with_obstacle(): x=" + str(col_orig)) row = utils.norm_to_cell(vector[0][1]) # y origin, same process as for x _logger.info("__shoot_collide_with_obstacle(): y=" + str(row)) col_end = int(utils.norm_to_cell(vector[1][0])) row_end = int(utils.norm_to_cell(vector[1][1])) # The following variables will be used to increment in the "right direction" (negative if the end if lower # than the origin, etc.... col_increment_sign = 1 if (col_end-col_orig) > 0 else -1 row_increment_sign = 1 if (row_end-row) > 0 else -1 # A bit of explanation of the conditions here : # row < self.slmap.height --> Self explanatory, do not go over the map (as the line is multiplied by a # coefficient, this check is necessary # (row-row_end) != row_increment_sign --> This means that we want to stop when the "row" variable has gone one # unit further than the row_end variable. row_increment_sign will always have the same sign as # (row-row_end) when row is one unit further than row_end (by further we mean : one iteration further, in the # "direction" in which we are iterating: that could be forward or backward). Stopping when we are "one further" # means that we iterate until we reach the row_end... INCLUDED! (else, would not work when perfectly aligned) # same thing for the condition with "row" replaced by "col" while row < self.slmap.height and (row-row_end) != row_increment_sign: col = col_orig while col < self.slmap.width and (col-col_end) != col_increment_sign: if self.slmap.is_obstacle_from_cell_coords(row, col): callback_result = callback(vector, row, col, **callback_args) if callback_result is not None: return callback_result col += col_increment_sign * 1 row += row_increment_sign * 1 return None
def step(self): # TODO: Maybe re-write the following lines, for a better handling of # game termination. if self.auto_mode and self.__game_finished(): self.end_of_game() return # Update players' positions and visions for p in self.__players: normalized_array = self.__get_normalized_direction_vector_from_angle(p.move_angle) self.__move_player(p, normalized_array[0] * p.speedx, normalized_array[1] * p.speedy) p.obstacles_in_sight = [] p.obstacles_in_sight_n = 0 # ------- Update player's sight ------- # Parametrize things for occlusion (get obstacles that need to be taken into account by occlusion) sight_direction = self.__get_normalized_direction_vector_from_angle(p.sight_angle) * p.sight_range # A bit bruteforce here, let's use a circle instead of the real shaped vision # Just because there won't be many items to go through anyway # and for simplicity's and implementation speed's sakes y_start = max(0, p.posy - p.sight_range) y_end = min(self.slmap.max_y, p.posy + p.sight_range) x_start = max(0, p.posx - p.sight_range) x_end = min(self.slmap.max_x, p.posx + p.sight_range) row_start = utils.norm_to_cell(y_start) row_end = utils.norm_to_cell(y_end) col_start = utils.norm_to_cell(x_start) col_end = utils.norm_to_cell(x_end) vect = ((x_start, y_start), (x_end, y_end)) self.__for_obstacle_in_range(vect, self.__occlusion_get_obstacle_in_range_callback, player=p) p.compute_sight_polygon_coords() # Launch occlusion p.sight_vertices, p.occlusion_polygon = occlusion(p.posx, p.posy, p.sight_polygon_coords, p.obstacles_in_sight, p.obstacles_in_sight_n) # ---------- Update player's visible objects list ---------- # Note: Here we only go through the visible objects that are in a given range, not through all of them # We will go through the complete list, in order to update them, later in this method del p.visible_objects[:] # Empty the list for row in xrange(row_start, row_end+1): for col in xrange(col_start, col_end+1): try: for item in self.__actionable_items[self.__map_item_key_from_row_col(row, col)]: if p.occlusion_polygon.intersects(item.geometric_point): p.add_new_visible_object(item) except KeyError: pass # There was nothing at this (row,col) position... try: for item in self.__proximity_objects[self.__map_item_key_from_row_col(row, col)]: if p.occlusion_polygon.intersects(item.geometric_point): p.add_new_visible_object(item) except KeyError: pass # There was nothing at this (row,col) position... # ---------- Update player's visible players list ---------- del p.visible_players[:] # Empty the list # Re-populate it for p2 in self.__players: if p2 is p: continue # Do not include ourself in visible objects if p.occlusion_polygon.intersects(p2.hitbox): p.visible_players.append((p2.player_id, p2.posx, p2.posy, p2.move_angle)) # end of by player loop # Now go through all of the visible items to update them for row in xrange(0, self.slmap.height): for col in xrange(0, self.slmap.width): try: for item in self.__actionable_items[self.__map_item_key_from_row_col(row, col)]: item.update() except KeyError: pass # There was nothing at this (row,col) position... try: for item in self.__proximity_objects[self.__map_item_key_from_row_col(row, col)]: item.update() # Try to activate the proximity object on this player for p_ in self.__players: item.activate(p_) except KeyError: pass # There was nothing at this (row,col) position...
def __init__(self, *args): x, y = args super(ActionableItem, self).__init__(x, y) self.pos_row, self.pos_col = utils.norm_to_cell(x), utils.norm_to_cell(y) self.geometric_point = Point(x, y) # This will be used to compute intersections with the players' vision polygon