Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2017
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.51 KB | None | 0 0
  1. (function(exports) {
  2.  
  3. // Vector Class -----------------------------------------------------------
  4. // ------------------------------------------------------------------------
  5. function Vector2(x, y) {
  6. this.x = x;
  7. this.y = y;
  8. }
  9.  
  10. Vector2.prototype = {
  11.  
  12. add: function(v) {
  13. return new Vector2(this.x + v.x, this.y + v.y);
  14. },
  15.  
  16. sub: function(v) {
  17. return new Vector2(this.x - v.x, this.y - v.y);
  18. },
  19.  
  20. dot: function(v) {
  21. return this.x * v.x + this.y * v.y;
  22. },
  23.  
  24. cross: function(v) {
  25. return this.x * v.y - this.y * v.x;
  26. },
  27.  
  28. div: function(s) {
  29. this.x /= s;
  30. this.y /= s;
  31. return this;
  32. },
  33.  
  34. mul: function(s) {
  35. this.x *= s;
  36. this.y *= s;
  37. return this;
  38. },
  39.  
  40. normalize: function() {
  41.  
  42. var len = this.length();
  43. if (this.length > 0.0001) {
  44. var invLen = 1.0 / len;
  45. this.x *= invLen;
  46. this.y *= invLen;
  47. }
  48.  
  49. },
  50.  
  51. // Length
  52. lengthSqr: function() {
  53. return this.x * this.x + this.y * this.y;
  54. },
  55.  
  56. length: function() {
  57. return Math.sqrt(this.x * this.x + this.y * this.y);
  58. }
  59.  
  60. };
  61.  
  62.  
  63. // AABB implementation ----------------------------------------------------
  64. // ------------------------------------------------------------------------
  65. function AABB(x, y, w, h, mass) {
  66.  
  67. mass = mass !== undefined ? mass : 0;
  68.  
  69. // Properties
  70. this.id = ++AABB.id;
  71.  
  72. // The is actually the inverse mass.
  73. // The value 0 is used as a placeholder for infinite mass
  74. this.im = mass === 0 ? 0 : 1 / mass;
  75.  
  76. // How "bouncy" this box is. The higher the value, the more the box will
  77. // bounce of in case of a collision
  78. this.restitution = 0.1;
  79.  
  80. this.staticFriction = 1;
  81. this.dynamicFriction = 0.3;
  82.  
  83. this.position = new Vector2(x, y);
  84. this.velocity = new Vector2(0, 0);
  85. this.size = new Vector2(w, h);
  86.  
  87. // Internal, temporary values only used during the collision phase
  88. this.force = new Vector2(0, 0);
  89. this.min = new Vector2(0, 0);
  90. this.max = new Vector2(0, 0);
  91.  
  92. }
  93.  
  94. AABB.prototype = {
  95.  
  96. /**
  97. * Quick check to see if all of the axis of two AABBs are overlapping.
  98. */
  99. isOverlapping: function(other) {
  100. if (this.max.x < other.min.x || this.min.x > other.max.x) {
  101. return false;
  102.  
  103. } else if (this.max.y < other.min.y || this.min.y > other.max.y) {
  104. return false;
  105.  
  106. } else {
  107. return true;
  108. }
  109. },
  110.  
  111. /**
  112. * Update the boundaries of the AABB
  113. */
  114. updateBounds: function() {
  115. this.min.x = this.position.x - this.size.x;
  116. this.max.x = this.position.x + this.size.x;
  117. this.min.y = this.position.y - this.size.y;
  118. this.max.y = this.position.y + this.size.y;
  119. },
  120.  
  121. /**
  122. * Integrate force and gravity into the AABB's velocity.
  123. */
  124. integrateForces: function(gravity) {
  125. if (this.im !== 0) {
  126. this.velocity.x += (this.force.x * this.im + gravity.x) / 2;
  127. this.velocity.y += (this.force.y * this.im + gravity.y) / 2;
  128. }
  129. },
  130.  
  131. /**
  132. * Integrate the velocity into the AABB's position.
  133. */
  134. integrateVelocity: function(gravity) {
  135. if (this.im !== 0) {
  136. this.position.x += this.velocity.x;
  137. this.position.y += this.velocity.y;
  138. this.integrateForces(gravity);
  139. }
  140. },
  141.  
  142. applyImpulse: function(x, y) {
  143. this.velocity.x += this.im * x;
  144. this.velocity.y += this.im * y;
  145. },
  146.  
  147. applyForce: function(x, y) {
  148. this.force.x += x;
  149. this.force.y += y;
  150. },
  151.  
  152. clearForces: function() {
  153. this.force.x = 0;
  154. this.force.y = 0;
  155. }
  156.  
  157. };
  158.  
  159.  
  160. // Manifold which contains information about a single collision -----------
  161. // ------------------------------------------------------------------------
  162. function Manifold(a, b) {
  163.  
  164. this.a = a;
  165. this.b = b;
  166. this.e = Math.min(a.restitution, b.restitution);
  167. this.sf = 0;
  168. this.df = 0;
  169.  
  170. this.normal = new Vector2(0, 0);
  171. this.penetration = 0;
  172.  
  173. }
  174.  
  175. Manifold.prototype = {
  176.  
  177. /**
  178. * Initialize the manifold for the collision phase.
  179. */
  180. init: function(gravity, epsilon) {
  181.  
  182. // TODO is this correct?
  183. this.sf = Math.sqrt(this.a.staticFriction * this.b.staticFriction);
  184. this.df = Math.sqrt(this.a.dynamicFriction * this.b.dynamicFriction);
  185.  
  186. // Figure out whether this is a resting collision, if so do not apply
  187. // any restitution
  188. var rx = this.b.velocity.x - this.a.velocity.x,
  189. ry = this.b.velocity.y - this.a.velocity.y;
  190.  
  191. if ((rx * rx + ry * ry) < (gravity.x * gravity.x + gravity.y * gravity.y) + epsilon) {
  192. this.e = 0.0;
  193. }
  194.  
  195. },
  196.  
  197. /**
  198. * Solve the SAT for two AABBs
  199. */
  200. solve: function() {
  201.  
  202. // Vector from A to B
  203. var nx = this.a.position.x - this.b.position.x,
  204. ny = this.a.position.y - this.b.position.y;
  205.  
  206. // Calculate half extends along x axis
  207. var aex = (this.a.max.x - this.a.min.x) / 2,
  208. bex = (this.b.max.x - this.b.min.x) / 2;
  209.  
  210. // Overlap on x axis
  211. var xoverlap = aex + bex - Math.abs(nx);
  212. if (xoverlap > 0) {
  213.  
  214. // Calculate half extends along y axis
  215. var aey = (this.a.max.y - this.a.min.y) / 2,
  216. bey = (this.b.max.y - this.b.min.y) / 2;
  217.  
  218. // Overlap on x axis
  219. var yoverlap = aey + bey - Math.abs(ny);
  220. if (yoverlap) {
  221.  
  222. // Find out which axis is the axis of least penetration
  223. if (xoverlap < yoverlap) {
  224.  
  225. // Point towards B knowing that n points from A to B
  226. this.normal.x = nx < 0 ? 1 : -1;
  227. this.normal.y = 0;
  228. this.penetration = xoverlap;
  229. return true;
  230.  
  231. } else {
  232.  
  233. // Point towards B knowing that n points from A to B
  234. this.normal.x = 0;
  235. this.normal.y = ny < 0 ? 1 : -1;
  236. this.penetration = yoverlap;
  237. return true;
  238.  
  239. }
  240.  
  241. }
  242.  
  243. }
  244.  
  245. return false;
  246.  
  247. },
  248.  
  249. /**
  250. * Resolves a collision by applying a impulse to each of the AABB's
  251. * involved.
  252. */
  253. resolve: function(epsilon) {
  254.  
  255. var a = this.a,
  256. b = this.b,
  257.  
  258. // Relative velocity from a to b
  259. rx = b.velocity.x - a.velocity.x,
  260. ry = b.velocity.y - a.velocity.y,
  261. velAlongNormal = rx * this.normal.x + ry * this.normal.y;
  262.  
  263. // If the velocities are separating do nothing
  264. if (velAlongNormal > 0 ) {
  265. return;
  266.  
  267. } else {
  268.  
  269. // Correct penetration
  270. var j = -(1.0 + this.e) * velAlongNormal;
  271. j /= (a.im + b.im);
  272.  
  273. // Apply the impulse each box gets a impulse based on its mass
  274. // ratio
  275. a.applyImpulse(-j * this.normal.x, -j * this.normal.y);
  276. b.applyImpulse(j * this.normal.x, j * this.normal.y);
  277.  
  278. // Apply Friction
  279. var tx = rx - (this.normal.x * velAlongNormal),
  280. ty = ry - (this.normal.y * velAlongNormal),
  281. tl = Math.sqrt(tx * tx + ty * ty);
  282.  
  283. if (tl > epsilon) {
  284. tx /= tl;
  285. ty /= tl;
  286. }
  287.  
  288. var jt = -(rx * tx + ry * ty);
  289. jt /= (a.im + b.im);
  290.  
  291. // Don't apply tiny friction impulses
  292. if (Math.abs(jt) < epsilon) {
  293. return;
  294. }
  295.  
  296. if (Math.abs(jt) < j * this.sf) {
  297. tx = tx * jt;
  298. ty = ty * jt;
  299.  
  300. } else {
  301. tx = tx * -j * this.df;
  302. ty = ty * -j * this.df;
  303. }
  304.  
  305. a.applyImpulse(-tx, -ty);
  306. b.applyImpulse(tx, ty);
  307.  
  308. }
  309.  
  310. },
  311.  
  312. /**
  313. * This will prevent objects from sinking into each other when they're
  314. * resting.
  315. */
  316. positionalCorrection: function() {
  317.  
  318. var a = this.a,
  319. b = this.b;
  320.  
  321. var percent = 0.7,
  322. slop = 0.05,
  323. m = Math.max(this.penetration - slop, 0.0) / (a.im + b.im);
  324.  
  325. // Apply correctional impulse
  326. var cx = m * this.normal.x * percent,
  327. cy = m * this.normal.y * percent;
  328.  
  329. a.position.x -= cx * a.im;
  330. a.position.y -= cy * a.im;
  331.  
  332. b.position.x += cx * b.im;
  333. b.position.y += cy * b.im;
  334.  
  335. }
  336.  
  337. };
  338.  
  339.  
  340. // AABB collision engine --------------------------------------------------
  341. // ------------------------------------------------------------------------
  342. function Engine() {
  343. this.iterations = 10;
  344. this.gravity = new Vector2(0, 1);
  345. this.contacts = [];
  346. this.boxes = [];
  347. this.length = 0;
  348. }
  349.  
  350. Engine.EPSILON = 0.0001;
  351.  
  352. Engine.prototype = {
  353.  
  354. findCollisions: function() {
  355.  
  356. this.contacts.length = 0;
  357.  
  358. for(var i = 0; i < this.length; i++) {
  359.  
  360. var a = this.boxes[i];
  361. for(var j = i + 1; j < this.length; j++) {
  362.  
  363. var b = this.boxes[j];
  364.  
  365. // Ignore collisions between objects with infinite mass
  366. if (a.im === 0 && b.im === 0) {
  367. continue;
  368.  
  369. } else if (a.isOverlapping(b)) {
  370. var c = new Manifold(a, b);
  371. if (c.solve()) {
  372. this.contacts.push(c);
  373. }
  374. }
  375.  
  376. }
  377.  
  378. }
  379.  
  380. },
  381.  
  382. integrateForces: function() {
  383. for(var i = 0; i < this.length; i++) {
  384. this.boxes[i].integrateForces(this.gravity);
  385. }
  386. },
  387.  
  388. initializeCollisions: function() {
  389. for(var i = 0, l = this.contacts.length; i < l; i++) {
  390. this.contacts[i].init(this.gravity, Engine.EPSILON);
  391. }
  392. },
  393.  
  394. solveCollisions: function() {
  395. for(var i = 0; i < this.iterations; i++) {
  396. for(var c = 0, l = this.contacts.length; c < l; c++) {
  397. this.contacts[c].resolve(Engine.EPSILON);
  398. }
  399. }
  400. },
  401.  
  402. integrateVelocities: function() {
  403. for(var i = 0; i < this.length; i++) {
  404. this.boxes[i].integrateVelocity(this.gravity);
  405. this.boxes[i].clearForces();
  406. this.boxes[i].updateBounds();
  407. }
  408. },
  409.  
  410. correctPositions: function() {
  411. for(var i = 0, l = this.contacts.length; i < l; i++) {
  412. this.contacts[i].positionalCorrection();
  413. }
  414. },
  415.  
  416. tick: function() {
  417. this.findCollisions();
  418. this.integrateForces();
  419. this.initializeCollisions();
  420. this.solveCollisions();
  421. this.integrateVelocities();
  422. this.correctPositions();
  423. },
  424.  
  425. addBox: function(box) {
  426. this.boxes.push(box);
  427. this.length++;
  428. }
  429.  
  430. };
  431.  
  432. exports.Engine = Engine;
  433. exports.Vector2 = Vector2;
  434. exports.Box = AABB;
  435.  
  436. })(typeof module === 'undefined' ? window : module.exports);
  437.  
  438.  
  439. var box = exports;
  440.  
  441. var ground = new box.Box(0, 20, 100, 10);
  442. //ground.restitution = 1;
  443. var object = new box.Box(0, -20, 10, 10, 1);
  444. //var two = new box.Box(20, -40, 10, 10, 1);
  445. //two.restitution = 0.1;
  446.  
  447. var w = new box.Engine();
  448. w.addBox(ground);
  449. w.addBox(object);
  450. //w.addBox(two);
  451.  
  452. //object.applyImpulse(4, 0);
  453.  
  454. setInterval(function() {
  455. //object.applyForce(0.5, 0);
  456. w.tick();
  457. console.log(Math.round(object.position.x), object.position.y);
  458.  
  459. }, 33);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement