diff --git a/src/badguy/crusher.cpp b/src/badguy/crusher.cpp index 257d4d98755..d4ba6d57aa5 100644 --- a/src/badguy/crusher.cpp +++ b/src/badguy/crusher.cpp @@ -28,6 +28,7 @@ #include "object/camera.hpp" #include "object/particles.hpp" #include "object/player.hpp" +#include "object/rock.hpp" #include "sprite/sprite.hpp" #include "sprite/sprite_manager.hpp" #include "supertux/flip_level_transformer.hpp" @@ -136,10 +137,24 @@ Crusher::collision(GameObject& other, const CollisionHit& hit) } auto* badguy = dynamic_cast(&other); - if (badguy && m_state == CRUSHING) { + if (badguy && m_state == CRUSHING && ((!m_sideways && hit.bottom) || + (m_sideways && ((hit.left && m_physic.get_velocity_x() < 0.f) || + (hit.right && m_physic.get_velocity_x() > 0.f))))) + { badguy->kill_fall(); } + auto* rock = dynamic_cast(&other); + if (rock && !rock->is_grabbed() && m_state == CRUSHING && ((!m_sideways && hit.bottom) || + (m_sideways && ((hit.left && m_physic.get_velocity_x() < 0.f) || + (hit.right && m_physic.get_velocity_x() > 0.f))))) + { + SoundManager::current()->play("sounds/brick.wav", get_pos()); + m_physic.reset(); + set_state(RECOVERING); + return ABORT_MOVE; + } + const auto* heavy_coin = dynamic_cast(&other); if (heavy_coin) { return ABORT_MOVE; @@ -328,7 +343,7 @@ Crusher::update(float dt_sec) switch (m_state) { case IDLE: - m_start_position = get_pos(); + //m_start_position = get_pos(); if (found_victim()) { set_state(CRUSHING); @@ -360,9 +375,11 @@ Crusher::update(float dt_sec) case RECOVERING: if (returned_down || returned_up || returned_left || returned_right) { - set_pos(Vector(m_sideways ? m_start_position.x : get_pos().x, - m_sideways ? get_pos().y : m_start_position.y)); - m_physic.set_velocity(0.f, 0.f); + m_physic.reset(); + // we have to offset the crusher when we bring it back to its original position because otherwise it will gain an ugly offset. #JustPhysicErrorThings + set_pos(Vector(m_sideways ? m_start_position.x + (2.6f * (m_side_dir == Direction::LEFT ? -1.f : 1.f)) : get_pos().x, + m_sideways ? get_pos().y : m_start_position.y + (2.6f * (m_flip ? -1.f : 1.f)))); + if (m_ic_size == LARGE) m_cooldown_timer = PAUSE_TIME_LARGE; else diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index ca16402b855..b6ab713da24 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -33,6 +33,7 @@ namespace { const float MAX_SPEED = 16.0f; +static const float FORGIVENESS = 256.f; // 16.f * 16.f - half a tile by half a tile. } // namespace @@ -419,6 +420,13 @@ CollisionSystem::collision_static(collision::Constraints* constraints, // Collision with other (static) objects. for (auto* static_object : m_objects) { + const float static_size = static_object->get_bbox().get_width() * static_object->get_bbox().get_height(); + const float object_size = object.get_bbox().get_width() * object.get_bbox().get_height(); + // let's skip this if two colgroup_moving_static's connect and our object is somewhat larger than the static object. + if ((object.get_group() == COLGROUP_MOVING_STATIC && static_object->get_group() == COLGROUP_MOVING_STATIC) && + (object_size > static_size + FORGIVENESS)) { + return; + } if (( static_object->get_group() == COLGROUP_STATIC || static_object->get_group() == COLGROUP_MOVING_STATIC @@ -639,9 +647,9 @@ CollisionSystem::update() { auto object = *i; - if ((object->get_group() != COLGROUP_MOVING - && object->get_group() != COLGROUP_MOVING_STATIC) - || !object->is_valid()) + if (!object->is_valid() || + (object->get_group() != COLGROUP_MOVING && + object->get_group() != COLGROUP_MOVING_STATIC)) continue; for (auto i2 = i+1; i2 != m_objects.end(); ++i2) { diff --git a/src/object/rock.cpp b/src/object/rock.cpp index 3bcfe7bfdb6..178e1024196 100644 --- a/src/object/rock.cpp +++ b/src/object/rock.cpp @@ -151,11 +151,7 @@ Rock::collision(GameObject& other, const CollisionHit& hit) auto crusher = dynamic_cast (&other); if (crusher) { - auto state = crusher->get_state(); - if(state == Crusher::CrusherState::RECOVERING || - state == Crusher::CrusherState::IDLE) { - return ABORT_MOVE; - } + return FORCE_MOVE; } // Don't fall further if we are on a rock which is on the ground.