diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-05-08 21:47:57 -0400 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-05-09 17:59:13 -0400 |
commit | 67b24a8ddd89371cfb944c5b441c852f0edc23b1 (patch) | |
tree | d52c054e35e680bcc65c0acafc924dc1deb6c50e | |
parent | 5c82f052c26303318e81ddd76475c1d188cc74f4 (diff) | |
download | therapy-67b24a8ddd89371cfb944c5b441c852f0edc23b1.tar.gz therapy-67b24a8ddd89371cfb944c5b441c852f0edc23b1.tar.bz2 therapy-67b24a8ddd89371cfb944c5b441c852f0edc23b1.zip |
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.
-rw-r--r-- | src/components/ponderable.h | 5 | ||||
-rw-r--r-- | src/systems/pondering.cpp | 222 | ||||
-rw-r--r-- | 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 @@ | |||
5 | #include "component.h" | 5 | #include "component.h" |
6 | #include "entity_manager.h" | 6 | #include "entity_manager.h" |
7 | #include "vector.h" | 7 | #include "vector.h" |
8 | #include "direction.h" | ||
8 | 9 | ||
9 | class PonderableComponent : public Component { | 10 | class PonderableComponent : public Component { |
10 | public: | 11 | public: |
@@ -84,11 +85,11 @@ public: | |||
84 | id_type ferry; | 85 | id_type ferry; |
85 | 86 | ||
86 | /** | 87 | /** |
87 | * The location of the body relative to the location of its ferry. | 88 | * The side of the ferry that the body is resting on, if there is one. |
88 | * | 89 | * |
89 | * @managed_by PonderingSystem | 90 | * @managed_by PonderingSystem |
90 | */ | 91 | */ |
91 | vec2d rel = { 0.0, 0.0 }; | 92 | Direction ferrySide; |
92 | 93 | ||
93 | /** | 94 | /** |
94 | * The bodies that are being ferried by this body. | 95 | * 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) | |||
31 | continue; | 31 | continue; |
32 | } | 32 | } |
33 | 33 | ||
34 | tickBody( | 34 | tickBody(entity, dt); |
35 | entity, | ||
36 | dt, | ||
37 | entities); | ||
38 | } | 35 | } |
39 | } | 36 | } |
40 | 37 | ||
@@ -85,8 +82,7 @@ void PonderingSystem::unferry(id_type entity) | |||
85 | 82 | ||
86 | void PonderingSystem::tickBody( | 83 | void PonderingSystem::tickBody( |
87 | id_type entity, | 84 | id_type entity, |
88 | double dt, | 85 | double dt) |
89 | const std::set<id_type>& entities) | ||
90 | { | 86 | { |
91 | auto& ponderable = game_.getEntityManager(). | 87 | auto& ponderable = game_.getEntityManager(). |
92 | getComponent<PonderableComponent>(entity); | 88 | getComponent<PonderableComponent>(entity); |
@@ -116,14 +112,6 @@ void PonderingSystem::tickBody( | |||
116 | 112 | ||
117 | if (!ponderable.frozen) | 113 | if (!ponderable.frozen) |
118 | { | 114 | { |
119 | if (ponderable.ferried) | ||
120 | { | ||
121 | auto& ferryTrans = game_.getEntityManager(). | ||
122 | getComponent<TransformableComponent>(ponderable.ferry); | ||
123 | |||
124 | newPos = ferryTrans.pos + ponderable.rel; | ||
125 | } | ||
126 | |||
127 | newPos += ponderable.vel * dt; | 115 | newPos += ponderable.vel * dt; |
128 | } | 116 | } |
129 | 117 | ||
@@ -171,6 +159,7 @@ void PonderingSystem::tickBody( | |||
171 | 159 | ||
172 | ponderable.ferried = true; | 160 | ponderable.ferried = true; |
173 | ponderable.ferry = result.groundEntity; | 161 | ponderable.ferry = result.groundEntity; |
162 | ponderable.ferrySide = Direction::up; | ||
174 | 163 | ||
175 | ferryPonder.passengers.insert(entity); | 164 | ferryPonder.passengers.insert(entity); |
176 | } else if (ponderable.ferried) | 165 | } else if (ponderable.ferried) |
@@ -180,67 +169,12 @@ void PonderingSystem::tickBody( | |||
180 | } | 169 | } |
181 | } | 170 | } |
182 | 171 | ||
183 | // Update a ferry passenger's relative position | ||
184 | if (ponderable.ferried) | ||
185 | { | ||
186 | auto& ferryTrans = game_.getEntityManager(). | ||
187 | getComponent<TransformableComponent>(ponderable.ferry); | ||
188 | |||
189 | ponderable.rel = transformable.pos - ferryTrans.pos; | ||
190 | } | ||
191 | |||
192 | // Handle ferry passengers | 172 | // Handle ferry passengers |
193 | std::set<id_type> passengers = ponderable.passengers; | 173 | std::set<id_type> passengers = ponderable.passengers; |
194 | 174 | ||
195 | for (id_type passenger : passengers) | 175 | for (id_type passenger : passengers) |
196 | { | 176 | { |
197 | tickBody( | 177 | tickBody(passenger, dt); |
198 | passenger, | ||
199 | dt, | ||
200 | entities); | ||
201 | } | ||
202 | |||
203 | // Move to an adjacent map, if necessary | ||
204 | if (result.adjacentlyWarping) | ||
205 | { | ||
206 | vec2d warpPos = result.pos; | ||
207 | |||
208 | switch (result.adjWarpDir) | ||
209 | { | ||
210 | case Direction::left: | ||
211 | { | ||
212 | warpPos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); | ||
213 | |||
214 | break; | ||
215 | } | ||
216 | |||
217 | case Direction::right: | ||
218 | { | ||
219 | warpPos.x() = -WALL_GAP; | ||
220 | |||
221 | break; | ||
222 | } | ||
223 | |||
224 | case Direction::up: | ||
225 | { | ||
226 | warpPos.y() = MAP_HEIGHT * TILE_HEIGHT - transformable.size.h(); | ||
227 | |||
228 | break; | ||
229 | } | ||
230 | |||
231 | case Direction::down: | ||
232 | { | ||
233 | warpPos.y() = -WALL_GAP; | ||
234 | |||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | game_.getSystemManager().getSystem<PlayingSystem>(). | ||
240 | changeMap( | ||
241 | entity, | ||
242 | result.adjWarpMapId, | ||
243 | warpPos); | ||
244 | } | 178 | } |
245 | } | 179 | } |
246 | 180 | ||
@@ -251,9 +185,6 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( | |||
251 | auto& ponderable = game_.getEntityManager(). | 185 | auto& ponderable = game_.getEntityManager(). |
252 | getComponent<PonderableComponent>(entity); | 186 | getComponent<PonderableComponent>(entity); |
253 | 187 | ||
254 | auto& transformable = game_.getEntityManager(). | ||
255 | getComponent<TransformableComponent>(entity); | ||
256 | |||
257 | CollisionResult result; | 188 | CollisionResult result; |
258 | 189 | ||
259 | if (ponderable.collidable) | 190 | if (ponderable.collidable) |
@@ -263,11 +194,17 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( | |||
263 | result.pos = newPos; | 194 | result.pos = newPos; |
264 | } | 195 | } |
265 | 196 | ||
266 | // Move | ||
267 | if (!ponderable.frozen) | 197 | if (!ponderable.frozen) |
268 | { | 198 | { |
199 | auto& transformable = game_.getEntityManager(). | ||
200 | getComponent<TransformableComponent>(entity); | ||
201 | |||
202 | vec2d delta = result.pos - transformable.pos; | ||
203 | |||
204 | // Move. | ||
269 | transformable.pos = result.pos; | 205 | transformable.pos = result.pos; |
270 | 206 | ||
207 | // Stop if the entity hit a wall. | ||
271 | if (result.blockedHoriz) | 208 | if (result.blockedHoriz) |
272 | { | 209 | { |
273 | ponderable.vel.x() = 0.0; | 210 | ponderable.vel.x() = 0.0; |
@@ -277,6 +214,60 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( | |||
277 | { | 214 | { |
278 | ponderable.vel.y() = 0.0; | 215 | ponderable.vel.y() = 0.0; |
279 | } | 216 | } |
217 | |||
218 | // Move ferry passengers by the appropriate amount. | ||
219 | auto passengers = ponderable.passengers; | ||
220 | |||
221 | for (id_type passenger : passengers) | ||
222 | { | ||
223 | auto& passTrans = game_.getEntityManager(). | ||
224 | getComponent<TransformableComponent>(passenger); | ||
225 | |||
226 | moveBody(passenger, passTrans.pos + delta); | ||
227 | } | ||
228 | |||
229 | // Move to an adjacent map, if necessary | ||
230 | if (result.adjacentlyWarping) | ||
231 | { | ||
232 | vec2d warpPos = result.pos; | ||
233 | |||
234 | switch (result.adjWarpDir) | ||
235 | { | ||
236 | case Direction::left: | ||
237 | { | ||
238 | warpPos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); | ||
239 | |||
240 | break; | ||
241 | } | ||
242 | |||
243 | case Direction::right: | ||
244 | { | ||
245 | warpPos.x() = -WALL_GAP; | ||
246 | |||
247 | break; | ||
248 | } | ||
249 | |||
250 | case Direction::up: | ||
251 | { | ||
252 | warpPos.y() = MAP_HEIGHT * TILE_HEIGHT - transformable.size.h(); | ||
253 | |||
254 | break; | ||
255 | } | ||
256 | |||
257 | case Direction::down: | ||
258 | { | ||
259 | warpPos.y() = -WALL_GAP; | ||
260 | |||
261 | break; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | game_.getSystemManager().getSystem<PlayingSystem>(). | ||
266 | changeMap( | ||
267 | entity, | ||
268 | result.adjWarpMapId, | ||
269 | warpPos); | ||
270 | } | ||
280 | } | 271 | } |
281 | 272 | ||
282 | return result; | 273 | return result; |
@@ -506,6 +497,9 @@ void PonderingSystem::detectCollisionsInDirection( | |||
506 | auto& transform = game_.getEntityManager(). | 497 | auto& transform = game_.getEntityManager(). |
507 | getComponent<TransformableComponent>(entity); | 498 | getComponent<TransformableComponent>(entity); |
508 | 499 | ||
500 | auto& ponderable = game_.getEntityManager(). | ||
501 | getComponent<PonderableComponent>(entity); | ||
502 | |||
509 | bool boundaryCollision = false; | 503 | bool boundaryCollision = false; |
510 | 504 | ||
511 | auto boundaries = Param::MapBoundaries(mappable); | 505 | auto boundaries = Param::MapBoundaries(mappable); |
@@ -530,6 +524,26 @@ void PonderingSystem::detectCollisionsInDirection( | |||
530 | } | 524 | } |
531 | } | 525 | } |
532 | 526 | ||
527 | // Find the results of pretending to move the entity's passengers, if there | ||
528 | // are any. | ||
529 | vec2d delta = result.pos - transform.pos; | ||
530 | std::map<id_type, CollisionResult> passResults; | ||
531 | |||
532 | for (id_type passenger : ponderable.passengers) | ||
533 | { | ||
534 | auto& passPonder = game_.getEntityManager(). | ||
535 | getComponent<PonderableComponent>(passenger); | ||
536 | |||
537 | if (passPonder.ferrySide == Param::Dir) | ||
538 | { | ||
539 | auto& passTrans = game_.getEntityManager(). | ||
540 | getComponent<TransformableComponent>(passenger); | ||
541 | |||
542 | passResults[passenger] = | ||
543 | detectCollisions(passenger, passTrans.pos + delta); | ||
544 | } | ||
545 | } | ||
546 | |||
533 | // Find a list of potential colliders, sorted so that the closest is | 547 | // Find a list of potential colliders, sorted so that the closest is |
534 | // first. | 548 | // first. |
535 | std::vector<id_type> colliders; | 549 | std::vector<id_type> colliders; |
@@ -555,33 +569,46 @@ void PonderingSystem::detectCollisionsInDirection( | |||
555 | continue; | 569 | continue; |
556 | } | 570 | } |
557 | 571 | ||
572 | // If the collider is a passenger of the entity, pretend that it has already | ||
573 | // moved. | ||
558 | auto& colliderTrans = game_.getEntityManager(). | 574 | auto& colliderTrans = game_.getEntityManager(). |
559 | getComponent<TransformableComponent>(collider); | 575 | getComponent<TransformableComponent>(collider); |
560 | 576 | ||
577 | vec2d colliderPos = colliderTrans.pos; | ||
578 | vec2i colliderSize = colliderTrans.size; | ||
579 | |||
580 | if (passResults.count(collider)) | ||
581 | { | ||
582 | colliderPos = passResults[collider].pos; | ||
583 | } | ||
584 | |||
561 | // Check if the entity would move into the potential collider, | 585 | // Check if the entity would move into the potential collider, |
562 | if (Param::IsPastAxis( | 586 | if (Param::IsPastAxis( |
563 | Param::ObjectAxis(colliderTrans), | 587 | Param::ObjectAxis(colliderPos, colliderSize), |
564 | Param::EntityAxis(result.pos, transform.size)) && | 588 | Param::EntityAxis(result.pos, transform.size)) && |
565 | // that it wasn't already colliding, | 589 | // that it wasn't already colliding, |
566 | !Param::IsPastAxis( | 590 | !Param::IsPastAxis( |
567 | Param::ObjectAxis(colliderTrans), | 591 | Param::ObjectAxis(colliderPos, colliderSize), |
568 | Param::EntityAxis(transform)) && | 592 | Param::EntityAxis(transform)) && |
569 | // that the position on the non-axis is in range, | 593 | // that the position on the non-axis is in range, |
570 | (Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size) > | 594 | (Param::NonAxisUpper(colliderPos, colliderSize) > |
571 | Param::NonAxisLower(result.pos)) && | 595 | Param::NonAxisLower(result.pos)) && |
572 | (Param::NonAxisLower(colliderTrans.pos) < | 596 | (Param::NonAxisLower(colliderPos) < |
573 | Param::NonAxisUpper(result.pos, transform.size)) && | 597 | Param::NonAxisUpper(result.pos, transform.size)) && |
574 | // and that the collider is not farther away than the environmental | 598 | // and that the collider is not farther away than the environmental |
575 | // boundary. | 599 | // boundary. |
576 | (!boundaryCollision || | 600 | (!boundaryCollision || |
577 | Param::AtLeastInAxisSweep( | 601 | Param::AtLeastInAxisSweep( |
578 | Param::ObjectAxis(colliderTrans), | 602 | Param::ObjectAxis(colliderPos, colliderSize), |
579 | it->first))) | 603 | it->first))) |
580 | { | 604 | { |
581 | colliders.push_back(collider); | 605 | colliders.push_back(collider); |
582 | } | 606 | } |
583 | } | 607 | } |
584 | 608 | ||
609 | // Sort the potential colliders such that the closest to the axis of movement | ||
610 | // is first. When sorting, treat passengers of the entity as having already | ||
611 | // moved. | ||
585 | std::sort( | 612 | std::sort( |
586 | std::begin(colliders), | 613 | std::begin(colliders), |
587 | std::end(colliders), | 614 | std::end(colliders), |
@@ -589,12 +616,26 @@ void PonderingSystem::detectCollisionsInDirection( | |||
589 | auto& leftTrans = game_.getEntityManager(). | 616 | auto& leftTrans = game_.getEntityManager(). |
590 | getComponent<TransformableComponent>(left); | 617 | getComponent<TransformableComponent>(left); |
591 | 618 | ||
619 | vec2d leftPos = leftTrans.pos; | ||
620 | |||
621 | if (passResults.count(left)) | ||
622 | { | ||
623 | leftPos = passResults[left].pos; | ||
624 | } | ||
625 | |||
592 | auto& rightTrans = game_.getEntityManager(). | 626 | auto& rightTrans = game_.getEntityManager(). |
593 | getComponent<TransformableComponent>(right); | 627 | getComponent<TransformableComponent>(right); |
594 | 628 | ||
629 | vec2d rightPos = rightTrans.pos; | ||
630 | |||
631 | if (passResults.count(right)) | ||
632 | { | ||
633 | rightPos = passResults[right].pos; | ||
634 | } | ||
635 | |||
595 | return Param::Closer( | 636 | return Param::Closer( |
596 | Param::ObjectAxis(leftTrans), | 637 | Param::ObjectAxis(leftPos, leftTrans.size), |
597 | Param::ObjectAxis(rightTrans)); | 638 | Param::ObjectAxis(rightPos, rightTrans.size)); |
598 | }); | 639 | }); |
599 | 640 | ||
600 | for (id_type collider : colliders) | 641 | for (id_type collider : colliders) |
@@ -602,14 +643,25 @@ void PonderingSystem::detectCollisionsInDirection( | |||
602 | auto& colliderTrans = game_.getEntityManager(). | 643 | auto& colliderTrans = game_.getEntityManager(). |
603 | getComponent<TransformableComponent>(collider); | 644 | getComponent<TransformableComponent>(collider); |
604 | 645 | ||
646 | // If the collider is a passenger of the entity, pretend that it has already | ||
647 | // moved. | ||
648 | vec2d colliderPos = colliderTrans.pos; | ||
649 | vec2i colliderSize = colliderTrans.size; | ||
650 | |||
651 | if (passResults.count(collider)) | ||
652 | { | ||
653 | colliderPos = passResults[collider].pos; | ||
654 | } | ||
655 | |||
605 | // Check if the entity would still move into the potential collider. | 656 | // Check if the entity would still move into the potential collider. |
606 | if (!Param::IsPastAxis( | 657 | if (!Param::IsPastAxis( |
607 | Param::ObjectAxis(colliderTrans), | 658 | Param::ObjectAxis(colliderPos, colliderSize), |
608 | Param::EntityAxis(result.pos, transform.size))) | 659 | Param::EntityAxis(result.pos, transform.size))) |
609 | { | 660 | { |
610 | break; | 661 | break; |
611 | } | 662 | } |
612 | 663 | ||
664 | // TODO: Check if the entity is moving into one of its passengers. | ||
613 | auto& colliderPonder = game_.getEntityManager(). | 665 | auto& colliderPonder = game_.getEntityManager(). |
614 | getComponent<PonderableComponent>(collider); | 666 | getComponent<PonderableComponent>(collider); |
615 | 667 | ||
@@ -618,9 +670,9 @@ void PonderingSystem::detectCollisionsInDirection( | |||
618 | collider, | 670 | collider, |
619 | Param::Dir, | 671 | Param::Dir, |
620 | colliderPonder.colliderType, | 672 | colliderPonder.colliderType, |
621 | Param::ObjectAxis(colliderTrans), | 673 | Param::ObjectAxis(colliderPos, colliderSize), |
622 | Param::NonAxisLower(colliderTrans.pos), | 674 | Param::NonAxisLower(colliderPos), |
623 | Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size), | 675 | Param::NonAxisUpper(colliderPos, colliderSize), |
624 | result); | 676 | result); |
625 | 677 | ||
626 | if (result.stopProcessing) | 678 | 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: | |||
51 | 51 | ||
52 | void tickBody( | 52 | void tickBody( |
53 | id_type entity, | 53 | id_type entity, |
54 | double dt, | 54 | double dt); |
55 | const std::set<id_type>& entities); | ||
56 | 55 | ||
57 | CollisionResult moveBody( | 56 | CollisionResult moveBody( |
58 | id_type entity, | 57 | id_type entity, |