summary refs log tree commit diff stats
path: root/src/systems
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-05-04 11:16:02 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-05-09 17:59:13 -0400
commit5b3d87d24b4c2c750d34d1e970254358cba087a4 (patch)
treeb68ca8e65a4026fc355e33e04e7380ec000f7f48 /src/systems
parent83534176373bd05a13db88ffff095f52cca07a21 (diff)
downloadtherapy-5b3d87d24b4c2c750d34d1e970254358cba087a4.tar.gz
therapy-5b3d87d24b4c2c750d34d1e970254358cba087a4.tar.bz2
therapy-5b3d87d24b4c2c750d34d1e970254358cba087a4.zip
Fixed behavior of uncollidable bodies
The collidable flag, previously unused, now correctly disables collision detection when unset. This has the side effect of platforms being able to move through a dying player. It is undecided whether this behavior is wanted.
Diffstat (limited to 'src/systems')
-rw-r--r--src/systems/pondering.cpp880
1 files changed, 443 insertions, 437 deletions
diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 0be3add..f5d3df2 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp
@@ -148,272 +148,275 @@ void PonderingSystem::tickBody(
148 bool oldGrounded = ponderable.grounded; 148 bool oldGrounded = ponderable.grounded;
149 ponderable.grounded = false; 149 ponderable.grounded = false;
150 150
151 // Find horizontal collisions. 151 if (ponderable.collidable)
152 if (result.newX < oldX)
153 { 152 {
154 bool boundaryCollision = false; 153 // Find horizontal collisions.
155 auto it = mappable.leftBoundaries.lower_bound(oldX); 154 if (result.newX < oldX)
156
157 // Find the axis distance of the closest environmental boundary.
158 for (;
159 (it != std::end(mappable.leftBoundaries)) &&
160 (it->first >= result.newX);
161 it++)
162 { 155 {
163 // Check that the boundary is in range for the other axis. 156 bool boundaryCollision = false;
164 if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) 157 auto it = mappable.leftBoundaries.lower_bound(oldX);
158
159 // Find the axis distance of the closest environmental boundary.
160 for (;
161 (it != std::end(mappable.leftBoundaries)) &&
162 (it->first >= result.newX);
163 it++)
165 { 164 {
166 // We have a collision! 165 // Check that the boundary is in range for the other axis.
167 boundaryCollision = true; 166 if ((oldBottom > it->second.lower) && (oldY < it->second.upper))
167 {
168 // We have a collision!
169 boundaryCollision = true;
168 170
169 break; 171 break;
172 }
170 } 173 }
171 }
172 174
173 // Find a list of potential colliders, sorted so that the closest is 175 // Find a list of potential colliders, sorted so that the closest is
174 // first. 176 // first.
175 std::vector<id_type> colliders; 177 std::vector<id_type> colliders;
176 178
177 for (id_type collider : entities) 179 for (id_type collider : entities)
178 {
179 // Can't collide with self.
180 if (collider == entity)
181 { 180 {
182 continue; 181 // Can't collide with self.
183 } 182 if (collider == entity)
183 {
184 continue;
185 }
184 186
185 auto& colliderPonder = game_.getEntityManager(). 187 auto& colliderPonder = game_.getEntityManager().
186 getComponent<PonderableComponent>(collider); 188 getComponent<PonderableComponent>(collider);
187 189
188 // Only check objects that are active. 190 // Only check objects that are active and collidable.
189 if (!colliderPonder.active) 191 if (!colliderPonder.active || !colliderPonder.collidable)
190 { 192 {
191 continue; 193 continue;
192 } 194 }
193 195
194 auto& colliderTrans = game_.getEntityManager(). 196 auto& colliderTrans = game_.getEntityManager().
195 getComponent<TransformableComponent>(collider); 197 getComponent<TransformableComponent>(collider);
196 198
197 // Check if the entity would move into the potential collider, 199 // Check if the entity would move into the potential collider,
198 if ((colliderTrans.x + colliderTrans.w > result.newX) && 200 if ((colliderTrans.x + colliderTrans.w > result.newX) &&
199 // that it wasn't already colliding, 201 // that it wasn't already colliding,
200 (colliderTrans.x + colliderTrans.w <= oldX) && 202 (colliderTrans.x + colliderTrans.w <= oldX) &&
201 // that the position on the other axis is in range, 203 // that the position on the other axis is in range,
202 (colliderTrans.y + colliderTrans.h > oldY) && 204 (colliderTrans.y + colliderTrans.h > oldY) &&
203 (colliderTrans.y < oldBottom) && 205 (colliderTrans.y < oldBottom) &&
204 // and that the collider is not farther away than the environmental 206 // and that the collider is not farther away than the environmental
205 // boundary. 207 // boundary.
206 (!boundaryCollision || 208 (!boundaryCollision ||
207 (colliderTrans.x + colliderTrans.w >= it->first))) 209 (colliderTrans.x + colliderTrans.w >= it->first)))
208 { 210 {
209 colliders.push_back(collider); 211 colliders.push_back(collider);
212 }
210 } 213 }
211 }
212 214
213 std::sort( 215 std::sort(
214 std::begin(colliders), 216 std::begin(colliders),
215 std::end(colliders), 217 std::end(colliders),
216 [&] (id_type left, id_type right) { 218 [&] (id_type left, id_type right) {
217 auto& leftTrans = game_.getEntityManager(). 219 auto& leftTrans = game_.getEntityManager().
218 getComponent<TransformableComponent>(left); 220 getComponent<TransformableComponent>(left);
219 221
220 auto& rightTrans = game_.getEntityManager(). 222 auto& rightTrans = game_.getEntityManager().
221 getComponent<TransformableComponent>(right); 223 getComponent<TransformableComponent>(right);
222 224
223 return (rightTrans.x < leftTrans.x); 225 return (rightTrans.x < leftTrans.x);
224 }); 226 });
225 227
226 for (id_type collider : colliders) 228 for (id_type collider : colliders)
227 {
228 auto& colliderTrans = game_.getEntityManager().
229 getComponent<TransformableComponent>(collider);
230
231 // Check if the entity would still move into the potential collider.
232 if (colliderTrans.x + colliderTrans.w <= result.newX)
233 { 229 {
234 break; 230 auto& colliderTrans = game_.getEntityManager().
235 } 231 getComponent<TransformableComponent>(collider);
236 232
237 auto& colliderPonder = game_.getEntityManager(). 233 // Check if the entity would still move into the potential collider.
238 getComponent<PonderableComponent>(collider); 234 if (colliderTrans.x + colliderTrans.w <= result.newX)
235 {
236 break;
237 }
239 238
240 processCollision( 239 auto& colliderPonder = game_.getEntityManager().
241 entity, 240 getComponent<PonderableComponent>(collider);
242 collider,
243 Direction::left,
244 colliderPonder.colliderType,
245 colliderTrans.x + colliderTrans.w,
246 colliderTrans.y,
247 colliderTrans.y + colliderTrans.h,
248 result);
249
250 if (result.stopProcessing)
251 {
252 break;
253 }
254 }
255 241
256 // If movement hasn't been stopped by an intermediary object, and 242 processCollision(
257 // collision checking hasn't been stopped, process the environmental 243 entity,
258 // boundaries closest to the entity. 244 collider,
259 if (!result.stopProcessing && !result.touchedWall && boundaryCollision) 245 Direction::left,
260 { 246 colliderPonder.colliderType,
261 double boundaryAxis = it->first; 247 colliderTrans.x + colliderTrans.w,
248 colliderTrans.y,
249 colliderTrans.y + colliderTrans.h,
250 result);
262 251
263 for (; 252 if (result.stopProcessing)
264 (it != std::end(mappable.leftBoundaries)) && 253 {
265 (it->first == boundaryAxis); 254 break;
266 it++) 255 }
256 }
257
258 // If movement hasn't been stopped by an intermediary object, and
259 // collision checking hasn't been stopped, process the environmental
260 // boundaries closest to the entity.
261 if (!result.stopProcessing && !result.touchedWall && boundaryCollision)
267 { 262 {
268 if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) 263 double boundaryAxis = it->first;
264
265 for (;
266 (it != std::end(mappable.leftBoundaries)) &&
267 (it->first == boundaryAxis);
268 it++)
269 { 269 {
270 processCollision( 270 if ((oldBottom > it->second.lower) && (oldY < it->second.upper))
271 entity,
272 mapEntity,
273 Direction::left,
274 it->second.type,
275 it->first,
276 it->second.lower,
277 it->second.upper,
278 result);
279
280 if (result.stopProcessing)
281 { 271 {
282 break; 272 processCollision(
273 entity,
274 mapEntity,
275 Direction::left,
276 it->second.type,
277 it->first,
278 it->second.lower,
279 it->second.upper,
280 result);
281
282 if (result.stopProcessing)
283 {
284 break;
285 }
283 } 286 }
284 } 287 }
285 } 288 }
286 } 289 } else if (result.newX > oldX)
287 } else if (result.newX > oldX)
288 {
289 bool boundaryCollision = false;
290 auto it = mappable.rightBoundaries.lower_bound(oldRight);
291
292 // Find the axis distance of the closest environmental boundary.
293 for (;
294 (it != std::end(mappable.rightBoundaries))
295 && (it->first <= (result.newX + transformable.w));
296 it++)
297 { 290 {
298 // Check that the boundary is in range for the other axis. 291 bool boundaryCollision = false;
299 if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) 292 auto it = mappable.rightBoundaries.lower_bound(oldRight);
293
294 // Find the axis distance of the closest environmental boundary.
295 for (;
296 (it != std::end(mappable.rightBoundaries))
297 && (it->first <= (result.newX + transformable.w));
298 it++)
300 { 299 {
301 // We have a collision! 300 // Check that the boundary is in range for the other axis.
302 boundaryCollision = true; 301 if ((oldBottom > it->second.lower) && (oldY < it->second.upper))
302 {
303 // We have a collision!
304 boundaryCollision = true;
303 305
304 break; 306 break;
307 }
305 } 308 }
306 }
307 309
308 // Find a list of potential colliders, sorted so that the closest is 310 // Find a list of potential colliders, sorted so that the closest is
309 // first. 311 // first.
310 std::vector<id_type> colliders; 312 std::vector<id_type> colliders;
311 313
312 for (id_type collider : entities) 314 for (id_type collider : entities)
313 {
314 // Can't collide with self.
315 if (collider == entity)
316 { 315 {
317 continue; 316 // Can't collide with self.
318 } 317 if (collider == entity)
318 {
319 continue;
320 }
319 321
320 auto& colliderPonder = game_.getEntityManager(). 322 auto& colliderPonder = game_.getEntityManager().
321 getComponent<PonderableComponent>(collider); 323 getComponent<PonderableComponent>(collider);
322 324
323 // Only check objects that are active. 325 // Only check objects that are active and collidable.
324 if (!colliderPonder.active) 326 if (!colliderPonder.active || !colliderPonder.collidable)
325 { 327 {
326 continue; 328 continue;
327 } 329 }
328 330
329 auto& colliderTrans = game_.getEntityManager(). 331 auto& colliderTrans = game_.getEntityManager().
330 getComponent<TransformableComponent>(collider); 332 getComponent<TransformableComponent>(collider);
331 333
332 // Check if the entity would move into the potential collider, 334 // Check if the entity would move into the potential collider,
333 if ((colliderTrans.x < result.newX + transformable.w) && 335 if ((colliderTrans.x < result.newX + transformable.w) &&
334 // that it wasn't already colliding, 336 // that it wasn't already colliding,
335 (colliderTrans.x >= oldRight) && 337 (colliderTrans.x >= oldRight) &&
336 // that the position on the other axis is in range, 338 // that the position on the other axis is in range,
337 (colliderTrans.y + colliderTrans.h > oldY) && 339 (colliderTrans.y + colliderTrans.h > oldY) &&
338 (colliderTrans.y < oldBottom) && 340 (colliderTrans.y < oldBottom) &&
339 // and that the collider is not farther away than the environmental 341 // and that the collider is not farther away than the environmental
340 // boundary. 342 // boundary.
341 (!boundaryCollision || (colliderTrans.x <= it->first))) 343 (!boundaryCollision || (colliderTrans.x <= it->first)))
342 { 344 {
343 colliders.push_back(collider); 345 colliders.push_back(collider);
346 }
344 } 347 }
345 }
346
347 std::sort(
348 std::begin(colliders),
349 std::end(colliders),
350 [&] (id_type left, id_type right) {
351 auto& leftTrans = game_.getEntityManager().
352 getComponent<TransformableComponent>(left);
353 348
354 auto& rightTrans = game_.getEntityManager(). 349 std::sort(
355 getComponent<TransformableComponent>(right); 350 std::begin(colliders),
351 std::end(colliders),
352 [&] (id_type left, id_type right) {
353 auto& leftTrans = game_.getEntityManager().
354 getComponent<TransformableComponent>(left);
356 355
357 return (leftTrans.x < rightTrans.x); 356 auto& rightTrans = game_.getEntityManager().
358 }); 357 getComponent<TransformableComponent>(right);
359 358
360 for (id_type collider : colliders) 359 return (leftTrans.x < rightTrans.x);
361 { 360 });
362 auto& colliderTrans = game_.getEntityManager().
363 getComponent<TransformableComponent>(collider);
364 361
365 // Check if the entity would still move into the potential collider. 362 for (id_type collider : colliders)
366 if (colliderTrans.x >= result.newX + transformable.w)
367 { 363 {
368 break; 364 auto& colliderTrans = game_.getEntityManager().
369 } 365 getComponent<TransformableComponent>(collider);
370 366
371 auto& colliderPonder = game_.getEntityManager(). 367 // Check if the entity would still move into the potential collider.
372 getComponent<PonderableComponent>(collider); 368 if (colliderTrans.x >= result.newX + transformable.w)
369 {
370 break;
371 }
373 372
374 processCollision( 373 auto& colliderPonder = game_.getEntityManager().
375 entity, 374 getComponent<PonderableComponent>(collider);
376 collider,
377 Direction::right,
378 colliderPonder.colliderType,
379 colliderTrans.x,
380 colliderTrans.y,
381 colliderTrans.y + colliderTrans.h,
382 result);
383
384 if (result.stopProcessing)
385 {
386 break;
387 }
388 }
389 375
390 // If movement hasn't been stopped by an intermediary object, and 376 processCollision(
391 // collision checking hasn't been stopped, process the environmental 377 entity,
392 // boundaries closest to the entity. 378 collider,
393 if (!result.stopProcessing && !result.touchedWall && boundaryCollision) 379 Direction::right,
394 { 380 colliderPonder.colliderType,
395 double boundaryAxis = it->first; 381 colliderTrans.x,
382 colliderTrans.y,
383 colliderTrans.y + colliderTrans.h,
384 result);
396 385
397 for (; 386 if (result.stopProcessing)
398 (it != std::end(mappable.rightBoundaries)) && 387 {
399 (it->first == boundaryAxis); 388 break;
400 it++) 389 }
390 }
391
392 // If movement hasn't been stopped by an intermediary object, and
393 // collision checking hasn't been stopped, process the environmental
394 // boundaries closest to the entity.
395 if (!result.stopProcessing && !result.touchedWall && boundaryCollision)
401 { 396 {
402 if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) 397 double boundaryAxis = it->first;
398
399 for (;
400 (it != std::end(mappable.rightBoundaries)) &&
401 (it->first == boundaryAxis);
402 it++)
403 { 403 {
404 processCollision( 404 if ((oldBottom > it->second.lower) && (oldY < it->second.upper))
405 entity,
406 mapEntity,
407 Direction::right,
408 it->second.type,
409 it->first,
410 it->second.lower,
411 it->second.upper,
412 result);
413
414 if (result.stopProcessing)
415 { 405 {
416 break; 406 processCollision(
407 entity,
408 mapEntity,
409 Direction::right,
410 it->second.type,
411 it->first,
412 it->second.lower,
413 it->second.upper,
414 result);
415
416 if (result.stopProcessing)
417 {
418 break;
419 }
417 } 420 }
418 } 421 }
419 } 422 }
@@ -421,277 +424,280 @@ void PonderingSystem::tickBody(
421 } 424 }
422 425
423 // Find vertical collisions 426 // Find vertical collisions
424 result.touchedWall = false; 427 if (ponderable.collidable && !result.stopProcessing)
425
426 if ((!result.stopProcessing) && (result.newY < oldY))
427 { 428 {
428 bool boundaryCollision = false; 429 result.touchedWall = false;
429 auto it = mappable.upBoundaries.lower_bound(oldY); 430
430 431 if (result.newY < oldY)
431 // Find the axis distance of the closest environmental boundary.
432 for (;
433 (it != std::end(mappable.upBoundaries)) &&
434 (it->first >= result.newY);
435 it++)
436 { 432 {
437 // Check that the boundary is in range for the other axis. 433 bool boundaryCollision = false;
438 if ((result.newX + transformable.h > it->second.lower) && 434 auto it = mappable.upBoundaries.lower_bound(oldY);
439 (result.newX < it->second.upper)) 435
436 // Find the axis distance of the closest environmental boundary.
437 for (;
438 (it != std::end(mappable.upBoundaries)) &&
439 (it->first >= result.newY);
440 it++)
440 { 441 {
441 // We have a collision! 442 // Check that the boundary is in range for the other axis.
442 boundaryCollision = true; 443 if ((result.newX + transformable.h > it->second.lower) &&
444 (result.newX < it->second.upper))
445 {
446 // We have a collision!
447 boundaryCollision = true;
443 448
444 break; 449 break;
450 }
445 } 451 }
446 }
447 452
448 // Find a list of potential colliders, sorted so that the closest is 453 // Find a list of potential colliders, sorted so that the closest is
449 // first. 454 // first.
450 std::vector<id_type> colliders; 455 std::vector<id_type> colliders;
451 456
452 for (id_type collider : entities) 457 for (id_type collider : entities)
453 {
454 // Can't collide with self.
455 if (collider == entity)
456 { 458 {
457 continue; 459 // Can't collide with self.
458 } 460 if (collider == entity)
461 {
462 continue;
463 }
459 464
460 auto& colliderPonder = game_.getEntityManager(). 465 auto& colliderPonder = game_.getEntityManager().
461 getComponent<PonderableComponent>(collider); 466 getComponent<PonderableComponent>(collider);
462 467
463 // Only check objects that are active. 468 // Only check objects that are active and collidable.
464 if (!colliderPonder.active) 469 if (!colliderPonder.active || !colliderPonder.collidable)
465 { 470 {
466 continue; 471 continue;
467 } 472 }
468 473
469 auto& colliderTrans = game_.getEntityManager(). 474 auto& colliderTrans = game_.getEntityManager().
470 getComponent<TransformableComponent>(collider); 475 getComponent<TransformableComponent>(collider);
471 476
472 // Check if the entity would move into the potential collider, 477 // Check if the entity would move into the potential collider,
473 if ((colliderTrans.y + colliderTrans.h > result.newY) && 478 if ((colliderTrans.y + colliderTrans.h > result.newY) &&
474 // that it wasn't already colliding, 479 // that it wasn't already colliding,
475 (colliderTrans.y + colliderTrans.h <= oldY) && 480 (colliderTrans.y + colliderTrans.h <= oldY) &&
476 // that the position on the other axis is in range, 481 // that the position on the other axis is in range,
477 (colliderTrans.x + colliderTrans.w > result.newX) && 482 (colliderTrans.x + colliderTrans.w > result.newX) &&
478 (colliderTrans.x < result.newX + transformable.w) && 483 (colliderTrans.x < result.newX + transformable.w) &&
479 // and that the collider is not farther away than the environmental 484 // and that the collider is not farther away than the environmental
480 // boundary. 485 // boundary.
481 (!boundaryCollision || 486 (!boundaryCollision ||
482 (colliderTrans.y + colliderTrans.h >= it->first))) 487 (colliderTrans.y + colliderTrans.h >= it->first)))
483 { 488 {
484 colliders.push_back(collider); 489 colliders.push_back(collider);
490 }
485 } 491 }
486 }
487
488 std::sort(
489 std::begin(colliders),
490 std::end(colliders),
491 [&] (id_type left, id_type right) {
492 auto& leftTrans = game_.getEntityManager().
493 getComponent<TransformableComponent>(left);
494 492
495 auto& rightTrans = game_.getEntityManager(). 493 std::sort(
496 getComponent<TransformableComponent>(right); 494 std::begin(colliders),
495 std::end(colliders),
496 [&] (id_type left, id_type right) {
497 auto& leftTrans = game_.getEntityManager().
498 getComponent<TransformableComponent>(left);
497 499
498 return (rightTrans.y < leftTrans.y); 500 auto& rightTrans = game_.getEntityManager().
499 }); 501 getComponent<TransformableComponent>(right);
500 502
501 for (id_type collider : colliders) 503 return (rightTrans.y < leftTrans.y);
502 { 504 });
503 auto& colliderTrans = game_.getEntityManager().
504 getComponent<TransformableComponent>(collider);
505 505
506 // Check if the entity would still move into the potential collider. 506 for (id_type collider : colliders)
507 if (colliderTrans.y + colliderTrans.h <= result.newY)
508 { 507 {
509 break; 508 auto& colliderTrans = game_.getEntityManager().
510 } 509 getComponent<TransformableComponent>(collider);
511 510
512 auto& colliderPonder = game_.getEntityManager(). 511 // Check if the entity would still move into the potential collider.
513 getComponent<PonderableComponent>(collider); 512 if (colliderTrans.y + colliderTrans.h <= result.newY)
513 {
514 break;
515 }
514 516
515 processCollision( 517 auto& colliderPonder = game_.getEntityManager().
516 entity, 518 getComponent<PonderableComponent>(collider);
517 collider,
518 Direction::up,
519 colliderPonder.colliderType,
520 colliderTrans.y + colliderTrans.h,
521 colliderTrans.x,
522 colliderTrans.x + colliderTrans.w,
523 result);
524
525 if (result.stopProcessing)
526 {
527 break;
528 }
529 }
530 519
531 // If movement hasn't been stopped by an intermediary object, and 520 processCollision(
532 // collision checking hasn't been stopped, process the environmental 521 entity,
533 // boundaries closest to the entity. 522 collider,
534 if (!result.stopProcessing && !result.touchedWall && boundaryCollision) 523 Direction::up,
535 { 524 colliderPonder.colliderType,
536 double boundaryAxis = it->first; 525 colliderTrans.y + colliderTrans.h,
526 colliderTrans.x,
527 colliderTrans.x + colliderTrans.w,
528 result);
537 529
538 for (; 530 if (result.stopProcessing)
539 (it != std::end(mappable.upBoundaries)) && 531 {
540 (it->first == boundaryAxis); 532 break;
541 it++) 533 }
534 }
535
536 // If movement hasn't been stopped by an intermediary object, and
537 // collision checking hasn't been stopped, process the environmental
538 // boundaries closest to the entity.
539 if (!result.stopProcessing && !result.touchedWall && boundaryCollision)
542 { 540 {
543 if ((result.newX + transformable.w > it->second.lower) && 541 double boundaryAxis = it->first;
544 (result.newX < it->second.upper)) 542
543 for (;
544 (it != std::end(mappable.upBoundaries)) &&
545 (it->first == boundaryAxis);
546 it++)
545 { 547 {
546 processCollision( 548 if ((result.newX + transformable.w > it->second.lower) &&
547 entity, 549 (result.newX < it->second.upper))
548 mapEntity,
549 Direction::up,
550 it->second.type,
551 it->first,
552 it->second.lower,
553 it->second.upper,
554 result);
555
556 if (result.stopProcessing)
557 { 550 {
558 break; 551 processCollision(
552 entity,
553 mapEntity,
554 Direction::up,
555 it->second.type,
556 it->first,
557 it->second.lower,
558 it->second.upper,
559 result);
560
561 if (result.stopProcessing)
562 {
563 break;
564 }
559 } 565 }
560 } 566 }
561 } 567 }
562 } 568 } else if (result.newY > oldY)
563 } else if ((!result.stopProcessing) && (result.newY > oldY))
564 {
565 bool boundaryCollision = false;
566 auto it = mappable.downBoundaries.lower_bound(oldBottom);
567
568 // Find the axis distance of the closest environmental boundary.
569 for (;
570 (it != std::end(mappable.downBoundaries))
571 && (it->first <= (result.newY + transformable.h));
572 it++)
573 { 569 {
574 // Check that the boundary is in range for the other axis. 570 bool boundaryCollision = false;
575 if ((result.newX + transformable.w > it->second.lower) && 571 auto it = mappable.downBoundaries.lower_bound(oldBottom);
576 (result.newX < it->second.upper)) 572
573 // Find the axis distance of the closest environmental boundary.
574 for (;
575 (it != std::end(mappable.downBoundaries))
576 && (it->first <= (result.newY + transformable.h));
577 it++)
577 { 578 {
578 // We have a collision! 579 // Check that the boundary is in range for the other axis.
579 boundaryCollision = true; 580 if ((result.newX + transformable.w > it->second.lower) &&
581 (result.newX < it->second.upper))
582 {
583 // We have a collision!
584 boundaryCollision = true;
580 585
581 break; 586 break;
587 }
582 } 588 }
583 }
584 589
585 // Find a list of potential colliders, sorted so that the closest is 590 // Find a list of potential colliders, sorted so that the closest is
586 // first. 591 // first.
587 std::vector<id_type> colliders; 592 std::vector<id_type> colliders;
588 593
589 for (id_type collider : entities) 594 for (id_type collider : entities)
590 {
591 // Can't collide with self.
592 if (collider == entity)
593 { 595 {
594 continue; 596 // Can't collide with self.
595 } 597 if (collider == entity)
598 {
599 continue;
600 }
596 601
597 auto& colliderPonder = game_.getEntityManager(). 602 auto& colliderPonder = game_.getEntityManager().
598 getComponent<PonderableComponent>(collider); 603 getComponent<PonderableComponent>(collider);
599 604
600 // Only check objects that are active. 605 // Only check objects that are active and collidable.
601 if (!colliderPonder.active) 606 if (!colliderPonder.active || !colliderPonder.collidable)
602 { 607 {
603 continue; 608 continue;
604 } 609 }
605 610
606 auto& colliderTrans = game_.getEntityManager(). 611 auto& colliderTrans = game_.getEntityManager().
607 getComponent<TransformableComponent>(collider); 612 getComponent<TransformableComponent>(collider);
608 613
609 // Check if the entity would move into the potential collider, 614 // Check if the entity would move into the potential collider,
610 if ((colliderTrans.y < result.newY + transformable.h) && 615 if ((colliderTrans.y < result.newY + transformable.h) &&
611 // that it wasn't already colliding, 616 // that it wasn't already colliding,
612 (colliderTrans.y >= oldBottom) && 617 (colliderTrans.y >= oldBottom) &&
613 // that the position on the other axis is in range, 618 // that the position on the other axis is in range,
614 (colliderTrans.x + colliderTrans.w > result.newX) && 619 (colliderTrans.x + colliderTrans.w > result.newX) &&
615 (colliderTrans.x < result.newX + transformable.w) && 620 (colliderTrans.x < result.newX + transformable.w) &&
616 // and that the collider is not farther away than the environmental 621 // and that the collider is not farther away than the environmental
617 // boundary. 622 // boundary.
618 (!boundaryCollision || (colliderTrans.y <= it->first))) 623 (!boundaryCollision || (colliderTrans.y <= it->first)))
619 { 624 {
620 colliders.push_back(collider); 625 colliders.push_back(collider);
626 }
621 } 627 }
622 }
623
624 std::sort(
625 std::begin(colliders),
626 std::end(colliders),
627 [&] (id_type left, id_type right) {
628 auto& leftTrans = game_.getEntityManager().
629 getComponent<TransformableComponent>(left);
630 628
631 auto& rightTrans = game_.getEntityManager(). 629 std::sort(
632 getComponent<TransformableComponent>(right); 630 std::begin(colliders),
631 std::end(colliders),
632 [&] (id_type left, id_type right) {
633 auto& leftTrans = game_.getEntityManager().
634 getComponent<TransformableComponent>(left);
633 635
634 return (leftTrans.y < rightTrans.y); 636 auto& rightTrans = game_.getEntityManager().
635 }); 637 getComponent<TransformableComponent>(right);
636 638
637 for (id_type collider : colliders) 639 return (leftTrans.y < rightTrans.y);
638 { 640 });
639 auto& colliderTrans = game_.getEntityManager().
640 getComponent<TransformableComponent>(collider);
641 641
642 // Check if the entity would still move into the potential collider. 642 for (id_type collider : colliders)
643 if (colliderTrans.y >= result.newY + transformable.h)
644 { 643 {
645 break; 644 auto& colliderTrans = game_.getEntityManager().
646 } 645 getComponent<TransformableComponent>(collider);
647 646
648 auto& colliderPonder = game_.getEntityManager(). 647 // Check if the entity would still move into the potential collider.
649 getComponent<PonderableComponent>(collider); 648 if (colliderTrans.y >= result.newY + transformable.h)
649 {
650 break;
651 }
650 652
651 processCollision( 653 auto& colliderPonder = game_.getEntityManager().
652 entity, 654 getComponent<PonderableComponent>(collider);
653 collider,
654 Direction::down,
655 colliderPonder.colliderType,
656 colliderTrans.y,
657 colliderTrans.x,
658 colliderTrans.x + colliderTrans.w,
659 result);
660
661 if (result.stopProcessing)
662 {
663 break;
664 }
665 }
666 655
667 // If movement hasn't been stopped by an intermediary object, and 656 processCollision(
668 // collision checking hasn't been stopped, process the environmental 657 entity,
669 // boundaries closest to the entity. 658 collider,
670 if (!result.stopProcessing && !result.touchedWall && boundaryCollision) 659 Direction::down,
671 { 660 colliderPonder.colliderType,
672 double boundaryAxis = it->first; 661 colliderTrans.y,
662 colliderTrans.x,
663 colliderTrans.x + colliderTrans.w,
664 result);
673 665
674 for (; 666 if (result.stopProcessing)
675 (it != std::end(mappable.downBoundaries)) && 667 {
676 (it->first == boundaryAxis); 668 break;
677 it++) 669 }
670 }
671
672 // If movement hasn't been stopped by an intermediary object, and
673 // collision checking hasn't been stopped, process the environmental
674 // boundaries closest to the entity.
675 if (!result.stopProcessing && !result.touchedWall && boundaryCollision)
678 { 676 {
679 if ((result.newX + transformable.w > it->second.lower) && 677 double boundaryAxis = it->first;
680 (result.newX < it->second.upper)) 678
679 for (;
680 (it != std::end(mappable.downBoundaries)) &&
681 (it->first == boundaryAxis);
682 it++)
681 { 683 {
682 processCollision( 684 if ((result.newX + transformable.w > it->second.lower) &&
683 entity, 685 (result.newX < it->second.upper))
684 mapEntity,
685 Direction::down,
686 it->second.type,
687 it->first,
688 it->second.lower,
689 it->second.upper,
690 result);
691
692 if (result.stopProcessing)
693 { 686 {
694 break; 687 processCollision(
688 entity,
689 mapEntity,
690 Direction::down,
691 it->second.type,
692 it->first,
693 it->second.lower,
694 it->second.upper,
695 result);
696
697 if (result.stopProcessing)
698 {
699 break;
700 }
695 } 701 }
696 } 702 }
697 } 703 }