示例#1
0
/**
 * \brief Updates the position.
 */
void RelativeMovement::update() {

  if (entity_followed == nullptr) {
    finished = true;
    return;
  }

  if (entity_followed->is_being_removed()) {
    finished = true;
    entity_followed = nullptr;
  }
  else {

    Point next = entity_followed->get_xy() + entity_offset;
    Point dnext = next - get_xy();

    if (!are_obstacles_ignored()) {

      if (!finished && (dnext.x != 0 || dnext.y != 0)) {

        if (!test_collision_with_obstacles(dnext)) {
          set_xy(next);
        }
        else {
          finished = true;
          notify_obstacle_reached();
        }
      }
    }
    else {
      set_xy(next);
    }
  }
}
示例#2
0
/**
 * \brief Tests whether a point collides with the map obstacles.
 * \param layer Layer of point to check.
 * \param point Point to check.
 * \param entity_to_check The entity to check (used to decide what is
 * considered as obstacle)
 * \return \c true if the point is overlapping an obstacle.
 */
bool Map::test_collision_with_obstacles(
    Layer layer,
    const Point& point,
    MapEntity& entity_to_check) const {

  return test_collision_with_obstacles(layer, point.x, point.y, entity_to_check);
}
示例#3
0
void StraightMovement::update_y() {
	uint32_t next_move_time_y = delay_y;
	if(move_y != 0) { //entity wants to move in y direction.
		next_move_time_y = delay_y;
		if(!test_collision_with_obstacles(0, move_y) && !test_collision_with_borders(0, move_y)) {
			translate_y(move_y);  //make the move on y
			if(move_x != 0 && test_collision_with_obstacles(move_x, 0)) {
				// if there is also a y move and this move is stopped by an obstacles.
				next_move_time_y = (int) (1000 / get_speed());
				update_x();
			}
		}
	} else {
		stop();
	}
	next_move_date_y += next_move_time_y;
}
示例#4
0
void StraightMovement::update_x() {
	uint32_t next_move_time_x;
	if(move_x != 0) {	// entity wants to move in x direction.
		next_move_time_x = delay_x;
		if(!test_collision_with_obstacles(move_x, 0) && !test_collision_with_borders(move_x, 0)) {
			translate_x(move_x);	// no collision in x direction 
			if(move_y != 0 && test_collision_with_obstacles(0, move_y)) {
				// if there is also a y move and this move is stopped by an obstacles.
				next_move_time_x = (int) (1000 / get_speed());
				update_y();
			}
		}
	} else {	//entity does not want to move in x direction so we stop the movement.
	    stop();
	}
	next_move_date_x += next_move_time_x;
}
示例#5
0
/**
 * @brief Updates the y position of the entity if it wants to move
 * (non-smooth version).
 */
void StraightMovement::update_non_smooth_y() {

  if (y_move != 0) { // if it's time to try a move

    // make the move only if there is no collision
    if (!test_collision_with_obstacles(x_move, y_move)) {
      translate_y(y_move);
    }
    else {
      stop(); // also stop on x
    }
    next_move_date_y += y_delay;
  }
}
示例#6
0
/**
 * @brief Updates the x position of the entity if it wants to move
 * (non-smooth version).
 */
void StraightMovement::update_non_smooth_x() {

  if (x_move != 0) {

    // make the move only if there is no collision
    if (!test_collision_with_obstacles(x_move, y_move)) {
      translate_x(x_move);
    }
    else {
      stop(); // also stop on y
    }
    next_move_date_x += x_delay;
  }
}
示例#7
0
/**
 * @brief Computes the position of the object controlled by this movement.
 *
 * This function should be called whenever the angle, the radius or the center changes.
 */
