From 705aa2a448c665dcf00351c8471de2024b75f102 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 11 Jan 2026 20:54:51 +0100 Subject: [PATCH 1/3] Addition of wall collisions --- lib/include/chomper/player.hpp | 1 + lib/src/player.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/include/chomper/player.hpp b/lib/include/chomper/player.hpp index a96fe7c..1235d2b 100644 --- a/lib/include/chomper/player.hpp +++ b/lib/include/chomper/player.hpp @@ -20,6 +20,7 @@ class Player : public IController::IListener, public IDebugInspector, public kli private: bool selfCollides() const; + bool wallCollides() const; void move(); // IController::IListener diff --git a/lib/src/player.cpp b/lib/src/player.cpp index 27cada5..75d30b1 100644 --- a/lib/src/player.cpp +++ b/lib/src/player.cpp @@ -34,6 +34,11 @@ bool Player::selfCollides() const { }); } +bool Player::wallCollides() const { + auto targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; + return targetGrid.x <= 0 || targetGrid.y <= 0 || targetGrid.x > worldSize_v.x || targetGrid.y > worldSize_v.y; +} + void Player::move() { // no body, no movement if (m_snake.getSegments().empty()) { @@ -45,7 +50,7 @@ void Player::move() { m_headingQueue.erase(m_headingQueue.begin()); } - if (selfCollides()) { + if (selfCollides() || wallCollides()) { if (m_graceMove) { m_engine->setNextRuntime(); } else { From 6af68f6bb0bba3b4c070536f8479049723fd8d2a Mon Sep 17 00:00:00 2001 From: = Date: Sun, 11 Jan 2026 22:22:53 +0100 Subject: [PATCH 2/3] Add requested changes --- lib/include/chomper/player.hpp | 4 ++-- lib/include/chomper/world_space.hpp | 5 +++++ lib/src/player.cpp | 18 ++++++++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/include/chomper/player.hpp b/lib/include/chomper/player.hpp index 1235d2b..4a99664 100644 --- a/lib/include/chomper/player.hpp +++ b/lib/include/chomper/player.hpp @@ -19,8 +19,8 @@ class Player : public IController::IListener, public IDebugInspector, public kli void draw(le::IRenderer& renderer) const; private: - bool selfCollides() const; - bool wallCollides() const; + [[nodiscard]] bool isCollidingWithSelf() const; + [[nodiscard]] bool isCollidingWithWall() const; void move(); // IController::IListener diff --git a/lib/include/chomper/world_space.hpp b/lib/include/chomper/world_space.hpp index e56844e..ef9c337 100644 --- a/lib/include/chomper/world_space.hpp +++ b/lib/include/chomper/world_space.hpp @@ -1,5 +1,6 @@ #pragma once #include "chomper/world_size.hpp" +#include "glm/common.hpp" #include namespace chomper::worldSpace { @@ -16,4 +17,8 @@ constexpr auto gridToWorld(glm::vec2 gridPosition) { constexpr auto worldToGrid(glm::vec2 worldPosition) { return glm::floor((worldPosition - tileOffset) / tileSize_v) + halfGridSize; } + +constexpr auto isOutOfBounds(glm::vec2 gridPoint) { + return gridPoint.x <= 0 || gridPoint.y <= 0 || gridPoint.x > worldSize_v.x || gridPoint.y > worldSize_v.y; +} } // namespace chomper::worldSpace \ No newline at end of file diff --git a/lib/src/player.cpp b/lib/src/player.cpp index 75d30b1..4cf2299 100644 --- a/lib/src/player.cpp +++ b/lib/src/player.cpp @@ -27,16 +27,22 @@ void Player::tick(kvf::Seconds dt) { } } -bool Player::selfCollides() const { - auto targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; +bool Player::isCollidingWithSelf() const { + if (m_snake.getSegments().empty()) { + return false; + } + auto const targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; return std::ranges::any_of(m_snake.getSegments(), [targetGrid](le::RenderInstance const& s) { return worldSpace::worldToGrid(s.transform.position) == targetGrid; }); } -bool Player::wallCollides() const { - auto targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; - return targetGrid.x <= 0 || targetGrid.y <= 0 || targetGrid.x > worldSize_v.x || targetGrid.y > worldSize_v.y; +bool Player::isCollidingWithWall() const { + if (m_snake.getSegments().empty()) { + return false; + } + auto const targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; + return worldSpace::isOutOfBounds(targetGrid); } void Player::move() { @@ -50,7 +56,7 @@ void Player::move() { m_headingQueue.erase(m_headingQueue.begin()); } - if (selfCollides() || wallCollides()) { + if (isCollidingWithSelf() || isCollidingWithWall()) { if (m_graceMove) { m_engine->setNextRuntime(); } else { From b684bf7687b1bb661efaa35ab86f6ee8374efa1b Mon Sep 17 00:00:00 2001 From: = Date: Sun, 11 Jan 2026 22:31:09 +0100 Subject: [PATCH 3/3] compute `targetGrid` once, instead of twice --- lib/include/chomper/player.hpp | 4 ++-- lib/src/player.cpp | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/include/chomper/player.hpp b/lib/include/chomper/player.hpp index 4a99664..065b01c 100644 --- a/lib/include/chomper/player.hpp +++ b/lib/include/chomper/player.hpp @@ -19,8 +19,8 @@ class Player : public IController::IListener, public IDebugInspector, public kli void draw(le::IRenderer& renderer) const; private: - [[nodiscard]] bool isCollidingWithSelf() const; - [[nodiscard]] bool isCollidingWithWall() const; + [[nodiscard]] bool isCollidingWithSelf(glm::vec2 targetGrid) const; + [[nodiscard]] bool isCollidingWithWall(glm::vec2 targetGrid) const; void move(); // IController::IListener diff --git a/lib/src/player.cpp b/lib/src/player.cpp index 4cf2299..9cd6621 100644 --- a/lib/src/player.cpp +++ b/lib/src/player.cpp @@ -27,21 +27,19 @@ void Player::tick(kvf::Seconds dt) { } } -bool Player::isCollidingWithSelf() const { +bool Player::isCollidingWithSelf(glm::vec2 const targetGrid) const { if (m_snake.getSegments().empty()) { return false; } - auto const targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; return std::ranges::any_of(m_snake.getSegments(), [targetGrid](le::RenderInstance const& s) { return worldSpace::worldToGrid(s.transform.position) == targetGrid; }); } -bool Player::isCollidingWithWall() const { +bool Player::isCollidingWithWall(glm::vec2 const targetGrid) const { if (m_snake.getSegments().empty()) { return false; } - auto const targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; return worldSpace::isOutOfBounds(targetGrid); } @@ -56,7 +54,8 @@ void Player::move() { m_headingQueue.erase(m_headingQueue.begin()); } - if (isCollidingWithSelf() || isCollidingWithWall()) { + auto const targetGrid = worldSpace::worldToGrid(m_snake.getSegments().back().transform.position) + headingToDir_v[m_heading]; + if (isCollidingWithSelf(targetGrid) || isCollidingWithWall(targetGrid)) { if (m_graceMove) { m_engine->setNextRuntime(); } else {