/** * \brief Returns the ground at the specified point. * * Static tiles and dynamic entities are all taken into account here. * * \param layer Layer of the point. * \param x X coordinate of the point. * \param y Y coordinate of the point. * \return The ground at this place. */ Ground Map::get_ground(Layer layer, int x, int y) const { if (test_collision_with_border(x, y)) { // Outside the map bounds. return Ground::EMPTY; } // See if a dynamic entity changes the ground. // TODO store ground modifiers in a quad tree for performance. const std::list<Entity*>& ground_modifiers = entities->get_ground_modifiers(layer); std::list<Entity*>::const_reverse_iterator it; const std::list<Entity*>::const_reverse_iterator rend = ground_modifiers.rend(); for (it = ground_modifiers.rbegin(); it != rend; ++it) { const Entity& ground_modifier = *(*it); if (ground_modifier.overlaps(x, y) && ground_modifier.get_modified_ground() != Ground::EMPTY && ground_modifier.is_enabled() && !ground_modifier.is_being_removed()) { return ground_modifier.get_modified_ground(); } } // Otherwise, return the ground defined by static tiles (this is very fast). return entities->get_tile_ground(layer, x, y); }
/** * \brief Returns the ground at the specified point. * * Static tiles and dynamic entities are all taken into account here. * * \param layer Layer of the point. * \param x X coordinate of the point. * \param y Y coordinate of the point. * \return The ground at this place. */ Ground Map::get_ground(int layer, int x, int y) const { if (test_collision_with_border(x, y)) { // Outside the map bounds. return Ground::EMPTY; } // See if a dynamic entity changes the ground. const Rectangle box(Point(x, y), Size(1, 1)); std::vector<EntityPtr> entities_nearby; get_entities().get_entities_in_rectangle_sorted(box, entities_nearby); const auto& rend = entities_nearby.rend(); for (auto it = entities_nearby.rbegin(); it != rend; ++it) { const Entity& entity_nearby = *(*it); const Ground ground = entity_nearby.get_modified_ground(); if (ground == Ground::EMPTY) { // The entity has no influence on the ground. continue; } if (entity_nearby.overlaps(x, y) && entity_nearby.get_layer() == layer && entity_nearby.is_enabled() && !entity_nearby.is_being_removed() ) { return entity_nearby.get_modified_ground(); } } // Otherwise, return the ground defined by static tiles (this is very fast). return entities->get_tile_ground(layer, x, y); }
/** * \brief Tests whether a point collides with the ground of the map. * * The ground is the terrain of the point. It is defined by the tiles and * by the presence of entities that may change it * (like dynamic tiles and destructible items). * * This method also returns true if the point is outside the map. * * \param layer Layer of the point. * \param x X of the point in pixels. * \param y Y of the point in pixels. * \param entity_to_check The entity to check (used to decide what grounds are * considered as obstacle). * \param [out] found_diagonal_wall \c true if the ground under this point was * a diagonal wall, unchanged otherwise. * Your algorithm may decide to check more points if there is a diagonal wall. * \return \c true if this point is on an obstacle. */ bool Map::test_collision_with_ground( Layer layer, int x, int y, const MapEntity& entity_to_check, bool& found_diagonal_wall) const { bool on_obstacle = false; int x_in_tile, y_in_tile; // If the point is outside the map, this is an obstacle. if (test_collision_with_border(x, y)) { return true; } // Get the ground property under this point. Ground ground = get_ground(layer, x, y); switch (ground) { case GROUND_EMPTY: case GROUND_TRAVERSABLE: case GROUND_GRASS: case GROUND_ICE: // The square is not an obstacle. on_obstacle = false; break; case GROUND_WALL: // The square is entirely an obstacle. on_obstacle = true; break; case GROUND_WALL_TOP_RIGHT: case GROUND_WALL_TOP_RIGHT_WATER: // The upper right half of the square is an obstacle // so we have to test the position of the point in the square. x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile <= x_in_tile; found_diagonal_wall = true; break; case GROUND_WALL_TOP_LEFT: case GROUND_WALL_TOP_LEFT_WATER: // Same thing. x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile <= 7 - x_in_tile; found_diagonal_wall = true; break; case GROUND_WALL_BOTTOM_LEFT: case GROUND_WALL_BOTTOM_LEFT_WATER: x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile >= x_in_tile; found_diagonal_wall = true; break; case GROUND_WALL_BOTTOM_RIGHT: case GROUND_WALL_BOTTOM_RIGHT_WATER: x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile >= 7 - x_in_tile; found_diagonal_wall = true; break; case GROUND_LOW_WALL: on_obstacle = entity_to_check.is_low_wall_obstacle(); break; case GROUND_SHALLOW_WATER: on_obstacle = entity_to_check.is_shallow_water_obstacle(); break; case GROUND_DEEP_WATER: on_obstacle = entity_to_check.is_deep_water_obstacle(); break; case GROUND_HOLE: on_obstacle = entity_to_check.is_hole_obstacle(); break; case GROUND_LAVA: on_obstacle = entity_to_check.is_lava_obstacle(); break; case GROUND_PRICKLE: on_obstacle = entity_to_check.is_prickle_obstacle(); break; case GROUND_LADDER: on_obstacle = entity_to_check.is_ladder_obstacle(); break; } return on_obstacle; }
/** * \brief Tests whether a point collides with the ground of the map. * * The ground is the terrain of the point. It is defined by the tiles and * by the presence of entities that may change it * (like dynamic tiles and destructible items). * * This method also returns true if the point is outside the map. * * \param layer Layer of the point. * \param x X of the point in pixels. * \param y Y of the point in pixels. * \param entity_to_check The entity to check (used to decide what grounds are * considered as obstacle). * \param [out] found_diagonal_wall \c true if the ground under this point was * a diagonal wall, unchanged otherwise. * Your algorithm may decide to check more points if there is a diagonal wall. * \return \c true if this point is on an obstacle. */ bool Map::test_collision_with_ground( int layer, int x, int y, const Entity& entity_to_check, bool& found_diagonal_wall) const { bool on_obstacle = false; int x_in_tile, y_in_tile; // If the point is outside the map, this is an obstacle. if (test_collision_with_border(x, y)) { return true; } // Get the ground property under this point. Ground ground = get_ground(layer, x, y); switch (ground) { case Ground::EMPTY: case Ground::TRAVERSABLE: case Ground::GRASS: case Ground::ICE: // The square is not an obstacle. on_obstacle = false; break; case Ground::WALL: // The square is entirely an obstacle. on_obstacle = true; break; case Ground::WALL_TOP_RIGHT: case Ground::WALL_TOP_RIGHT_WATER: // The upper right half of the square is an obstacle // so we have to test the position of the point in the square. x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile <= x_in_tile; found_diagonal_wall = true; break; case Ground::WALL_TOP_LEFT: case Ground::WALL_TOP_LEFT_WATER: // Same thing. x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile <= 7 - x_in_tile; found_diagonal_wall = true; break; case Ground::WALL_BOTTOM_LEFT: case Ground::WALL_BOTTOM_LEFT_WATER: x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile >= x_in_tile; found_diagonal_wall = true; break; case Ground::WALL_BOTTOM_RIGHT: case Ground::WALL_BOTTOM_RIGHT_WATER: x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile >= 7 - x_in_tile; found_diagonal_wall = true; break; case Ground::LOW_WALL: case Ground::SHALLOW_WATER: case Ground::DEEP_WATER: case Ground::HOLE: case Ground::LAVA: case Ground::PRICKLE: case Ground::LADDER: on_obstacle = entity_to_check.is_ground_obstacle(ground); break; } return on_obstacle; }