void CircleMovement::recompute_position() {

  Rectangle center = this->center_point;
  if (center_entity != NULL) {
    center.add_xy(center_entity->get_xy());
  }

  const Rectangle &xy = Geometry::get_xy(center, Geometry::degrees_to_radians(current_angle), current_radius);
  if (get_entity() == NULL
      || !test_collision_with_obstacles(xy.get_x() - get_entity()->get_x(), xy.get_y() - get_entity()->get_y())) {
    set_xy(xy);
    notify_position_changed();
  }
  else {
    notify_obstacle_reached();
  }
}
示例#8
0
/**
 * \brief Computes the position of the object controlled by this movement.
 *
 * This function should be called whenever the angle, the radius or the center changes.
 */
void CircleMovement::recompute_position() {

  Point center = this->center_point;
  if (center_entity != nullptr) {
    center += center_entity->get_xy();
  }

  Point xy = Geometry::get_xy(center, Geometry::degrees_to_radians(current_angle), current_radius);
  if (get_entity() == nullptr
      || !test_collision_with_obstacles(xy - get_entity()->get_xy())) {
    set_xy(xy);
    notify_position_changed();
  }
  else {
    notify_obstacle_reached();
  }
}
示例#9
0
/**
 * @brief Updates the movement.
 */
void TargetMovement::update() {

  if (System::now() >= next_recomputation_date) {
    recompute_movement();
    next_recomputation_date += recomputation_delay;
  }

  // see if the target is reached
  int dx = target_x - get_x();
  int dy = target_y - get_y();
  if (dx * sign_x <= 0 && dy * sign_y <= 0) {
    if (!test_collision_with_obstacles(dx, dy)) {
      set_xy(target_x, target_y); // because the target movement may have not been very precise
      stop();
      finished = true;
    }
  }

  StraightMovement::update();
}
示例#10
0
/**
 * \brief Updates the position.
 */
void FollowMovement::update() {

  if (entity_followed == NULL) {
    finished = true;
    return;
  }

  if (entity_followed->is_being_removed()) {
    finished = true;
    RefCountable::unref(entity_followed);
    entity_followed = NULL;
  }
  else {

    int next_x = entity_followed->get_x() + x;
    int next_y = entity_followed->get_y() + y;

    int dx = next_x - get_x();
    int dy = next_y - get_y();

    if (!are_obstacles_ignored()) {

      if (!finished && (dx != 0 || dy != 0)) {

        if (!test_collision_with_obstacles(dx, dy)) {
          set_x(next_x);
          set_y(next_y);
        }
        else {
          finished = true;
          notify_obstacle_reached();
        }
      }
    }
    else {
      set_x(next_x);
      set_y(next_y);
    }
  }
}
示例#11
0
/**
 * @brief Updates the y position of the entity if it wants to move
 * (smooth version).
 */
