From 67b24a8ddd89371cfb944c5b441c852f0edc23b1 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 8 May 2018 21:47:57 -0400 Subject: Fixed ferries pushing passengers Ferries now pretend that their passengers have already moved by the appropriate delta when detecting collision in the direction of their passengers. This allows a ferry to move into the space where their passengers are when there is nothing else blocking it. It also allows for special behavior when a passenger is crushed between its ferry and a wall, but this is not yet implemented. This fixes the first issue described in 8f1c4f1 -- that ferries cannot push their passengers. With this fix, ferries are basically functional. --- src/components/ponderable.h | 5 +- src/systems/pondering.cpp | 222 +++++++++++++++++++++++++++----------------- src/systems/pondering.h | 3 +- 3 files changed, 141 insertions(+), 89 deletions(-) diff --git a/src/components/ponderable.h b/src/components/ponderable.h index c0312b4..e6aa976 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -5,6 +5,7 @@ #include "component.h" #include "entity_manager.h" #include "vector.h" +#include "direction.h" class PonderableComponent : public Component { public: @@ -84,11 +85,11 @@ public: id_type ferry; /** - * The location of the body relative to the location of its ferry. + * The side of the ferry that the body is resting on, if there is one. * * @managed_by PonderingSystem */ - vec2d rel = { 0.0, 0.0 }; + Direction ferrySide; /** * The bodies that are being ferried by this body. diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index ec83270..c806cc8 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -31,10 +31,7 @@ void PonderingSystem::tick(double dt) continue; } - tickBody( - entity, - dt, - entities); + tickBody(entity, dt); } } @@ -85,8 +82,7 @@ void PonderingSystem::unferry(id_type entity) void PonderingSystem::tickBody( id_type entity, - double dt, - const std::set& entities) + double dt) { auto& ponderable = game_.getEntityManager(). getComponent(entity); @@ -116,14 +112,6 @@ void PonderingSystem::tickBody( if (!ponderable.frozen) { - if (ponderable.ferried) - { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); - - newPos = ferryTrans.pos + ponderable.rel; - } - newPos += ponderable.vel * dt; } @@ -171,6 +159,7 @@ void PonderingSystem::tickBody( ponderable.ferried = true; ponderable.ferry = result.groundEntity; + ponderable.ferrySide = Direction::up; ferryPonder.passengers.insert(entity); } else if (ponderable.ferried) @@ -180,67 +169,12 @@ void PonderingSystem::tickBody( } } - // Update a ferry passenger's relative position - if (ponderable.ferried) - { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); - - ponderable.rel = transformable.pos - ferryTrans.pos; - } - // Handle ferry passengers std::set passengers = ponderable.passengers; for (id_type passenger : passengers) { - tickBody( - passenger, - dt, - entities); - } - - // Move to an adjacent map, if necessary - if (result.adjacentlyWarping) - { - vec2d warpPos = result.pos; - - switch (result.adjWarpDir) - { - case Direction::left: - { - warpPos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); - - break; - } - - case Direction::right: - { - warpPos.x() = -WALL_GAP; - - break; - } - - case Direction::up: - { - warpPos.y() = MAP_HEIGHT * TILE_HEIGHT - transformable.size.h(); - - break; - } - - case Direction::down: - { - warpPos.y() = -WALL_GAP; - - break; - } - } - - game_.getSystemManager().getSystem(). - changeMap( - entity, - result.adjWarpMapId, - warpPos); + tickBody(passenger, dt); } } @@ -251,9 +185,6 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( auto& ponderable = game_.getEntityManager(). getComponent(entity); - auto& transformable = game_.getEntityManager(). - getComponent(entity); - CollisionResult result; if (ponderable.collidable) @@ -263,11 +194,17 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( result.pos = newPos; } - // Move if (!ponderable.frozen) { + auto& transformable = game_.getEntityManager(). + getComponent(entity); + + vec2d delta = result.pos - transformable.pos; + + // Move. transformable.pos = result.pos; + // Stop if the entity hit a wall. if (result.blockedHoriz) { ponderable.vel.x() = 0.0; @@ -277,6 +214,60 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( { ponderable.vel.y() = 0.0; } + + // Move ferry passengers by the appropriate amount. + auto passengers = ponderable.passengers; + + for (id_type passenger : passengers) + { + auto& passTrans = game_.getEntityManager(). + getComponent(passenger); + + moveBody(passenger, passTrans.pos + delta); + } + + // Move to an adjacent map, if necessary + if (result.adjacentlyWarping) + { + vec2d warpPos = result.pos; + + switch (result.adjWarpDir) + { + case Direction::left: + { + warpPos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); + + break; + } + + case Direction::right: + { + warpPos.x() = -WALL_GAP; + + break; + } + + case Direction::up: + { + warpPos.y() = MAP_HEIGHT * TILE_HEIGHT - transformable.size.h(); + + break; + } + + case Direction::down: + { + warpPos.y() = -WALL_GAP; + + break; + } + } + + game_.getSystemManager().getSystem(). + changeMap( + entity, + result.adjWarpMapId, + warpPos); + } } return result; @@ -506,6 +497,9 @@ void PonderingSystem::detectCollisionsInDirection( auto& transform = game_.getEntityManager(). getComponent(entity); + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + bool boundaryCollision = false; auto boundaries = Param::MapBoundaries(mappable); @@ -530,6 +524,26 @@ void PonderingSystem::detectCollisionsInDirection( } } + // Find the results of pretending to move the entity's passengers, if there + // are any. + vec2d delta = result.pos - transform.pos; + std::map passResults; + + for (id_type passenger : ponderable.passengers) + { + auto& passPonder = game_.getEntityManager(). + getComponent(passenger); + + if (passPonder.ferrySide == Param::Dir) + { + auto& passTrans = game_.getEntityManager(). + getComponent(passenger); + + passResults[passenger] = + detectCollisions(passenger, passTrans.pos + delta); + } + } + // Find a list of potential colliders, sorted so that the closest is // first. std::vector colliders; @@ -555,33 +569,46 @@ void PonderingSystem::detectCollisionsInDirection( continue; } + // If the collider is a passenger of the entity, pretend that it has already + // moved. auto& colliderTrans = game_.getEntityManager(). getComponent(collider); + vec2d colliderPos = colliderTrans.pos; + vec2i colliderSize = colliderTrans.size; + + if (passResults.count(collider)) + { + colliderPos = passResults[collider].pos; + } + // Check if the entity would move into the potential collider, if (Param::IsPastAxis( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), Param::EntityAxis(result.pos, transform.size)) && // that it wasn't already colliding, !Param::IsPastAxis( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), Param::EntityAxis(transform)) && // that the position on the non-axis is in range, - (Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size) > + (Param::NonAxisUpper(colliderPos, colliderSize) > Param::NonAxisLower(result.pos)) && - (Param::NonAxisLower(colliderTrans.pos) < + (Param::NonAxisLower(colliderPos) < Param::NonAxisUpper(result.pos, transform.size)) && // and that the collider is not farther away than the environmental // boundary. (!boundaryCollision || Param::AtLeastInAxisSweep( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), it->first))) { colliders.push_back(collider); } } + // Sort the potential colliders such that the closest to the axis of movement + // is first. When sorting, treat passengers of the entity as having already + // moved. std::sort( std::begin(colliders), std::end(colliders), @@ -589,12 +616,26 @@ void PonderingSystem::detectCollisionsInDirection( auto& leftTrans = game_.getEntityManager(). getComponent(left); + vec2d leftPos = leftTrans.pos; + + if (passResults.count(left)) + { + leftPos = passResults[left].pos; + } + auto& rightTrans = game_.getEntityManager(). getComponent(right); + vec2d rightPos = rightTrans.pos; + + if (passResults.count(right)) + { + rightPos = passResults[right].pos; + } + return Param::Closer( - Param::ObjectAxis(leftTrans), - Param::ObjectAxis(rightTrans)); + Param::ObjectAxis(leftPos, leftTrans.size), + Param::ObjectAxis(rightPos, rightTrans.size)); }); for (id_type collider : colliders) @@ -602,14 +643,25 @@ void PonderingSystem::detectCollisionsInDirection( auto& colliderTrans = game_.getEntityManager(). getComponent(collider); + // If the collider is a passenger of the entity, pretend that it has already + // moved. + vec2d colliderPos = colliderTrans.pos; + vec2i colliderSize = colliderTrans.size; + + if (passResults.count(collider)) + { + colliderPos = passResults[collider].pos; + } + // Check if the entity would still move into the potential collider. if (!Param::IsPastAxis( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), Param::EntityAxis(result.pos, transform.size))) { break; } + // TODO: Check if the entity is moving into one of its passengers. auto& colliderPonder = game_.getEntityManager(). getComponent(collider); @@ -618,9 +670,9 @@ void PonderingSystem::detectCollisionsInDirection( collider, Param::Dir, colliderPonder.colliderType, - Param::ObjectAxis(colliderTrans), - Param::NonAxisLower(colliderTrans.pos), - Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size), + Param::ObjectAxis(colliderPos, colliderSize), + Param::NonAxisLower(colliderPos), + Param::NonAxisUpper(colliderPos, colliderSize), result); if (result.stopProcessing) diff --git a/src/systems/pondering.h b/src/systems/pondering.h index 273db67..c79bbf6 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -51,8 +51,7 @@ private: void tickBody( id_type entity, - double dt, - const std::set& entities); + double dt); CollisionResult moveBody( id_type entity, -- cgit 1.4.1