/** * \brief Returns whether an entity is correctly placed to start jumping * with this jumper. * \param entity A map entity. * \return \c true if the entity is correctly placed to start the jump. */ bool Jumper::is_in_jump_position(const MapEntity& entity) const { const int direction8 = get_direction(); if (is_jump_diagonal()) { // The sensor's shape is a diagonal bar. return is_point_in_diagonal(entity.get_facing_point((direction8 - 1) / 2)) || is_point_in_diagonal(entity.get_facing_point((direction8 + 1) % 8 / 2)); } // The sensor has one of the four main directions. // Its shape is exactly its rectangle. const int expected_direction4 = direction8 / 2; const Rectangle& facing_point = entity.get_facing_point(expected_direction4); const bool horizontal_jump = is_jump_horizontal(); return overlaps(facing_point.get_x() + (horizontal_jump ? 0 : -8), facing_point.get_y() + (horizontal_jump ? -8 : 0)) && overlaps(facing_point.get_x() + (horizontal_jump ? 0 : 7), facing_point.get_y() + (horizontal_jump ? 7 : 0)); }
/** * \brief Returns whether the hero is correctly placed to * start jumping with this jumper. * \param hero The hero. * \param candidate_position The candidate bounding box. * \param extended_region Whether you want to consider the extended jumper * beyond its bounding box, or to keep it restricted to its bounding box. * \return \c true if the hero is correctly placed to start a jump. */ bool Jumper::is_in_jump_position( const Hero& hero, const Rectangle& candidate_position, bool extended_region) const { if (overlaps_jumping_region(candidate_position, extended_region)) { // Overlapping the active region: cannot start a jump from there. return false; } const int direction8 = get_direction(); const int expected_hero_direction4 = direction8 / 2; if (is_jump_diagonal()) { // Diagonal case: The sensor's shape is a diagonal bar. // The player should move toward one of both directions. if (!hero.is_moving_towards(expected_hero_direction4) && !hero.is_moving_towards((expected_hero_direction4 + 1) % 4)) { return false; } // Test if the appropriate corner of the hero crosses the diagonal. Point corner = { candidate_position.get_x() - 1, candidate_position.get_y() - 1 }; if (direction8 == 1 || direction8 == 7) { // Right-up or right-down. corner.x += candidate_position.get_width() + 1; } if (direction8 == 5 || direction8 == 7) { // Left-down or right-down. corner.y += candidate_position.get_height() + 1; } return extended_region ? is_point_in_extended_diagonal(corner) : is_point_in_diagonal(corner); } // Non-diagonal case: the sensor has one of the four main directions. // Its shape is exactly its rectangle. // The player should move toward the jumper's direction. if (!hero.is_moving_towards(expected_hero_direction4)) { return false; } Point facing_point; switch (expected_hero_direction4) { // right case 0: facing_point = { candidate_position.get_x() + 16, candidate_position.get_y() + 8 }; break; // up case 1: facing_point = { candidate_position.get_x() + 8, candidate_position.get_y() - 1 }; break; // left case 2: facing_point = { candidate_position.get_x() - 1, candidate_position.get_y() + 8 }; break; // down case 3: facing_point = { candidate_position.get_x() + 8, candidate_position.get_y() + 16 }; break; default: Debug::die("Invalid direction"); } if (is_jump_horizontal()) { if (extended_region) { // Are we inside the extended strip? return facing_point.x >= get_top_left_x() && facing_point.x < get_top_left_x() + get_width(); } else { // Are we inside the strip and the bounding box? return overlaps(facing_point.x, facing_point.y - 8) && overlaps(facing_point.x, facing_point.y + 7); } } else { // Same thing for a vertical jump. if (extended_region) { // Are we inside the extended strip? return facing_point.y >= get_top_left_y() && facing_point.y < get_top_left_y() + get_height(); } else { return overlaps(facing_point.x - 8, facing_point.y) && overlaps(facing_point.x + 7, facing_point.y); } } }