| 519 | } |
| 520 | |
| 521 | void CCollision::MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, vec2 Elasticity, bool *pGrounded) const |
| 522 | { |
| 523 | // do the move |
| 524 | vec2 Pos = *pInoutPos; |
| 525 | vec2 Vel = *pInoutVel; |
| 526 | |
| 527 | float Distance = length(Vel); |
| 528 | int Max = (int)Distance; |
| 529 | |
| 530 | if(Distance > 0.00001f) |
| 531 | { |
| 532 | float Fraction = 1.0f / (float)(Max + 1); |
| 533 | float ElasticityX = std::clamp(Elasticity.x, -1.0f, 1.0f); |
| 534 | float ElasticityY = std::clamp(Elasticity.y, -1.0f, 1.0f); |
| 535 | |
| 536 | for(int i = 0; i <= Max; i++) |
| 537 | { |
| 538 | // Early break as optimization to stop checking for collisions for |
| 539 | // large distances after the obstacles we have already hit reduced |
| 540 | // our speed to exactly 0. |
| 541 | if(Vel == vec2(0, 0)) |
| 542 | { |
| 543 | break; |
| 544 | } |
| 545 | |
| 546 | vec2 NewPos = Pos + Vel * Fraction; // TODO: this row is not nice |
| 547 | |
| 548 | // Fraction can be very small and thus the calculation has no effect, no |
| 549 | // reason to continue calculating. |
| 550 | if(NewPos == Pos) |
| 551 | { |
| 552 | break; |
| 553 | } |
| 554 | |
| 555 | if(TestBox(vec2(NewPos.x, NewPos.y), Size)) |
| 556 | { |
| 557 | int Hits = 0; |
| 558 | |
| 559 | if(TestBox(vec2(Pos.x, NewPos.y), Size)) |
| 560 | { |
| 561 | if(pGrounded && ElasticityY > 0 && Vel.y > 0) |
| 562 | *pGrounded = true; |
| 563 | NewPos.y = Pos.y; |
| 564 | Vel.y *= -ElasticityY; |
| 565 | Hits++; |
| 566 | } |
| 567 | |
| 568 | if(TestBox(vec2(NewPos.x, Pos.y), Size)) |
| 569 | { |
| 570 | NewPos.x = Pos.x; |
| 571 | Vel.x *= -ElasticityX; |
| 572 | Hits++; |
| 573 | } |
| 574 | |
| 575 | // neither of the tests got a collision. |
| 576 | // this is a real _corner case_! |
| 577 | if(Hits == 0) |
| 578 | { |
no test coverage detected