From a6d1ded1a41d0f461bf340a33e21fa896ce9da66 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 11 Mar 2021 17:29:02 -0500 Subject: Added sliding around solid tiles #3 --- src/character_system.cpp | 2 +- src/main.cpp | 1 + src/sprite.h | 1 + src/transform_system.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++++++- src/transform_system.h | 7 ++++- 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/character_system.cpp b/src/character_system.cpp index 10cb06f..368505e 100644 --- a/src/character_system.cpp +++ b/src/character_system.cpp @@ -153,7 +153,7 @@ void CharacterSystem::tick(double dt) { pLoc += (unitVecInDirection(sprite.movementDir) * speed); // Check collision. - CollisionResult collision = game_.getSystem().checkCollision(spriteId, sprite.loc, pLoc, sprite.movementDir); + CollisionResult collision = game_.getSystem().checkCollision(spriteId, sprite.loc, pLoc, sprite.movementDir, CheckCollisionOptions::AllowSliding); if (!(collision.blocked && sprite.clipping)) { pLoc = collision.adjustedLoc; diff --git a/src/main.cpp b/src/main.cpp index dcf96e5..b515891 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,6 +42,7 @@ void loop(Renderer& renderer, std::mt19937& rng) { game.getSprite(lucasSprite).player = true; game.getSprite(lucasSprite).controllable = true; game.getSprite(lucasSprite).persistent = true; + game.getSprite(lucasSprite).sliding = true; game.getSystem().initSprite(lucasSprite, LUCAS_MOVEMENT_SPEED); game.getSystem().setFollowingSprite(lucasSprite); game.getSystem().unlockCamera(); diff --git a/src/sprite.h b/src/sprite.h index f631652..413c20d 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -83,6 +83,7 @@ public: std::string walkthroughScript; std::string bumpPlayerScript; std::string enclosureZone; + bool sliding = false; // Animation (internals) bool isAnimated = false; diff --git a/src/transform_system.cpp b/src/transform_system.cpp index a643255..825514f 100644 --- a/src/transform_system.cpp +++ b/src/transform_system.cpp @@ -2,6 +2,10 @@ #include "game.h" #include "map.h" +bool checkCollisionOptionsContains(CheckCollisionOptions options, CheckCollisionOptions value) { + return (static_cast(options) & static_cast(value)) != 0; +} + void TransformSystem::initSprite(int spriteId, vec2i loc, SpriteLayer layer) { Sprite& sprite = game_.getSprite(spriteId); sprite.loc = loc; @@ -47,7 +51,7 @@ void TransformSystem::moveSprite(int spriteId, vec2i newLoc) { } } -CollisionResult TransformSystem::checkCollision(int spriteId, vec2i curLoc, vec2i newLoc, Direction dir) { +CollisionResult TransformSystem::checkCollision(int spriteId, vec2i curLoc, vec2i newLoc, Direction dir, CheckCollisionOptions options) { CollisionResult result; Sprite& sprite = game_.getSprite(spriteId); @@ -87,6 +91,22 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i curLoc, vec2 break; } } + + if (checkCollisionOptionsContains(options, CheckCollisionOptions::AllowSliding) && + sprite.sliding && + dir == Direction::right && + horizBlocked && + oldTileUL.y() != oldTileDR.y()) { + // If sliding is enabled for this sprite, check if we can slide + // either perpendicular direction. Because sliding can only happen + // if we were moving in a cardinal direction, we can use tail + // recursion and exit early. + if (!map.isBlocked(oldTileDR.x()+1, oldTileUL.y())) { + return checkCollision(spriteId, curLoc, curLoc - vec2i{0,1} * sprite.movementSpeed, Direction::up); + } else if (!map.isBlocked(oldTileDR.x()+1, oldTileDR.y())) { + return checkCollision(spriteId, curLoc, curLoc + vec2i{0,1} * sprite.movementSpeed, Direction::down); + } + } } if (!horizBlocked && enclosureZone) { @@ -128,6 +148,22 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i curLoc, vec2 break; } } + + if (checkCollisionOptionsContains(options, CheckCollisionOptions::AllowSliding) && + sprite.sliding && + dir == Direction::left && + horizBlocked && + oldTileUL.y() != oldTileDR.y()) { + // If sliding is enabled for this sprite, check if we can slide + // either perpendicular direction. Because sliding can only happen + // if we were moving in a cardinal direction, we can use tail + // recursion and exit early. + if (!map.isBlocked(oldTileUL.x()-1, oldTileUL.y())) { + return checkCollision(spriteId, curLoc, curLoc - vec2i{0,1} * sprite.movementSpeed, Direction::up); + } else if (!map.isBlocked(oldTileUL.x()-1, oldTileDR.y())) { + return checkCollision(spriteId, curLoc, curLoc + vec2i{0,1} * sprite.movementSpeed, Direction::down); + } + } } if (!horizBlocked && enclosureZone) { @@ -191,6 +227,22 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i curLoc, vec2 break; } } + + if (checkCollisionOptionsContains(options, CheckCollisionOptions::AllowSliding) && + sprite.sliding && + dir == Direction::down && + vertBlocked && + oldTileUL.x() != oldTileDR.x()) { + // If sliding is enabled for this sprite, check if we can slide + // either perpendicular direction. Because sliding can only happen + // if we were moving in a cardinal direction, we can use tail + // recursion and exit early. + if (!map.isBlocked(oldTileUL.x(), oldTileDR.y()+1)) { + return checkCollision(spriteId, curLoc, curLoc - vec2i{1,0} * sprite.movementSpeed, Direction::left); + } else if (!map.isBlocked(oldTileDR.x(), oldTileDR.y()+1)) { + return checkCollision(spriteId, curLoc, curLoc + vec2i{1,0} * sprite.movementSpeed, Direction::right); + } + } } if (!vertBlocked && enclosureZone) { @@ -232,6 +284,22 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i curLoc, vec2 break; } } + + if (checkCollisionOptionsContains(options, CheckCollisionOptions::AllowSliding) && + sprite.sliding && + dir == Direction::up && + vertBlocked && + oldTileUL.x() != oldTileDR.x()) { + // If sliding is enabled for this sprite, check if we can slide + // either perpendicular direction. Because sliding can only happen + // if we were moving in a cardinal direction, we can use tail + // recursion and exit early. + if (!map.isBlocked(oldTileUL.x(), oldTileUL.y()-1)) { + return checkCollision(spriteId, curLoc, curLoc - vec2i{1,0} * sprite.movementSpeed, Direction::left); + } else if (!map.isBlocked(oldTileDR.x(), oldTileUL.y()-1)) { + return checkCollision(spriteId, curLoc, curLoc + vec2i{1,0} * sprite.movementSpeed, Direction::right); + } + } } if (!vertBlocked && enclosureZone) { diff --git a/src/transform_system.h b/src/transform_system.h index 476b8d8..03f391a 100644 --- a/src/transform_system.h +++ b/src/transform_system.h @@ -21,6 +21,11 @@ struct CollisionResult { vec2i adjustedLoc; }; +enum class CheckCollisionOptions { + None = 0, + AllowSliding = 1 << 0 +}; + class TransformSystem : public System { public: @@ -42,7 +47,7 @@ public: }); } - CollisionResult checkCollision(int spriteId, vec2i curLoc, vec2i newLoc, Direction dir); + CollisionResult checkCollision(int spriteId, vec2i curLoc, vec2i newLoc, Direction dir, CheckCollisionOptions options = CheckCollisionOptions::None); CharacterMedium getMediumAtPosition(int spriteId, vec2i newLoc); -- cgit 1.4.1