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.3KB

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