From a55dfe8a6e8fa90a55bb9a2a6ba363474cb9e927 Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Sat, 2 Mar 2024 14:44:06 +0000 Subject: [PATCH 01/19] wip --- src/badguy/badguy.cpp | 40 ++++++++++++++++++++++-------- src/collision/collision_system.cpp | 2 +- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 92848605eb7..c3e86a3adfa 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -761,23 +761,43 @@ BadGuy::try_activate() bool BadGuy::might_fall(int height) const { + using RaycastResult = CollisionSystem::RaycastResult; + // Make sure we check for at least a 1-pixel fall. assert(height > 0); - float x1; - float x2; - float y1 = m_col.m_bbox.get_bottom() + 1; - float y2 = m_col.m_bbox.get_bottom() + 1 + static_cast(height); + Vector eye; + Vector end; + eye.y = m_col.m_bbox.get_bottom(); + end.y = eye.y + 600; if (m_dir == Direction::LEFT) { - x1 = m_col.m_bbox.get_left() - 1; - x2 = m_col.m_bbox.get_left(); + eye.x = m_col.m_bbox.get_left() - 1; } else { - x1 = m_col.m_bbox.get_right(); - x2 = m_col.m_bbox.get_right() + 1; + eye.x = m_col.m_bbox.get_right() + 1; + } + end.x = eye.x; + //const Rectf rect = Rectf(x1, y1, x2, y2); + + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, true, nullptr); + + auto tile_p = std::get_if(&result.hit); + if (tile_p && !result.box.empty()) + { + std::cout << "tile " << eye.y <<" "<< result.box.p1().y <<" "<< (result.box.p1().y - eye.y) <<" "<< (static_cast(height)) << std::endl; + if ((*tile_p)->is_slope()) + // Only fall if the slope is too far off the ledge + return result.box.p1().y - eye.y > 600.f; + else + { + return result.box.p1().y - eye.y > static_cast(height); + } + } + else + { + return true; } - const Rectf rect = Rectf(x1, y1, x2, y2); - return Sector::get().is_free_of_statics(rect) && Sector::get().is_free_of_specifically_movingstatics(rect); + //return Sector::get().is_free_of_statics(rect) && Sector::get().is_free_of_specifically_movingstatics(rect); } Player* diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index 251a3c69eed..f54668dd2de 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -781,7 +781,7 @@ CollisionSystem::get_first_line_intersection(const Vector& line_start, { result.is_valid = true; result.hit = tile; - result.box = {glm::floor((test_vector - solids->get_offset()) / 32.0f), Sizef(32.f, 32.f)}; + result.box = solids->get_tile_bbox(test_vector.x / 32.f, test_vector.y / 32.f); return result; } } From 0c646b6d0ce68d6b689e8259bf833659210ed56e Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Wed, 20 Mar 2024 23:10:52 +0000 Subject: [PATCH 02/19] wip again --- src/badguy/badguy.cpp | 27 ++++++++++++++++++--------- src/badguy/walking_badguy.cpp | 2 +- src/collision/collision_system.cpp | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index c3e86a3adfa..eb50e083c22 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -766,30 +766,39 @@ BadGuy::might_fall(int height) const // Make sure we check for at least a 1-pixel fall. assert(height > 0); - Vector eye; - Vector end; + Vector eye, end; eye.y = m_col.m_bbox.get_bottom(); - end.y = eye.y + 600; - if (m_dir == Direction::LEFT) { + end.y = eye.y + 600.f; + if (m_dir == Direction::LEFT) eye.x = m_col.m_bbox.get_left() - 1; - } else { + else eye.x = m_col.m_bbox.get_right() + 1; - } end.x = eye.x; - //const Rectf rect = Rectf(x1, y1, x2, y2); RaycastResult result = Sector::get().get_first_line_intersection(eye, end, true, nullptr); auto tile_p = std::get_if(&result.hit); if (tile_p && !result.box.empty()) { - std::cout << "tile " << eye.y <<" "<< result.box.p1().y <<" "<< (result.box.p1().y - eye.y) <<" "<< (static_cast(height)) << std::endl; + std::cout <<"tile " << eye.y + <<" "<< result.box.p1().y + <<" "<< (result.box.p1().y - eye.y) + <<" "<< (static_cast(height)) + << std::endl; if ((*tile_p)->is_slope()) // Only fall if the slope is too far off the ledge return result.box.p1().y - eye.y > 600.f; else { - return result.box.p1().y - eye.y > static_cast(height); + Vector groundcheck; + if (m_dir == Direction::RIGHT) + groundcheck.x = m_col.m_bbox.get_left() - 1; + else + groundcheck.x = m_col.m_bbox.get_right() + 1; + + return !Sector::get().is_free_of_tiles(Rectf(groundcheck, Sizef(1.f, 1.f)), + false, Tile::SLOPE) || + result.box.p1().y - eye.y > static_cast(height); } } else diff --git a/src/badguy/walking_badguy.cpp b/src/badguy/walking_badguy.cpp index 43f4ae0e8f6..7e6476bb0ac 100644 --- a/src/badguy/walking_badguy.cpp +++ b/src/badguy/walking_badguy.cpp @@ -99,7 +99,7 @@ void WalkingBadguy::set_ledge_behavior(LedgeBehavior behavior) break; case LedgeBehavior::SMART: - max_drop_height = static_cast(get_bbox().get_width()) / 2; + max_drop_height = 16.f; break; case LedgeBehavior::NORMAL: diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index f54668dd2de..91f893bbb35 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -781,7 +781,7 @@ CollisionSystem::get_first_line_intersection(const Vector& line_start, { result.is_valid = true; result.hit = tile; - result.box = solids->get_tile_bbox(test_vector.x / 32.f, test_vector.y / 32.f); + result.box = solids->get_tile_bbox(static_cast(test_vector.x / 32.f), static_cast(test_vector.y / 32.f)); return result; } } From 318beb62c22e97ed5c8516f3de46038849d26ad6 Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Sat, 23 Mar 2024 07:05:46 +0000 Subject: [PATCH 03/19] this is tiring to work on --- src/badguy/badguy.cpp | 69 ++++++++++++------------------ src/collision/collision_system.cpp | 18 ++++---- src/collision/collision_system.hpp | 2 +- src/supertux/sector.cpp | 5 ++- src/supertux/sector.hpp | 3 +- 5 files changed, 41 insertions(+), 56 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index eb50e083c22..3989b2443fd 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -136,6 +136,19 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, void BadGuy::draw(DrawingContext& context) { + float x1, x2; + float y1 = get_bbox().get_bottom() + 1; + float y2 = y1 + 16.f; + if (m_dir == Direction::LEFT) { + x1 = get_bbox().get_left() - 1; + x2 = get_bbox().get_left(); + } else { + x1 = get_bbox().get_right(); + x2 = get_bbox().get_right() + 1; + } + const Rectf rect = Rectf(x1, y1, x2, y2); + context.color().draw_filled_rect(rect, Color::CYAN, 0, 200); + if (!m_sprite.get()) return; if (m_state == STATE_INIT || m_state == STATE_INACTIVE) @@ -761,52 +774,24 @@ BadGuy::try_activate() bool BadGuy::might_fall(int height) const { - using RaycastResult = CollisionSystem::RaycastResult; - - // Make sure we check for at least a 1-pixel fall. assert(height > 0); - Vector eye, end; - eye.y = m_col.m_bbox.get_bottom(); - end.y = eye.y + 600.f; - if (m_dir == Direction::LEFT) - eye.x = m_col.m_bbox.get_left() - 1; - else - eye.x = m_col.m_bbox.get_right() + 1; - end.x = eye.x; - - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, true, nullptr); - - auto tile_p = std::get_if(&result.hit); - if (tile_p && !result.box.empty()) - { - std::cout <<"tile " << eye.y - <<" "<< result.box.p1().y - <<" "<< (result.box.p1().y - eye.y) - <<" "<< (static_cast(height)) - << std::endl; - if ((*tile_p)->is_slope()) - // Only fall if the slope is too far off the ledge - return result.box.p1().y - eye.y > 600.f; - else - { - Vector groundcheck; - if (m_dir == Direction::RIGHT) - groundcheck.x = m_col.m_bbox.get_left() - 1; - else - groundcheck.x = m_col.m_bbox.get_right() + 1; - - return !Sector::get().is_free_of_tiles(Rectf(groundcheck, Sizef(1.f, 1.f)), - false, Tile::SLOPE) || - result.box.p1().y - eye.y > static_cast(height); - } - } - else - { - return true; + float x1, x2; + float y1 = get_bbox().get_bottom() + 1; + float y2 = y1 + static_cast(height); + if (m_dir == Direction::LEFT) { + x1 = get_bbox().get_left() - 1; + x2 = get_bbox().get_left(); + } else { + x1 = get_bbox().get_right(); + x2 = get_bbox().get_right() + 1; } + const Rectf rect = Rectf(x1, y1, x2, y2); + + // Specifying Tile::SLOPE skips the AATriangle checks. + return Sector::get().is_free_of_statics(rect, nullptr, false, Tile::SOLID | Tile::UNISOLID | Tile::SLOPE) && + Sector::get().is_free_of_specifically_movingstatics(rect); - //return Sector::get().is_free_of_statics(rect) && Sector::get().is_free_of_specifically_movingstatics(rect); } Player* diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index 91f893bbb35..dc126c06344 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -675,20 +675,18 @@ CollisionSystem::is_free_of_tiles(const Rectf& rect, const bool ignoreUnisolid, for (int y = test_tiles.top; y < test_tiles.bottom; ++y) { const Tile& tile = solids->get_tile(x, y); - if (!(tile.get_attributes() & tiletype)) - continue; - if (tile.is_unisolid () && ignoreUnisolid) - continue; - if (tile.is_slope ()) { + if (tile.get_attributes() & tiletype) + return false; + if (!ignoreUnisolid & tile.is_unisolid()) + return false; + if (tile.is_slope()) { AATriangle triangle; const Rectf tbbox = solids->get_tile_bbox(x, y); triangle = AATriangle(tbbox, tile.get_data()); Constraints constraints; if (!collision::rectangle_aatriangle(&constraints, rect, triangle)) - continue; + return false; } - // We have a solid tile that overlaps the given rectangle. - return false; } } } @@ -697,11 +695,11 @@ CollisionSystem::is_free_of_tiles(const Rectf& rect, const bool ignoreUnisolid, } bool -CollisionSystem::is_free_of_statics(const Rectf& rect, const CollisionObject* ignore_object, const bool ignoreUnisolid) const +CollisionSystem::is_free_of_statics(const Rectf& rect, const CollisionObject* ignore_object, const bool ignoreUnisolid, uint32_t tiletype) const { using namespace collision; - if (!is_free_of_tiles(rect, ignoreUnisolid)) return false; + if (!is_free_of_tiles(rect, ignoreUnisolid, tiletype)) return false; for (const auto& object : m_objects) { if (object == ignore_object) continue; diff --git a/src/collision/collision_system.hpp b/src/collision/collision_system.hpp index 0dab8149991..41df059de2d 100644 --- a/src/collision/collision_system.hpp +++ b/src/collision/collision_system.hpp @@ -63,7 +63,7 @@ class CollisionSystem final } bool is_free_of_tiles(const Rectf& rect, const bool ignoreUnisolid = false, uint32_t tiletype = Tile::SOLID) const; - bool is_free_of_statics(const Rectf& rect, const CollisionObject* ignore_object, const bool ignoreUnisolid) const; + bool is_free_of_statics(const Rectf& rect, const CollisionObject* ignore_object, const bool ignoreUnisolid, uint32_t tiletype = Tile::SOLID) const; bool is_free_of_movingstatics(const Rectf& rect, const CollisionObject* ignore_object) const; bool is_free_of_specifically_movingstatics(const Rectf& rect, const CollisionObject* ignore_object) const; diff --git a/src/supertux/sector.cpp b/src/supertux/sector.cpp index 91c9f3cef89..5fff034c625 100644 --- a/src/supertux/sector.cpp +++ b/src/supertux/sector.cpp @@ -493,11 +493,12 @@ Sector::is_free_of_tiles(const Rectf& rect, const bool ignoreUnisolid, uint32_t } bool -Sector::is_free_of_statics(const Rectf& rect, const MovingObject* ignore_object, const bool ignoreUnisolid) const +Sector::is_free_of_statics(const Rectf& rect, const MovingObject* ignore_object, const bool ignoreUnisolid, uint32_t tiletype) const { return m_collision_system->is_free_of_statics(rect, ignore_object ? ignore_object->get_collision_object() : nullptr, - ignoreUnisolid); + ignoreUnisolid, + tiletype); } bool diff --git a/src/supertux/sector.hpp b/src/supertux/sector.hpp index 8591283fa90..d81696e5a9f 100644 --- a/src/supertux/sector.hpp +++ b/src/supertux/sector.hpp @@ -102,7 +102,8 @@ class Sector final : public Base::Sector 1.) solid tiles and 2.) MovingObjects in COLGROUP_STATIC. Note that this does not include badguys or players. */ - bool is_free_of_statics(const Rectf& rect, const MovingObject* ignore_object = nullptr, const bool ignoreUnisolid = false) const; + bool is_free_of_statics(const Rectf& rect, const MovingObject* ignore_object = nullptr, + const bool ignoreUnisolid = false, uint32_t tiletype = Tile::SOLID) const; /** Checks if the specified rectangle is free of both 1.) solid tiles and From 441feec805b585c838c169662f92c5657616592d Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Sat, 23 Mar 2024 20:37:48 +0000 Subject: [PATCH 04/19] something somthing is free of tiles --- src/badguy/badguy.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 5f5a4835a6e..e9d3eee55bf 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -138,7 +138,7 @@ BadGuy::draw(DrawingContext& context) { float x1, x2; float y1 = get_bbox().get_bottom() + 1; - float y2 = y1 + 16.f; + float y2 = y1 + get_bbox().get_width() * 2.f; if (m_dir == Direction::LEFT) { x1 = get_bbox().get_left() - 1; x2 = get_bbox().get_left(); @@ -782,16 +782,39 @@ BadGuy::might_fall(int height) const if (m_dir == Direction::LEFT) { x1 = get_bbox().get_left() - 1; x2 = get_bbox().get_left(); - } else { + } + else + { x1 = get_bbox().get_right(); x2 = get_bbox().get_right() + 1; } - const Rectf rect = Rectf(x1, y1, x2, y2); + Rectf rect(x1, y1, x2, y2); - // Specifying Tile::SLOPE skips the AATriangle checks. - return Sector::get().is_free_of_statics(rect, nullptr, false, Tile::SOLID | Tile::UNISOLID | Tile::SLOPE) && - Sector::get().is_free_of_specifically_movingstatics(rect); + // Is walking on slope + Rectf slopecheck(Vector(get_bbox().get_left(), get_bbox().get_bottom()), Sizef(get_bbox().get_width(), 1.f)); + bool slope = !Sector::get().is_free_of_tiles(slopecheck, false, Tile::SLOPE); + if (slope) + { + height = static_cast(get_bbox().get_width() * 1.5f); + rect.set_height(static_cast(height)); + return Sector::get().is_free_of_statics(rect) && + Sector::get().is_free_of_specifically_movingstatics(rect); + } + else + { + /* + * Some slopes are too steep for badguys with big hitboxes to + * recognize they're going down the slope. + * This is because the width is so big that the badguy doesn't + * finish going down the slope which means the max drop height + * becomes insufficient. + * + * HACK: Specifying Tile::SLOPE skips the AATriangle checks. + */ + return Sector::get().is_free_of_statics(rect, nullptr, false, Tile::SOLID | Tile::SLOPE) && + Sector::get().is_free_of_specifically_movingstatics(rect); + } } Player* From 3c270738c27e72fe142a96c6d48eff324f9bee69 Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:02:41 +0100 Subject: [PATCH 05/19] fix --- src/badguy/badguy.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index e9d3eee55bf..89c6f14cbac 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -796,8 +796,7 @@ BadGuy::might_fall(int height) const if (slope) { - height = static_cast(get_bbox().get_width() * 1.5f); - rect.set_height(static_cast(height)); + rect.set_height(get_bbox().get_width() * 1.5f); return Sector::get().is_free_of_statics(rect) && Sector::get().is_free_of_specifically_movingstatics(rect); } From bd7a3712e76134e7399bd554567768ff3bb52d01 Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:49:39 +0100 Subject: [PATCH 06/19] Fix this stupid function once and for all --- src/collision/collision_system.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index dc126c06344..98a36eefaeb 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -677,9 +677,17 @@ CollisionSystem::is_free_of_tiles(const Rectf& rect, const bool ignoreUnisolid, if (tile.get_attributes() & tiletype) return false; - if (!ignoreUnisolid & tile.is_unisolid()) + + if (!ignoreUnisolid && tile.is_unisolid()) return false; - if (tile.is_slope()) { + + // NOTE: As long as tiletype & Tile::SLOPE, + // you can skip the proper AATriangle checks + // and instead use the box checking + if ((tiletype & Tile::SOLID) && + !(tiletype & Tile::SLOPE) && + tile.is_slope()) + { AATriangle triangle; const Rectf tbbox = solids->get_tile_bbox(x, y); triangle = AATriangle(tbbox, tile.get_data()); From 0dacfccb5462863f78fe5cc0878bb863352e766a Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Thu, 4 Apr 2024 20:01:21 +0100 Subject: [PATCH 07/19] HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA --- src/badguy/badguy.cpp | 50 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 6db092b1bfb..6daebe0001d 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -19,6 +19,7 @@ #include "audio/sound_manager.hpp" #include "badguy/dispenser.hpp" #include "editor/editor.hpp" +#include "math/aatriangle.hpp" #include "math/random.hpp" #include "object/bullet.hpp" #include "object/camera.hpp" @@ -138,7 +139,7 @@ BadGuy::draw(DrawingContext& context) { float x1, x2; float y1 = get_bbox().get_bottom() + 1; - float y2 = y1 + get_bbox().get_width() * 2.f; + float y2 = y1 + get_bbox().get_width() * 1.5f; if (m_dir == Direction::LEFT) { x1 = get_bbox().get_left() - 1; x2 = get_bbox().get_left(); @@ -776,6 +777,8 @@ BadGuy::try_activate() bool BadGuy::might_fall(int height) const { + using RaycastResult = CollisionSystem::RaycastResult; + assert(height > 0); float x1, x2; @@ -798,9 +801,47 @@ BadGuy::might_fall(int height) const if (slope) { - rect.set_height(get_bbox().get_width() * 1.5f); - return Sector::get().is_free_of_statics(rect) && - Sector::get().is_free_of_specifically_movingstatics(rect); + float off = std::max(get_bbox().get_width() * 1.5f, static_cast(height)); + + Vector eye(x1, y1); + Vector end(eye.x, eye.y + off); + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + + if (result.is_valid) + { + if (auto tile_p = std::get_if(&result.hit)) + { + const Tile* tile = *tile_p; + + if (tile->get_attributes() & Tile::SLOPE) + { + bool is_steep = (tile->get_attributes() & Tile::SLOPE && + (tile->get_data() & AATriangle::DEFORM_LEFT || + tile->get_data() & AATriangle::DEFORM_RIGHT || + (tile->get_data() & AATriangle::DEFORM_MASK) == 0)); + if (!is_steep && result.box.get_top() - eye.y > static_cast(height)) + { + return true; + } + else + { + return false; + } + } + + if (!is_steep && result.box.get_top() - eye.y > static_cast(height)) + { + return true; + } + return false; + } + else + { + return true; + } + } + + return true; } else { @@ -813,6 +854,7 @@ BadGuy::might_fall(int height) const * * HACK: Specifying Tile::SLOPE skips the AATriangle checks. */ + return Sector::get().is_free_of_statics(rect, nullptr, false, Tile::SOLID | Tile::SLOPE) && Sector::get().is_free_of_specifically_movingstatics(rect); } From d533060b533b7974fa40f5fb36dbd97decd97ab1 Mon Sep 17 00:00:00 2001 From: MatusGuy <85036874+MatusGuy@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:37:33 +0100 Subject: [PATCH 08/19] just another tale from the streets of america --- src/badguy/badguy.cpp | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 6daebe0001d..dc8a2805499 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -809,35 +809,11 @@ BadGuy::might_fall(int height) const if (result.is_valid) { - if (auto tile_p = std::get_if(&result.hit)) + if (std::get_if(&result.hit)) { - const Tile* tile = *tile_p; + //const Tile* tile = *tile_p; - if (tile->get_attributes() & Tile::SLOPE) - { - bool is_steep = (tile->get_attributes() & Tile::SLOPE && - (tile->get_data() & AATriangle::DEFORM_LEFT || - tile->get_data() & AATriangle::DEFORM_RIGHT || - (tile->get_data() & AATriangle::DEFORM_MASK) == 0)); - if (!is_steep && result.box.get_top() - eye.y > static_cast(height)) - { - return true; - } - else - { - return false; - } - } - - if (!is_steep && result.box.get_top() - eye.y > static_cast(height)) - { - return true; - } - return false; - } - else - { - return true; + return eye.y - result.box.get_top() > static_cast(height); } } From 54cfa585444c268b4a461f9ff04344dbd544fd9f Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Mon, 15 Jul 2024 22:04:48 +0100 Subject: [PATCH 09/19] haa --- src/badguy/badguy.cpp | 82 ++++++++++++++--------------------------- src/math/aatriangle.hpp | 10 +++++ 2 files changed, 37 insertions(+), 55 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index dc8a2805499..93b4c182a32 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -137,18 +137,15 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, void BadGuy::draw(DrawingContext& context) { - float x1, x2; - float y1 = get_bbox().get_bottom() + 1; - float y2 = y1 + get_bbox().get_width() * 1.5f; - if (m_dir == Direction::LEFT) { - x1 = get_bbox().get_left() - 1; - x2 = get_bbox().get_left(); - } else { - x1 = get_bbox().get_right(); - x2 = get_bbox().get_right() + 1; - } - const Rectf rect = Rectf(x1, y1, x2, y2); - context.color().draw_filled_rect(rect, Color::CYAN, 0, 200); + Vector eye(0, get_bbox().get_bottom() + 1.f); + eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); + + Vector end(eye.x, eye.y + 16.f); + context.color().draw_line(eye, end, Color::GREEN, LAYER_GUI); + + Vector seye(get_bbox().get_left() + get_bbox().get_width() / 2.f, eye.y); + Vector send(seye.x + 5.f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 64.f); + context.color().draw_line(seye, send, Color::GREEN, LAYER_GUI); if (!m_sprite.get()) return; @@ -781,58 +778,33 @@ BadGuy::might_fall(int height) const assert(height > 0); - float x1, x2; - float y1 = get_bbox().get_bottom() + 1; - float y2 = y1 + static_cast(height); - if (m_dir == Direction::LEFT) { - x1 = get_bbox().get_left() - 1; - x2 = get_bbox().get_left(); - } - else + Vector eye(0, get_bbox().get_bottom() + 1.f); + eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); + + Vector end(eye.x, eye.y + 64.f); + + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + bool slope = false; + + auto tile_p = std::get_if(&result.hit); + if (tile_p && (*tile_p) && (*tile_p)->is_slope()) { - x1 = get_bbox().get_right(); - x2 = get_bbox().get_right() + 1; + AATriangle tri((*tile_p)->get_data()); + if (tri.is_south() && (m_dir == Direction::LEFT ? tri.is_east() : !tri.is_east())) + slope = true; } - Rectf rect(x1, y1, x2, y2); - - // Is walking on slope - Rectf slopecheck(Vector(get_bbox().get_left(), get_bbox().get_bottom()), Sizef(get_bbox().get_width(), 1.f)); - bool slope = !Sector::get().is_free_of_tiles(slopecheck, false, Tile::SLOPE); if (slope) { - float off = std::max(get_bbox().get_width() * 1.5f, static_cast(height)); - - Vector eye(x1, y1); - Vector end(eye.x, eye.y + off); - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); - - if (result.is_valid) - { - if (std::get_if(&result.hit)) - { - //const Tile* tile = *tile_p; - - return eye.y - result.box.get_top() > static_cast(height); - } - } + Vector seye(get_bbox().get_left() + get_bbox().get_width() / 2.f, eye.y); + Vector send(seye.x + 5.f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 64.f); + RaycastResult sresult = Sector::get().get_first_line_intersection(seye, send, false, nullptr); - return true; + return !sresult.is_valid; } else { - /* - * Some slopes are too steep for badguys with big hitboxes to - * recognize they're going down the slope. - * This is because the width is so big that the badguy doesn't - * finish going down the slope which means the max drop height - * becomes insufficient. - * - * HACK: Specifying Tile::SLOPE skips the AATriangle checks. - */ - - return Sector::get().is_free_of_statics(rect, nullptr, false, Tile::SOLID | Tile::SLOPE) && - Sector::get().is_free_of_specifically_movingstatics(rect); + return !result.is_valid && result.box.p1().y - get_pos().y < static_cast(height); } } diff --git a/src/math/aatriangle.hpp b/src/math/aatriangle.hpp index de43eca1acb..d7d48edd6a2 100644 --- a/src/math/aatriangle.hpp +++ b/src/math/aatriangle.hpp @@ -63,6 +63,16 @@ class AATriangle final { } + // Meant for checking directions + AATriangle(int newdir) : + bbox(), + dir(newdir) + { + } + + inline bool is_south() { return dir & SOUTHWEST || dir & SOUTHEAST; } + inline bool is_east() { return dir & NORTHEAST || dir & SOUTHEAST; } + public: Rectf bbox; int dir; From 9d74250e9d105038fa85d2b9d8123938b1477c88 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Wed, 17 Jul 2024 21:49:25 +0100 Subject: [PATCH 10/19] it works?? --- src/badguy/badguy.cpp | 43 +++++++++++++++++++---------------- src/badguy/badguy.hpp | 7 +++--- src/badguy/walking_badguy.cpp | 5 ++++ src/supertux/sector.cpp | 9 +++++++- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 52e5a987b8c..59136f8d156 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -70,11 +70,11 @@ BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite m_glowing(false), m_water_affected(true), m_unfreeze_timer(), + m_floor_normal(0.0f, 0.0f), m_state(STATE_INIT), m_is_active_flag(), m_state_timer(), m_on_ground_flag(false), - m_floor_normal(0.0f, 0.0f), m_colgroup_active(COLGROUP_MOVING) { SoundManager::current()->preload("sounds/squish.wav"); @@ -113,11 +113,11 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, m_glowing(false), m_water_affected(true), m_unfreeze_timer(), + m_floor_normal(0.0f, 0.0f), m_state(STATE_INIT), m_is_active_flag(), m_state_timer(), m_on_ground_flag(false), - m_floor_normal(0.0f, 0.0f), m_colgroup_active(COLGROUP_MOVING) { std::string dir_str; @@ -143,11 +143,11 @@ BadGuy::draw(DrawingContext& context) Vector eye(0, get_bbox().get_bottom() + 1.f); eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); - Vector end(eye.x, eye.y + 16.f); + Vector end(eye.x, eye.y + 256.f); context.color().draw_line(eye, end, Color::GREEN, LAYER_GUI); Vector seye(get_bbox().get_left() + get_bbox().get_width() / 2.f, eye.y); - Vector send(seye.x + 5.f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 64.f); + Vector send(seye.x + 6.5f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 80.f); context.color().draw_line(seye, send, Color::GREEN, LAYER_GUI); if (!m_sprite.get()) return; @@ -853,31 +853,34 @@ BadGuy::might_fall(int height) const Vector eye(0, get_bbox().get_bottom() + 1.f); eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); - Vector end(eye.x, eye.y + 64.f); + // TODO: change to max possible drop height + Vector end(eye.x, eye.y + 256.f); + std::cout << eye << " " << end << std::endl; RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); - bool slope = false; + //bool slope = false; auto tile_p = std::get_if(&result.hit); - if (tile_p && (*tile_p) && (*tile_p)->is_slope()) + if (result.is_valid && result.box.p1().y - eye.y < static_cast(height)) { + return false; + } + else if (tile_p && (*tile_p) && (*tile_p)->is_slope()) { AATriangle tri((*tile_p)->get_data()); + std::cout << "SLOPE" << std::endl; if (tri.is_south() && (m_dir == Direction::LEFT ? tri.is_east() : !tri.is_east())) - slope = true; - } - - if (slope) - { - Vector seye(get_bbox().get_left() + get_bbox().get_width() / 2.f, eye.y); - Vector send(seye.x + 5.f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 64.f); - RaycastResult sresult = Sector::get().get_first_line_intersection(seye, send, false, nullptr); + { + //slope = true; + Vector seye(get_bbox().get_left() + get_bbox().get_width() / 2.f, eye.y); + Vector send(seye.x + 6.5f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 80.f); + RaycastResult sresult = Sector::get().get_first_line_intersection(seye, send, false, nullptr); - return !sresult.is_valid; - } - else - { - return !result.is_valid && result.box.p1().y - get_pos().y < static_cast(height); + std::cout << sresult.is_valid << std::endl; + return !sresult.is_valid; + } } + + return true; } Player* diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index 438a22ee07c..b322a22f9ab 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -293,6 +293,10 @@ class BadGuy : public MovingSprite, Timer m_unfreeze_timer; + /** floor normal stored the last time when update_on_ground_flag was + called and we touched something solid from above */ + Vector m_floor_normal; + private: State m_state; @@ -306,9 +310,6 @@ class BadGuy : public MovingSprite, update_on_ground_flag was called last frame */ bool m_on_ground_flag; - /** floor normal stored the last time when update_on_ground_flag was - called and we touched something solid from above */ - Vector m_floor_normal; /** CollisionGroup the badguy should be in while active */ CollisionGroup m_colgroup_active; diff --git a/src/badguy/walking_badguy.cpp b/src/badguy/walking_badguy.cpp index 5547d5d9f59..ba96bb2e6a9 100644 --- a/src/badguy/walking_badguy.cpp +++ b/src/badguy/walking_badguy.cpp @@ -123,6 +123,11 @@ WalkingBadguy::active_update(float dt_sec, float dest_x_velocity, float modifier { BadGuy::active_update(dt_sec); + // Walk down slopes smoothly. + if (on_ground() && m_floor_normal.y != 0 && (m_floor_normal.x * m_physic.get_velocity_x()) >= 0) { + m_physic.set_velocity_y((std::abs(m_physic.get_velocity_x()) * std::abs(m_floor_normal.x)) + 100.f); + } + float current_x_velocity = m_physic.get_velocity_x (); if (m_frozen) diff --git a/src/supertux/sector.cpp b/src/supertux/sector.cpp index f724d90f2dc..62ee444e883 100644 --- a/src/supertux/sector.cpp +++ b/src/supertux/sector.cpp @@ -45,7 +45,6 @@ #include "object/tilemap.hpp" #include "object/vertical_stripes.hpp" #include "physfs/ifile_stream.hpp" -#include "scripting/sector.hpp" #include "squirrel/squirrel_environment.hpp" #include "supertux/colorscheme.hpp" #include "supertux/constants.hpp" @@ -559,6 +558,14 @@ Sector::is_free_of_statics(const Rectf& rect, const MovingObject* ignore_object, tiletype); } +bool +Sector::is_free_of_statics(float left, float top, float right, float bottom, + bool ignore_unisolid) const +{ + return m_collision_system->is_free_of_statics(Rectf(Vector(left, top), Vector(right, bottom)), + nullptr, ignore_unisolid); +} + bool Sector::is_free_of_movingstatics(const Rectf& rect, const MovingObject* ignore_object) const { From f0eaf04ab51099da8da137e21162a9a57ac8c94a Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Mon, 29 Jul 2024 07:24:06 +0100 Subject: [PATCH 11/19] wip --- src/badguy/badguy.cpp | 92 +++++++++++++++++++++++++++++++---------- src/badguy/badguy.hpp | 6 ++- src/math/aatriangle.hpp | 5 ++- 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 59136f8d156..f200b216c06 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -71,6 +71,7 @@ BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite m_water_affected(true), m_unfreeze_timer(), m_floor_normal(0.0f, 0.0f), + m_detected_slope(0), m_state(STATE_INIT), m_is_active_flag(), m_state_timer(), @@ -114,6 +115,7 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, m_water_affected(true), m_unfreeze_timer(), m_floor_normal(0.0f, 0.0f), + m_detected_slope(0), m_state(STATE_INIT), m_is_active_flag(), m_state_timer(), @@ -844,43 +846,91 @@ BadGuy::try_activate() } bool -BadGuy::might_fall(int height) const +BadGuy::might_fall(int height) { using RaycastResult = CollisionSystem::RaycastResult; assert(height > 0); - Vector eye(0, get_bbox().get_bottom() + 1.f); - eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); + // Origin in Y coord used for raycasting. + float oy = get_bbox().get_bottom() + 1.f; - // TODO: change to max possible drop height - Vector end(eye.x, eye.y + 256.f); - std::cout << eye << " " << end << std::endl; + if (m_detected_slope == 0) + { + Vector eye(0, oy); + eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); - //bool slope = false; + // TODO: change to max possible drop height + Vector end(eye.x, eye.y + 256.f); + //std::cout << eye << " " << end << std::endl; - auto tile_p = std::get_if(&result.hit); - if (result.is_valid && result.box.p1().y - eye.y < static_cast(height)) { - return false; + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + //bool slope = false; + + auto tile_p = std::get_if(&result.hit); + if (result.is_valid && result.box.get_top() - eye.y < static_cast(height)) + { + // The ground is within max drop height. Continue. + return false; + } + else if (tile_p && (*tile_p) && (*tile_p)->is_slope()) + { + // Switch to slope mode. + m_detected_slope = (*tile_p)->get_data(); + } + else + { + // The ground is no longer within reach. Turn around. + return true; + } } - else if (tile_p && (*tile_p) && (*tile_p)->is_slope()) + + if (m_detected_slope != 0) { - AATriangle tri((*tile_p)->get_data()); - std::cout << "SLOPE" << std::endl; + AATriangle tri(m_detected_slope); + std::cout << "SLOPE " << m_detected_slope << std::endl; if (tri.is_south() && (m_dir == Direction::LEFT ? tri.is_east() : !tri.is_east())) { //slope = true; - Vector seye(get_bbox().get_left() + get_bbox().get_width() / 2.f, eye.y); - Vector send(seye.x + 6.5f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 80.f); - RaycastResult sresult = Sector::get().get_first_line_intersection(seye, send, false, nullptr); + Vector eye(get_bbox().get_left() + get_bbox().get_width() / 2.f, oy); + Vector end(eye.x + 6.5f * (m_dir == Direction::LEFT ? 1.f : -1.f), eye.y + 80.f); + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + + std::cout << result.is_valid << std::endl; - std::cout << sresult.is_valid << std::endl; - return !sresult.is_valid; + if (!result.is_valid) + { + // Turn around and climb the slope. + m_detected_slope = 0; + return true; + } + else + { + if (result.box.get_top() - eye.y >= static_cast(height)) + { + // Result is not within reach. + std::cout << "gahh"; + m_detected_slope = 0; + return true; + } + + bool is_tile = std::holds_alternative(result.hit); + if (is_tile && std::get(result.hit)->is_slope()) + { + // Still going down a slope. Continue. + //m_detected_slope = (*tile_p)->get_data(); + return false; + } + + // No longer going down a slope. Switch off slope mode. + m_detected_slope = 0; + std::cout << "aggh" << std::endl; + return false; + } } - } - return true; + return false; + } } Player* diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index b322a22f9ab..a4157381af9 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -230,7 +230,7 @@ class BadGuy : public MovingSprite, /** Returns true if we might soon fall at least @c height pixels. Minimum value for height is 1 pixel */ - bool might_fall(int height = 1) const; + bool might_fall(int height = 1); /** Update on_ground_flag judging by solid collision @c hit. This gets called from the base implementation of collision_solid, so @@ -297,6 +297,10 @@ class BadGuy : public MovingSprite, called and we touched something solid from above */ Vector m_floor_normal; + /** Used for the might_fall function. + Represents the tile data of the detected slope. */ + int m_detected_slope; + private: State m_state; diff --git a/src/math/aatriangle.hpp b/src/math/aatriangle.hpp index d7d48edd6a2..97b145f3fb2 100644 --- a/src/math/aatriangle.hpp +++ b/src/math/aatriangle.hpp @@ -70,8 +70,9 @@ class AATriangle final { } - inline bool is_south() { return dir & SOUTHWEST || dir & SOUTHEAST; } - inline bool is_east() { return dir & NORTHEAST || dir & SOUTHEAST; } + inline int get_dir() const { return dir; } + inline bool is_south() const { return (dir & DIRECTION_MASK) == SOUTHWEST || (dir & DIRECTION_MASK) == SOUTHEAST; } + inline bool is_east() const { return (dir & DIRECTION_MASK) == NORTHEAST || (dir & DIRECTION_MASK) == SOUTHEAST; } public: Rectf bbox; From 9c94ca7aac4d85568260019eabc206f8aeb37746 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Mon, 12 Aug 2024 19:46:49 +0100 Subject: [PATCH 12/19] "just close your eyes and count to 3 (one, two, three)" --- src/badguy/badguy.cpp | 91 ++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index f200b216c06..b4658dc9022 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -148,8 +148,14 @@ BadGuy::draw(DrawingContext& context) Vector end(eye.x, eye.y + 256.f); context.color().draw_line(eye, end, Color::GREEN, LAYER_GUI); - Vector seye(get_bbox().get_left() + get_bbox().get_width() / 2.f, eye.y); - Vector send(seye.x + 6.5f * (m_dir == Direction::LEFT ? 1.f : -1.f), seye.y + 80.f); + float dirmult = (m_dir == Direction::LEFT ? 1.f : -1.f); + float rearx = (m_dir == Direction::LEFT ? get_bbox().get_right() : get_bbox().get_left()); + + float soff = (get_width() / 5.f) * dirmult; + Vector seye(rearx - soff, eye.y); + + float eoff = soff - (2.f * dirmult); + Vector send(seye.x + eoff, seye.y + 80.f); context.color().draw_line(seye, send, Color::GREEN, LAYER_GUI); if (!m_sprite.get()) return; @@ -875,8 +881,16 @@ BadGuy::might_fall(int height) } else if (tile_p && (*tile_p) && (*tile_p)->is_slope()) { - // Switch to slope mode. - m_detected_slope = (*tile_p)->get_data(); + // Check if we are about to go down a slope. + AATriangle tri((*tile_p)->get_data()); + if (tri.is_south() && (m_dir == Direction::LEFT ? tri.is_east() : !tri.is_east())) + { + // Switch to slope mode. + m_detected_slope = tri.dir; + } + + // Otherwise, climb the slope like normal. + return false; } else { @@ -887,50 +901,55 @@ BadGuy::might_fall(int height) if (m_detected_slope != 0) { - AATriangle tri(m_detected_slope); + //AATriangle tri(m_detected_slope); std::cout << "SLOPE " << m_detected_slope << std::endl; - if (tri.is_south() && (m_dir == Direction::LEFT ? tri.is_east() : !tri.is_east())) - { - //slope = true; - Vector eye(get_bbox().get_left() + get_bbox().get_width() / 2.f, oy); - Vector end(eye.x + 6.5f * (m_dir == Direction::LEFT ? 1.f : -1.f), eye.y + 80.f); - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + //slope = true; + + float dirmult = (m_dir == Direction::LEFT ? 1.f : -1.f); + float rearx = (m_dir == Direction::LEFT ? get_bbox().get_right() : get_bbox().get_left()); - std::cout << result.is_valid << std::endl; + float soff = (get_width() / 5.f) * dirmult; + Vector eye(rearx - soff, oy); - if (!result.is_valid) + float eoff = soff - (2.f * dirmult); + Vector end(eye.x + eoff, eye.y + 80.f); + + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + + std::cout << result.is_valid << std::endl; + + if (!result.is_valid) + { + // Turn around and climb the slope. + m_detected_slope = 0; + return true; + } + else + { + if (result.box.get_top() - eye.y > static_cast(height) + 1.f) { - // Turn around and climb the slope. + // Result is not within reach. + std::cout << "gahh " << result.box.get_top() - eye.y << std::endl; m_detected_slope = 0; return true; } - else - { - if (result.box.get_top() - eye.y >= static_cast(height)) - { - // Result is not within reach. - std::cout << "gahh"; - m_detected_slope = 0; - return true; - } - - bool is_tile = std::holds_alternative(result.hit); - if (is_tile && std::get(result.hit)->is_slope()) - { - // Still going down a slope. Continue. - //m_detected_slope = (*tile_p)->get_data(); - return false; - } - // No longer going down a slope. Switch off slope mode. - m_detected_slope = 0; - std::cout << "aggh" << std::endl; + auto tile_p = std::get_if(&result.hit); + if (tile_p && (*tile_p) && (*tile_p)->is_slope()) + { + // Still going down a slope. Continue. + //m_detected_slope = (*tile_p)->get_data(); return false; } - } - return false; + // No longer going down a slope. Switch off slope mode. + m_detected_slope = 0; + std::cout << "aggh" << std::endl; + return false; + } } + + return false; } Player* From b75fb3efb8d1106f40d0859130cde0e18ed89282 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Thu, 15 Aug 2024 12:49:47 +0100 Subject: [PATCH 13/19] fix stuff --- src/badguy/badguy.cpp | 67 +++++++++++++++++------------------ src/badguy/badguy.hpp | 3 ++ src/badguy/walking_badguy.hpp | 3 -- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index b4658dc9022..1768d39962f 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -142,6 +142,8 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, void BadGuy::draw(DrawingContext& context) { + /* + // TODEL: this shows the detection ranges for the might_fall function. Vector eye(0, get_bbox().get_bottom() + 1.f); eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); @@ -157,6 +159,7 @@ BadGuy::draw(DrawingContext& context) float eoff = soff - (2.f * dirmult); Vector send(seye.x + eoff, seye.y + 80.f); context.color().draw_line(seye, send, Color::GREEN, LAYER_GUI); + */ if (!m_sprite.get()) return; @@ -866,20 +869,18 @@ BadGuy::might_fall(int height) Vector eye(0, oy); eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); - // TODO: change to max possible drop height - Vector end(eye.x, eye.y + 256.f); - //std::cout << eye << " " << end << std::endl; + Vector end(eye.x, eye.y + static_cast(s_normal_max_drop_height)); RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); - //bool slope = false; - auto tile_p = std::get_if(&result.hit); if (result.is_valid && result.box.get_top() - eye.y < static_cast(height)) { // The ground is within max drop height. Continue. return false; } - else if (tile_p && (*tile_p) && (*tile_p)->is_slope()) + + auto tile_p = std::get_if(&result.hit); + if (tile_p && (*tile_p) && (*tile_p)->is_slope()) { // Check if we are about to go down a slope. AATriangle tri((*tile_p)->get_data()); @@ -889,8 +890,8 @@ BadGuy::might_fall(int height) m_detected_slope = tri.dir; } - // Otherwise, climb the slope like normal. - return false; + // Otherwise, climb the slope like normal, + // by returning false at the end of this function. } else { @@ -901,18 +902,20 @@ BadGuy::might_fall(int height) if (m_detected_slope != 0) { - //AATriangle tri(m_detected_slope); - std::cout << "SLOPE " << m_detected_slope << std::endl; - //slope = true; - float dirmult = (m_dir == Direction::LEFT ? 1.f : -1.f); + + // X position of the opposite face of the hitbox relative to m_dir. float rearx = (m_dir == Direction::LEFT ? get_bbox().get_right() : get_bbox().get_left()); - float soff = (get_width() / 5.f) * dirmult; - Vector eye(rearx - soff, oy); + // X Offset from rearx used for determining the start of the raycast. + float startoff = (get_width() / 5.f) * dirmult; + Vector eye(rearx - startoff, oy); - float eoff = soff - (2.f * dirmult); - Vector end(eye.x + eoff, eye.y + 80.f); + // X Offset from eye's X used for determining the end of the raycast. + float endoff = startoff - (2.f * dirmult); + Vector end(eye.x + endoff, eye.y + 80.f); + + // The resulting line segment (eye, end) should result in a downwards facing diagonal direction. RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); @@ -924,29 +927,23 @@ BadGuy::might_fall(int height) m_detected_slope = 0; return true; } - else - { - if (result.box.get_top() - eye.y > static_cast(height) + 1.f) - { - // Result is not within reach. - std::cout << "gahh " << result.box.get_top() - eye.y << std::endl; - m_detected_slope = 0; - return true; - } - auto tile_p = std::get_if(&result.hit); - if (tile_p && (*tile_p) && (*tile_p)->is_slope()) - { - // Still going down a slope. Continue. - //m_detected_slope = (*tile_p)->get_data(); - return false; - } - - // No longer going down a slope. Switch off slope mode. + if (result.box.get_top() - eye.y > static_cast(height) + 1.f) + { + // Result is not within reach. m_detected_slope = 0; - std::cout << "aggh" << std::endl; + return true; + } + + auto tile_p = std::get_if(&result.hit); + if (tile_p && (*tile_p) && (*tile_p)->is_slope()) + { + // Still going down a slope. Continue. return false; } + + // No longer going down a slope. Switch off slope mode. + m_detected_slope = 0; } return false; diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index a4157381af9..130667fd60a 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -258,6 +258,9 @@ class BadGuy : public MovingSprite, private: void try_activate(); +protected: + static const int s_normal_max_drop_height = 600; + protected: Physic m_physic; diff --git a/src/badguy/walking_badguy.hpp b/src/badguy/walking_badguy.hpp index b65537f2e0a..7e0bb34a312 100644 --- a/src/badguy/walking_badguy.hpp +++ b/src/badguy/walking_badguy.hpp @@ -81,9 +81,6 @@ class WalkingBadguy : public BadGuy protected: void turn_around(); -protected: - static const int s_normal_max_drop_height = 600; - protected: std::string walk_left_action; std::string walk_right_action; From 14c1b6e926bc47ae8b4315b61daab7e7fab1a6d9 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Fri, 13 Sep 2024 19:45:51 +0100 Subject: [PATCH 14/19] fix objects and that weird slope fall thing --- src/badguy/badguy.cpp | 20 +++---- src/collision/collision_system.cpp | 87 +++++++++++++++++------------- src/collision/collision_system.hpp | 9 +++- src/supertux/sector.cpp | 11 +++- src/supertux/sector.hpp | 6 +++ 5 files changed, 80 insertions(+), 53 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 1768d39962f..1bc525d624e 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -306,7 +306,7 @@ BadGuy::update(float dt_sec) m_freezesprite->set_action(get_overlay_size(), 1); else m_freezesprite->set_action("default", 1); - + active_update(dt_sec); break; @@ -873,31 +873,27 @@ BadGuy::might_fall(int height) RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); - if (result.is_valid && result.box.get_top() - eye.y < static_cast(height)) + if (result.is_valid && result.box.get_top() - eye.y >= static_cast(height)) { - // The ground is within max drop height. Continue. - return false; + // The ground is deeper than max drop height. Turn around. + return true; } auto tile_p = std::get_if(&result.hit); if (tile_p && (*tile_p) && (*tile_p)->is_slope()) { - // Check if we are about to go down a slope. + AATriangle tri((*tile_p)->get_data()); + if (tri.is_south() && (m_dir == Direction::LEFT ? tri.is_east() : !tri.is_east())) { // Switch to slope mode. m_detected_slope = tri.dir; } - // Otherwise, climb the slope like normal, + // Otherwise, climb the slope like normal // by returning false at the end of this function. } - else - { - // The ground is no longer within reach. Turn around. - return true; - } } if (m_detected_slope != 0) @@ -919,8 +915,6 @@ BadGuy::might_fall(int height) RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); - std::cout << result.is_valid << std::endl; - if (!result.is_valid) { // Turn around and climb the slope. diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index 9b1d8658ad7..8c22279b0a0 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -764,46 +764,51 @@ CollisionSystem::is_free_of_specifically_movingstatics(const Rectf& rect, const CollisionSystem::RaycastResult CollisionSystem::get_first_line_intersection(const Vector& line_start, const Vector& line_end, - bool ignore_objects, + RaycastIgnore ignore, const CollisionObject* ignore_object) const { using namespace collision; - RaycastResult result{}; - - // Check if no tile is in the way. - const float lsx = std::min(line_start.x, line_end.x); - const float lex = std::max(line_start.x, line_end.x); - const float lsy = std::min(line_start.y, line_end.y); - const float ley = std::max(line_start.y, line_end.y); - - for (float test_x = lsx; test_x <= lex; test_x += 16) { // NOLINT. - for (float test_y = lsy; test_y <= ley; test_y += 16) { // NOLINT. - for (const auto& solids : m_sector.get_solid_tilemaps()) { - const auto& test_vector = Vector(test_x, test_y); - if(solids->is_outside_bounds(test_vector)) - { - continue; - } + RaycastResult tileresult{}; + tileresult.is_valid = false; - const Tile* tile = &solids->get_tile_at(test_vector); + if (ignore != IGNORE_TILES) + { + // Check if no tile is in the way. + const float lsx = std::min(line_start.x, line_end.x); + const float lex = std::max(line_start.x, line_end.x); + const float lsy = std::min(line_start.y, line_end.y); + const float ley = std::max(line_start.y, line_end.y); + + for (float test_x = lsx; test_x <= lex; test_x += 16) { // NOLINT. + for (float test_y = lsy; test_y <= ley; test_y += 16) { // NOLINT. + for (const auto& solids : m_sector.get_solid_tilemaps()) { + const auto& test_vector = Vector(test_x, test_y); + if(solids->is_outside_bounds(test_vector)) + { + continue; + } - // FIXME: check collision with slope tiles - if ((tile->get_attributes() & Tile::SOLID)) - { - result.is_valid = true; - result.hit = tile; - result.box = solids->get_tile_bbox(static_cast(test_vector.x / 32.f), static_cast(test_vector.y / 32.f)); - return result; + const Tile* tile = &solids->get_tile_at(test_vector); + + // FIXME: check collision with slope tiles + if ((tile->get_attributes() & Tile::SOLID)) + { + tileresult.is_valid = true; + tileresult.hit = tile; + tileresult.box = solids->get_tile_bbox(static_cast(test_vector.x / 32.f), static_cast(test_vector.y / 32.f)); + goto finish_tiles; + } } } } } - if (ignore_objects) - { - result.is_valid = false; - return result; - } +finish_tiles: + if (ignore == IGNORE_OBJECTS) + return tileresult; + + RaycastResult objresult{}; + objresult.is_valid = false; // Check if no object is in the way. for (const auto& object : m_objects) { @@ -815,22 +820,30 @@ CollisionSystem::get_first_line_intersection(const Vector& line_start, { if (intersects_line(object->get_bbox(), line_start, line_end)) { - result.is_valid = true; - result.hit = object; - result.box = object->get_bbox(); - return result; + objresult.is_valid = true; + objresult.hit = object; + objresult.box = object->get_bbox(); + break; } } } - result.is_valid = false; - return result; + if (ignore == IGNORE_TILES) + return objresult; + + if (tileresult.is_valid && objresult.is_valid) + return tileresult.box.get_top() < objresult.box.get_top() ? tileresult : objresult; + else if (tileresult.is_valid) + return tileresult; + else + return objresult; } bool CollisionSystem::free_line_of_sight(const Vector& line_start, const Vector& line_end, bool ignore_objects, const CollisionObject* ignore_object) const { - return !get_first_line_intersection(line_start, line_end, ignore_objects, ignore_object).is_valid; + auto ignore = (ignore_objects ? IGNORE_OBJECTS : IGNORE_NONE); + return !get_first_line_intersection(line_start, line_end, ignore, ignore_object).is_valid; } std::vector diff --git a/src/collision/collision_system.hpp b/src/collision/collision_system.hpp index 41df059de2d..ed44636271d 100644 --- a/src/collision/collision_system.hpp +++ b/src/collision/collision_system.hpp @@ -67,11 +67,16 @@ class CollisionSystem final bool is_free_of_movingstatics(const Rectf& rect, const CollisionObject* ignore_object) const; bool is_free_of_specifically_movingstatics(const Rectf& rect, const CollisionObject* ignore_object) const; + enum RaycastIgnore { + IGNORE_NONE, + IGNORE_TILES, + IGNORE_OBJECTS + }; RaycastResult get_first_line_intersection(const Vector& line_start, const Vector& line_end, - bool ignore_objects, - const CollisionObject* ignore_object) const; + RaycastIgnore ignore = IGNORE_NONE, + const CollisionObject* ignore_object = nullptr) const; bool free_line_of_sight(const Vector& line_start, const Vector& line_end, bool ignore_objects, const CollisionObject* ignore_object) const; std::vector get_nearby_objects(const Vector& center, float max_distance) const; diff --git a/src/supertux/sector.cpp b/src/supertux/sector.cpp index 5299be6d0f7..471ecaed42a 100644 --- a/src/supertux/sector.cpp +++ b/src/supertux/sector.cpp @@ -592,12 +592,21 @@ Sector::is_free_of_specifically_movingstatics(float left, float top, float right return m_collision_system->is_free_of_specifically_movingstatics(Rectf(Vector(left, top), Vector(right, bottom)), nullptr); } +CollisionSystem::RaycastResult +Sector::get_first_line_intersection(const Vector& line_start, + const Vector& line_end, + CollisionSystem::RaycastIgnore ignore, + const CollisionObject* ignore_object) const { + return m_collision_system->get_first_line_intersection(line_start, line_end, ignore, ignore_object); +} + CollisionSystem::RaycastResult Sector::get_first_line_intersection(const Vector& line_start, const Vector& line_end, bool ignore_objects, const CollisionObject* ignore_object) const { - return m_collision_system->get_first_line_intersection(line_start, line_end, ignore_objects, ignore_object); + auto ignore = (ignore_objects ? CollisionSystem::IGNORE_OBJECTS : CollisionSystem::IGNORE_NONE); + return m_collision_system->get_first_line_intersection(line_start, line_end, ignore, ignore_object); } bool diff --git a/src/supertux/sector.hpp b/src/supertux/sector.hpp index 7dbfcc57a78..9bc16e009ec 100644 --- a/src/supertux/sector.hpp +++ b/src/supertux/sector.hpp @@ -177,10 +177,16 @@ class Sector final : public Base::Sector */ bool is_free_of_specifically_movingstatics(float left, float top, float right, float bottom) const; + CollisionSystem::RaycastResult get_first_line_intersection(const Vector& line_start, + const Vector& line_end, + CollisionSystem::RaycastIgnore ignore, + const CollisionObject* ignore_object) const; + CollisionSystem::RaycastResult get_first_line_intersection(const Vector& line_start, const Vector& line_end, bool ignore_objects, const CollisionObject* ignore_object) const; + bool free_line_of_sight(const Vector& line_start, const Vector& line_end, bool ignore_objects = false, const MovingObject* ignore_object = nullptr) const; bool can_see_player(const Vector& eye) const; From f7ac61de98d23a041bca0b041e3d3d37fb87e4d4 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Sun, 15 Sep 2024 11:07:21 +0100 Subject: [PATCH 15/19] ahaeiu --- src/badguy/badguy.cpp | 9 ++++----- src/collision/collision_system.cpp | 18 ++++++++++++------ src/collision/collision_system.hpp | 2 +- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 1bc525d624e..40f9e580b78 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -862,7 +862,7 @@ BadGuy::might_fall(int height) assert(height > 0); // Origin in Y coord used for raycasting. - float oy = get_bbox().get_bottom() + 1.f; + float oy = get_bbox().get_bottom() - 1.f; if (m_detected_slope == 0) { @@ -871,9 +871,9 @@ BadGuy::might_fall(int height) Vector end(eye.x, eye.y + static_cast(s_normal_max_drop_height)); - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, this); - if (result.is_valid && result.box.get_top() - eye.y >= static_cast(height)) + if (!result.is_valid || result.box.get_top() - eye.y >= static_cast(height)) { // The ground is deeper than max drop height. Turn around. return true; @@ -882,7 +882,6 @@ BadGuy::might_fall(int height) auto tile_p = std::get_if(&result.hit); if (tile_p && (*tile_p) && (*tile_p)->is_slope()) { - AATriangle tri((*tile_p)->get_data()); if (tri.is_south() && (m_dir == Direction::LEFT ? tri.is_east() : !tri.is_east())) @@ -913,7 +912,7 @@ BadGuy::might_fall(int height) // The resulting line segment (eye, end) should result in a downwards facing diagonal direction. - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, nullptr); + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, this); if (!result.is_valid) { diff --git a/src/collision/collision_system.cpp b/src/collision/collision_system.cpp index 8c22279b0a0..558c454d61c 100644 --- a/src/collision/collision_system.cpp +++ b/src/collision/collision_system.cpp @@ -768,8 +768,7 @@ CollisionSystem::get_first_line_intersection(const Vector& line_start, const CollisionObject* ignore_object) const { using namespace collision; - RaycastResult tileresult{}; - tileresult.is_valid = false; + RaycastResult tileresult; if (ignore != IGNORE_TILES) { @@ -807,8 +806,7 @@ CollisionSystem::get_first_line_intersection(const Vector& line_start, if (ignore == IGNORE_OBJECTS) return tileresult; - RaycastResult objresult{}; - objresult.is_valid = false; + RaycastResult objresult; // Check if no object is in the way. for (const auto& object : m_objects) { @@ -832,11 +830,19 @@ CollisionSystem::get_first_line_intersection(const Vector& line_start, return objresult; if (tileresult.is_valid && objresult.is_valid) - return tileresult.box.get_top() < objresult.box.get_top() ? tileresult : objresult; + { + float tiledist = glm::distance(tileresult.box.get_middle(), line_start); + float objdist = glm::distance(objresult.box.get_middle(), line_start); + return tiledist < objdist ? tileresult : objresult; + } else if (tileresult.is_valid) return tileresult; - else + else if (objresult.is_valid) return objresult; + else + { + return RaycastResult(); + } } bool diff --git a/src/collision/collision_system.hpp b/src/collision/collision_system.hpp index ed44636271d..23d9b84e549 100644 --- a/src/collision/collision_system.hpp +++ b/src/collision/collision_system.hpp @@ -38,7 +38,7 @@ class CollisionSystem final public: struct RaycastResult { - bool is_valid; /**< true if raycast hit something */ + bool is_valid = false; /**< true if raycast hit something */ std::variant hit; /**< tile/object that the raycast hit */ Rectf box = {}; /**< hitbox of tile/object */ }; From 80195affdc4cfc676c56c4bce67f6635317c38a0 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Sun, 15 Sep 2024 11:10:08 +0100 Subject: [PATCH 16/19] offsets n' shit --- src/badguy/badguy.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 40f9e580b78..4edf7d3162b 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -862,18 +862,18 @@ BadGuy::might_fall(int height) assert(height > 0); // Origin in Y coord used for raycasting. - float oy = get_bbox().get_bottom() - 1.f; + float oy = get_bbox().get_bottom() + 1.f; if (m_detected_slope == 0) { - Vector eye(0, oy); + Vector eye(0, oy - 2.f); eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); - Vector end(eye.x, eye.y + static_cast(s_normal_max_drop_height)); + Vector end(eye.x, eye.y + static_cast(s_normal_max_drop_height + 2)); RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, this); - if (!result.is_valid || result.box.get_top() - eye.y >= static_cast(height)) + if (!result.is_valid || result.box.get_top() - oy >= static_cast(height)) { // The ground is deeper than max drop height. Turn around. return true; @@ -921,7 +921,7 @@ BadGuy::might_fall(int height) return true; } - if (result.box.get_top() - eye.y > static_cast(height) + 1.f) + if (result.box.get_top() - oy > static_cast(height) + 1.f) { // Result is not within reach. m_detected_slope = 0; From 71d206ba85eaa4dd27c04dd22178eb5c719e16e4 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Sun, 15 Sep 2024 16:08:13 +0100 Subject: [PATCH 17/19] bgah --- src/badguy/badguy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 4edf7d3162b..d6b7c0a61cf 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -871,7 +871,7 @@ BadGuy::might_fall(int height) Vector end(eye.x, eye.y + static_cast(s_normal_max_drop_height + 2)); - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, this); + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, &m_col); if (!result.is_valid || result.box.get_top() - oy >= static_cast(height)) { @@ -912,7 +912,7 @@ BadGuy::might_fall(int height) // The resulting line segment (eye, end) should result in a downwards facing diagonal direction. - RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, this); + RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, &m_col); if (!result.is_valid) { From a5b24179beed9c5a97c959762a6d3283450cb007 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Mon, 16 Sep 2024 20:54:13 +0100 Subject: [PATCH 18/19] fix this weird thing --- src/badguy/badguy.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index d6b7c0a61cf..cc60cf0cb74 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -864,16 +864,18 @@ BadGuy::might_fall(int height) // Origin in Y coord used for raycasting. float oy = get_bbox().get_bottom() + 1.f; + float fh = static_cast(height); + if (m_detected_slope == 0) { Vector eye(0, oy - 2.f); eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); - Vector end(eye.x, eye.y + static_cast(s_normal_max_drop_height + 2)); + Vector end(eye.x, eye.y + fh + 2.f); RaycastResult result = Sector::get().get_first_line_intersection(eye, end, false, &m_col); - if (!result.is_valid || result.box.get_top() - oy >= static_cast(height)) + if (!result.is_valid) { // The ground is deeper than max drop height. Turn around. return true; @@ -921,7 +923,7 @@ BadGuy::might_fall(int height) return true; } - if (result.box.get_top() - oy > static_cast(height) + 1.f) + if (result.box.get_top() - oy > fh + 1.f) { // Result is not within reach. m_detected_slope = 0; From 47c535ac1685e8e84b9a8a69ba192c7aefcd4e28 Mon Sep 17 00:00:00 2001 From: MatusGuy Date: Mon, 16 Sep 2024 20:59:35 +0100 Subject: [PATCH 19/19] del --- src/badguy/badguy.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index c04eff1277f..b65bacac9b1 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -143,25 +143,6 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, void BadGuy::draw(DrawingContext& context) { - /* - // TODEL: this shows the detection ranges for the might_fall function. - Vector eye(0, get_bbox().get_bottom() + 1.f); - eye.x = (m_dir == Direction::LEFT ? get_bbox().get_left() : get_bbox().get_right()); - - Vector end(eye.x, eye.y + 256.f); - context.color().draw_line(eye, end, Color::GREEN, LAYER_GUI); - - float dirmult = (m_dir == Direction::LEFT ? 1.f : -1.f); - float rearx = (m_dir == Direction::LEFT ? get_bbox().get_right() : get_bbox().get_left()); - - float soff = (get_width() / 5.f) * dirmult; - Vector seye(rearx - soff, eye.y); - - float eoff = soff - (2.f * dirmult); - Vector send(seye.x + eoff, seye.y + 80.f); - context.color().draw_line(seye, send, Color::GREEN, LAYER_GUI); - */ - if (!m_sprite.get()) return; Vector draw_offset = context.get_time_offset() * m_physic.get_velocity();