A 2D tile-based sandbox game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PhysicsTrait.cc 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #include "traits/PhysicsTrait.h"
  2. #include "WorldPlane.h"
  3. #include "Win.h"
  4. namespace Swan {
  5. static float epsilon = 0.001;
  6. static void collideX(
  7. PhysicsTrait::Physics &phys, BodyTrait::Body &body,
  8. WorldPlane &plane, const PhysicsTrait::PhysicsProps &props) {
  9. bool collided = false;
  10. for (int y = (int)floor(body.top() + epsilon); y <= (int)floor(body.bottom() - epsilon); ++y) {
  11. int lx = (int)floor(body.left() + epsilon);
  12. Tile &left = plane.getTile({ lx, y });
  13. if (left.isSolid_) {
  14. body.pos.x = (float)lx + 1.0;
  15. collided = true;
  16. break;
  17. }
  18. int rx = (int)floor(body.right() - epsilon);
  19. Tile &right = plane.getTile({ rx, y });
  20. if (right.isSolid_) {
  21. body.pos.x = (float)rx - body.size.x;
  22. collided = true;
  23. break;
  24. }
  25. }
  26. if (collided) {
  27. phys.vel.x *= -props.bounciness;
  28. if (abs(phys.vel.x) < props.mushyness)
  29. phys.vel.x = 0;
  30. }
  31. }
  32. static void collideY(
  33. PhysicsTrait::Physics &phys, BodyTrait::Body &body,
  34. WorldPlane &plane, const PhysicsTrait::PhysicsProps &props) {
  35. bool collided = false;
  36. phys.onGround = false;
  37. for (int x = (int)floor(body.left() + epsilon); x <= (int)floor(body.right() - epsilon); ++x) {
  38. int ty = (int)floor(body.top() + epsilon);
  39. Tile &top = plane.getTile({ x, ty });
  40. if (top.isSolid_) {
  41. body.pos.y = (float)ty + 1.0;
  42. collided = true;
  43. break;
  44. }
  45. int by = (int)floor(body.bottom() - epsilon);
  46. Tile &bottom = plane.getTile({ x, by });
  47. if (bottom.isSolid_) {
  48. body.pos.y = (float)by - body.size.y;
  49. collided = true;
  50. phys.onGround = true;
  51. break;
  52. }
  53. }
  54. if (collided) {
  55. phys.vel.y *= -props.bounciness;
  56. if (abs(phys.vel.y) < props.mushyness)
  57. phys.vel.y = 0;
  58. }
  59. }
  60. void PhysicsTrait::Physics::update(
  61. const Swan::Context &ctx, float dt,
  62. BodyTrait::Body &body, const PhysicsProps &props) {
  63. vel += (force / props.mass) * dt;
  64. force = { 0, 0 };
  65. Vec2 dist = vel * dt;
  66. Vec2 dir = dist.sign();
  67. Vec2 step = dir * 0.4;
  68. // Move in increments of at most 'step', on the X axis
  69. while (abs(dist.x) > abs(step.x)) {
  70. body.pos.x += step.x;
  71. collideX(*this, body, ctx.plane, props);
  72. dist.x -= step.x;
  73. }
  74. body.pos.x += dist.x;
  75. collideX(*this, body, ctx.plane, props);
  76. // Move in increments of at most 'step', on the Y axis
  77. while (abs(dist.y) > abs(step.y)) {
  78. body.pos.y += step.y;
  79. collideY(*this, body, ctx.plane, props);
  80. dist.y -= step.y;
  81. }
  82. body.pos.y += dist.y;
  83. collideY(*this, body, ctx.plane, props);
  84. }
  85. }