void StraightMovement::update_smooth_y() {

  if (y_move != 0) {  // The entity wants to move on y.

    // By default, next_move_date_y will be incremented by y_delay,
    // unless we modify the movement in such a way that the
    // y speed needs to be fixed.
    uint32_t next_move_date_y_increment = y_delay;

    if (!test_collision_with_obstacles(0, y_move)) {

      translate_y(y_move);  // Make the move.

      if (x_move != 0 && test_collision_with_obstacles(x_move, 0)) {
        // If there is also an x move, and if this x move is illegal,
        // we still allow the y move and we give it all the speed.
        next_move_date_y_increment = (int) (1000.0 / get_speed());
      }
    }
    else {
      if (x_move == 0) {
        // The move on y is not possible and there is no x move:
        // let's try to add a move on x to make a diagonal move,
        // but only if the wall is really diagonal: otherwise, the hero
        // could bypass sensors.

        if (!test_collision_with_obstacles(1, y_move)    // Can move diagonally and:
            && (test_collision_with_obstacles(-1, 0) ||  // the wall is really diagonal
                test_collision_with_obstacles(1, 0))     // or we don't have a choice anyway.
        ) {
          translate_xy(1, y_move);
          next_move_date_y_increment = (int) (y_delay * Geometry::SQRT_2);  // Fix the speed.
        }
        else if (!test_collision_with_obstacles(-1, y_move)
            && (test_collision_with_obstacles(1, 0) ||
                test_collision_with_obstacles(-1, 0))
        ) {
          translate_xy(-1, y_move);
          next_move_date_y_increment = (int) (y_delay * Geometry::SQRT_2);
        }
        else {
          // The diagonal moves didn't work either.
          // So we look for a place (up to 8 pixels on the left and on the right)
          // where the required move would be allowed.
          // If we find a such place, then we move towards this place.

          bool moved = false;
          for (int i = 1; i <= 8 && !moved; i++) {

            if (!test_collision_with_obstacles(i, y_move) && !test_collision_with_obstacles(1, 0)) {
              translate_x(1);
              moved = true;
            }
            else if (!test_collision_with_obstacles(-i, y_move) && !test_collision_with_obstacles(-1, 0)) {
              translate_x(-1);
              moved = true;
            }
          }
        }
      }
      else {
        // The move on y is not possible, but there is also a horizontal move.
        if (!test_collision_with_obstacles(x_move, y_move)) {
          // This case is only necessary in narrow diagonal passages.
          translate_xy(x_move, y_move);
          next_move_date_x += x_delay;  // Delay the next update_smooth_x() since we just replaced it.
        }
        else if (!test_collision_with_obstacles(x_move, 0)) {
          // Do the horizontal move right now, don't wait uselessly.
          update_x();
        }
      }
    }
    next_move_date_y += next_move_date_y_increment;
  }
}
示例#12
0
/**
 * \brief Returns whether the entity would collide with the map
 * if it was moved a few pixels from its position.
 *
 * If the movement is not attached to an entity of a map,
 * or if obstacles are ignored, false is always returned.
 *
 * \param dxy distance between the current position and the position to check
 * \return true if the entity would overlap the map obstacles in this position
 */
bool Movement::test_collision_with_obstacles(const Point& dxy) const {
  return test_collision_with_obstacles(dxy.x, dxy.y);
}
示例#13
0
文件: Movement.cpp 项目: ziz/solarus
/**
 * @brief Returns whether the entity would collide with the map
 * if it was moved a few pixels from its position.
 *
 * If the movement is not attached to an entity of a map,
 * or if obstacles are ignored, false is always returned.
 *
 * @param dxy distance between the current position and the position to check
 * @return true if the entity would overlap the map obstacles in this position
 */
bool Movement::test_collision_with_obstacles(const Rectangle& dxy) {
  return test_collision_with_obstacles(dxy.get_x(), dxy.get_y());
}
示例#14
0
/**
 * \brief Updates the x position of the entity if it wants to move
 * (smooth version).
 */
void StraightMovement::update_smooth_x() {

  if (x_move != 0) {  // The entity wants to move on x.

    // By default, next_move_date_x will be incremented by x_delay,
    // unless we modify below the movement in such a way that the
    // x speed needs to be fixed.
    uint32_t next_move_date_x_increment = x_delay;

    if (!test_collision_with_obstacles(x_move, 0)) {

      translate_x(x_move);  // Make the move.

      if (y_move != 0 && test_collision_with_obstacles(0, y_move)) {
        // If there is also a y move, and if this y move is illegal,
        // we still allow the x move and we give it all the speed.
        next_move_date_x_increment = (int) (1000.0 / get_speed());
      }
    }
    else {
      if (y_move == 0) {
        // The move on x is not possible and there is no y move:
        // let's try to add a move on y to make a diagonal move,
        // but only if the wall is really diagonal: otherwise, the hero
        // could bypass sensors.

        if (!test_collision_with_obstacles(x_move, 1)    // Can move diagonally and:
            && (test_collision_with_obstacles(0, -1) ||  // the wall is really diagonal
                test_collision_with_obstacles(0, 1))     // or we don't have a choice anyway.
        ) {
          translate_xy(x_move, 1);
          next_move_date_x_increment = (int) (x_delay * Geometry::SQRT_2);  // Fix the speed.
        }
        else if (!test_collision_with_obstacles(x_move, -1)
            && (test_collision_with_obstacles(0, 1) ||
                test_collision_with_obstacles(0, -1))
        ) {
          translate_xy(x_move, -1);
          next_move_date_x_increment = (int) (x_delay * Geometry::SQRT_2);
        }
        else {

          // The diagonal moves didn't work either.
          // So we look for a place (up to 8 pixels up and down)
          // where the required move would be allowed.
          // If we find a such place, then we move towards this place.

          bool moved = false;
          for (int i = 1; i <= 8 && !moved; i++) {

            if (!test_collision_with_obstacles(x_move, i) && !test_collision_with_obstacles(0, 1)) {
              translate_y(1);
              moved = true;
            }
            else if (!test_collision_with_obstacles(x_move, -i) && !test_collision_with_obstacles(0, -1)) {
              translate_y(-1);
              moved = true;
            }
          }
        }
      }
      else {
        // The move on x is not possible, but there is also a vertical move.
        if (!test_collision_with_obstacles(0, y_move)) {
          // Do the vertical move right now, don't wait uselessly.
          update_y();
        }
        else {
          // The x move is not possible and neither is the y move.
          // Last chance: do both x and y moves in one step.
          // This case is only necessary in narrow diagonal passages.
          // We do it as a last resort, because we want separate x and y
          // steps whenever possible: otherwise, the hero could bypass sensors.
          if (!test_collision_with_obstacles(x_move, y_move)) {
            translate_xy(x_move, y_move);
            next_move_date_y += y_delay;  // Delay the next update_smooth_y() since we just replaced it.
          }
        }
      }
    }
    next_move_date_x += next_move_date_x_increment;
  }
}
示例#15
0
/**
 * @brief Updates the y position of the entity if it wants to move
 * (smooth version).
 */
void StraightMovement::update_smooth_y() {

  if (y_move != 0) { // the entity wants to move on y

    // by default, next_move_date_y will be incremented by y_delay,
    // unless we modify the movement in such a way that the
    // y speed needs to be fixed
    uint32_t next_move_date_y_increment = y_delay;

    if (!test_collision_with_obstacles(0, y_move)) {

      translate_y(y_move); // make the move

      if (x_move != 0 && test_collision_with_obstacles(x_move, 0)) {
        // if there is also an x move, and if this x move is illegal,
        // we still allow the y move and we give it all the speed
        next_move_date_y_increment = (int) (1000.0 / get_speed());
      }
    }
    else {
      if (x_move == 0) {
        // The move on y is not possible: let's try
        // to add a move on x to make a diagonal move.

        if (!test_collision_with_obstacles(1, y_move)
            && test_collision_with_obstacles(-1, 0)) {
          translate_xy(1, y_move);
          next_move_date_y_increment = (int) (y_delay * Geometry::SQRT_2); // fix the speed
        }
        else if (!test_collision_with_obstacles(-1, y_move)
            && test_collision_with_obstacles(1, 0)) {
          translate_xy(-1, y_move);
          next_move_date_y_increment = (int) (y_delay * Geometry::SQRT_2);
        }
        else {
          /* The diagonal moves didn't work either.
           * So we look for a place (up to 8 pixels on the left and on the right)
           * where the required move would be allowed.
           * If we find a such place, then we move towards this place.
           */

          bool moved = false;
          for (int i = 1; i <= 8 && !moved; i++) {

            if (!test_collision_with_obstacles(i, y_move) && !test_collision_with_obstacles(1, 0)) {
              translate_x(1);
              moved = true;
            }
            else if (!test_collision_with_obstacles(-i, y_move) && !test_collision_with_obstacles(-1, 0)) {
              translate_x(-1);
              moved = true;
            }
          }
        }
      }
      else {
        // no attractive place was found, but there is a horizontal move
        if (!test_collision_with_obstacles(x_move, 0)) {
          // do the horizontal move right now, don't wait uselessly
          update_x();
        }
      }
    }
    next_move_date_y += next_move_date_y_increment;
  }
}