PageRenderTime 143ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 3ms

/build/custom/p2.js

https://gitlab.com/lobsterhands/phaser
JavaScript | 15953 lines | 7431 code | 2586 blank | 5936 comment | 1094 complexity | f2ea851513870425f256ccc343e406c5 MD5 | raw file
  1. /**
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2013 p2.js authors
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define('p2', (function() { return this.p2 = e(); })()):"undefined"!=typeof window?window.p2=e():"undefined"!=typeof global?self.p2=e():"undefined"!=typeof self&&(self.p2=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  25. /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
  26. Redistribution and use in source and binary forms, with or without modification,
  27. are permitted provided that the following conditions are met:
  28. * Redistributions of source code must retain the above copyright notice, this
  29. list of conditions and the following disclaimer.
  30. * Redistributions in binary form must reproduce the above copyright notice,
  31. this list of conditions and the following disclaimer in the documentation
  32. and/or other materials provided with the distribution.
  33. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  34. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  35. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  36. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  37. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  38. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  39. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  40. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  41. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  42. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  43. if(!GLMAT_EPSILON) {
  44. var GLMAT_EPSILON = 0.000001;
  45. }
  46. if(!GLMAT_ARRAY_TYPE) {
  47. var GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
  48. }
  49. /**
  50. * @class Common utilities
  51. * @name glMatrix
  52. */
  53. var glMatrix = {};
  54. /**
  55. * Sets the type of array used when creating new vectors and matricies
  56. *
  57. * @param {Type} type Array type, such as Float32Array or Array
  58. */
  59. glMatrix.setMatrixArrayType = function(type) {
  60. GLMAT_ARRAY_TYPE = type;
  61. }
  62. if(typeof(exports) !== 'undefined') {
  63. exports.glMatrix = glMatrix;
  64. }
  65. /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
  66. Redistribution and use in source and binary forms, with or without modification,
  67. are permitted provided that the following conditions are met:
  68. * Redistributions of source code must retain the above copyright notice, this
  69. list of conditions and the following disclaimer.
  70. * Redistributions in binary form must reproduce the above copyright notice,
  71. this list of conditions and the following disclaimer in the documentation
  72. and/or other materials provided with the distribution.
  73. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  74. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  75. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  76. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  77. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  78. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  79. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  80. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  81. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  82. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  83. /**
  84. * @class 2 Dimensional Vector
  85. * @name vec2
  86. */
  87. var vec2 = {};
  88. /**
  89. * Creates a new, empty vec2
  90. *
  91. * @returns {vec2} a new 2D vector
  92. */
  93. vec2.create = function() {
  94. var out = new GLMAT_ARRAY_TYPE(2);
  95. out[0] = 0;
  96. out[1] = 0;
  97. return out;
  98. };
  99. /**
  100. * Creates a new vec2 initialized with values from an existing vector
  101. *
  102. * @param {vec2} a vector to clone
  103. * @returns {vec2} a new 2D vector
  104. */
  105. vec2.clone = function(a) {
  106. var out = new GLMAT_ARRAY_TYPE(2);
  107. out[0] = a[0];
  108. out[1] = a[1];
  109. return out;
  110. };
  111. /**
  112. * Creates a new vec2 initialized with the given values
  113. *
  114. * @param {Number} x X component
  115. * @param {Number} y Y component
  116. * @returns {vec2} a new 2D vector
  117. */
  118. vec2.fromValues = function(x, y) {
  119. var out = new GLMAT_ARRAY_TYPE(2);
  120. out[0] = x;
  121. out[1] = y;
  122. return out;
  123. };
  124. /**
  125. * Copy the values from one vec2 to another
  126. *
  127. * @param {vec2} out the receiving vector
  128. * @param {vec2} a the source vector
  129. * @returns {vec2} out
  130. */
  131. vec2.copy = function(out, a) {
  132. out[0] = a[0];
  133. out[1] = a[1];
  134. return out;
  135. };
  136. /**
  137. * Set the components of a vec2 to the given values
  138. *
  139. * @param {vec2} out the receiving vector
  140. * @param {Number} x X component
  141. * @param {Number} y Y component
  142. * @returns {vec2} out
  143. */
  144. vec2.set = function(out, x, y) {
  145. out[0] = x;
  146. out[1] = y;
  147. return out;
  148. };
  149. /**
  150. * Adds two vec2's
  151. *
  152. * @param {vec2} out the receiving vector
  153. * @param {vec2} a the first operand
  154. * @param {vec2} b the second operand
  155. * @returns {vec2} out
  156. */
  157. vec2.add = function(out, a, b) {
  158. out[0] = a[0] + b[0];
  159. out[1] = a[1] + b[1];
  160. return out;
  161. };
  162. /**
  163. * Subtracts two vec2's
  164. *
  165. * @param {vec2} out the receiving vector
  166. * @param {vec2} a the first operand
  167. * @param {vec2} b the second operand
  168. * @returns {vec2} out
  169. */
  170. vec2.subtract = function(out, a, b) {
  171. out[0] = a[0] - b[0];
  172. out[1] = a[1] - b[1];
  173. return out;
  174. };
  175. /**
  176. * Alias for {@link vec2.subtract}
  177. * @function
  178. */
  179. vec2.sub = vec2.subtract;
  180. /**
  181. * Multiplies two vec2's
  182. *
  183. * @param {vec2} out the receiving vector
  184. * @param {vec2} a the first operand
  185. * @param {vec2} b the second operand
  186. * @returns {vec2} out
  187. */
  188. vec2.multiply = function(out, a, b) {
  189. out[0] = a[0] * b[0];
  190. out[1] = a[1] * b[1];
  191. return out;
  192. };
  193. /**
  194. * Alias for {@link vec2.multiply}
  195. * @function
  196. */
  197. vec2.mul = vec2.multiply;
  198. /**
  199. * Divides two vec2's
  200. *
  201. * @param {vec2} out the receiving vector
  202. * @param {vec2} a the first operand
  203. * @param {vec2} b the second operand
  204. * @returns {vec2} out
  205. */
  206. vec2.divide = function(out, a, b) {
  207. out[0] = a[0] / b[0];
  208. out[1] = a[1] / b[1];
  209. return out;
  210. };
  211. /**
  212. * Alias for {@link vec2.divide}
  213. * @function
  214. */
  215. vec2.div = vec2.divide;
  216. /**
  217. * Returns the minimum of two vec2's
  218. *
  219. * @param {vec2} out the receiving vector
  220. * @param {vec2} a the first operand
  221. * @param {vec2} b the second operand
  222. * @returns {vec2} out
  223. */
  224. vec2.min = function(out, a, b) {
  225. out[0] = Math.min(a[0], b[0]);
  226. out[1] = Math.min(a[1], b[1]);
  227. return out;
  228. };
  229. /**
  230. * Returns the maximum of two vec2's
  231. *
  232. * @param {vec2} out the receiving vector
  233. * @param {vec2} a the first operand
  234. * @param {vec2} b the second operand
  235. * @returns {vec2} out
  236. */
  237. vec2.max = function(out, a, b) {
  238. out[0] = Math.max(a[0], b[0]);
  239. out[1] = Math.max(a[1], b[1]);
  240. return out;
  241. };
  242. /**
  243. * Scales a vec2 by a scalar number
  244. *
  245. * @param {vec2} out the receiving vector
  246. * @param {vec2} a the vector to scale
  247. * @param {Number} b amount to scale the vector by
  248. * @returns {vec2} out
  249. */
  250. vec2.scale = function(out, a, b) {
  251. out[0] = a[0] * b;
  252. out[1] = a[1] * b;
  253. return out;
  254. };
  255. /**
  256. * Calculates the euclidian distance between two vec2's
  257. *
  258. * @param {vec2} a the first operand
  259. * @param {vec2} b the second operand
  260. * @returns {Number} distance between a and b
  261. */
  262. vec2.distance = function(a, b) {
  263. var x = b[0] - a[0],
  264. y = b[1] - a[1];
  265. return Math.sqrt(x*x + y*y);
  266. };
  267. /**
  268. * Alias for {@link vec2.distance}
  269. * @function
  270. */
  271. vec2.dist = vec2.distance;
  272. /**
  273. * Calculates the squared euclidian distance between two vec2's
  274. *
  275. * @param {vec2} a the first operand
  276. * @param {vec2} b the second operand
  277. * @returns {Number} squared distance between a and b
  278. */
  279. vec2.squaredDistance = function(a, b) {
  280. var x = b[0] - a[0],
  281. y = b[1] - a[1];
  282. return x*x + y*y;
  283. };
  284. /**
  285. * Alias for {@link vec2.squaredDistance}
  286. * @function
  287. */
  288. vec2.sqrDist = vec2.squaredDistance;
  289. /**
  290. * Calculates the length of a vec2
  291. *
  292. * @param {vec2} a vector to calculate length of
  293. * @returns {Number} length of a
  294. */
  295. vec2.length = function (a) {
  296. var x = a[0],
  297. y = a[1];
  298. return Math.sqrt(x*x + y*y);
  299. };
  300. /**
  301. * Alias for {@link vec2.length}
  302. * @function
  303. */
  304. vec2.len = vec2.length;
  305. /**
  306. * Calculates the squared length of a vec2
  307. *
  308. * @param {vec2} a vector to calculate squared length of
  309. * @returns {Number} squared length of a
  310. */
  311. vec2.squaredLength = function (a) {
  312. var x = a[0],
  313. y = a[1];
  314. return x*x + y*y;
  315. };
  316. /**
  317. * Alias for {@link vec2.squaredLength}
  318. * @function
  319. */
  320. vec2.sqrLen = vec2.squaredLength;
  321. /**
  322. * Negates the components of a vec2
  323. *
  324. * @param {vec2} out the receiving vector
  325. * @param {vec2} a vector to negate
  326. * @returns {vec2} out
  327. */
  328. vec2.negate = function(out, a) {
  329. out[0] = -a[0];
  330. out[1] = -a[1];
  331. return out;
  332. };
  333. /**
  334. * Normalize a vec2
  335. *
  336. * @param {vec2} out the receiving vector
  337. * @param {vec2} a vector to normalize
  338. * @returns {vec2} out
  339. */
  340. vec2.normalize = function(out, a) {
  341. var x = a[0],
  342. y = a[1];
  343. var len = x*x + y*y;
  344. if (len > 0) {
  345. //TODO: evaluate use of glm_invsqrt here?
  346. len = 1 / Math.sqrt(len);
  347. out[0] = a[0] * len;
  348. out[1] = a[1] * len;
  349. }
  350. return out;
  351. };
  352. /**
  353. * Calculates the dot product of two vec2's
  354. *
  355. * @param {vec2} a the first operand
  356. * @param {vec2} b the second operand
  357. * @returns {Number} dot product of a and b
  358. */
  359. vec2.dot = function (a, b) {
  360. return a[0] * b[0] + a[1] * b[1];
  361. };
  362. /**
  363. * Computes the cross product of two vec2's
  364. * Note that the cross product must by definition produce a 3D vector
  365. *
  366. * @param {vec3} out the receiving vector
  367. * @param {vec2} a the first operand
  368. * @param {vec2} b the second operand
  369. * @returns {vec3} out
  370. */
  371. vec2.cross = function(out, a, b) {
  372. var z = a[0] * b[1] - a[1] * b[0];
  373. out[0] = out[1] = 0;
  374. out[2] = z;
  375. return out;
  376. };
  377. /**
  378. * Performs a linear interpolation between two vec2's
  379. *
  380. * @param {vec2} out the receiving vector
  381. * @param {vec2} a the first operand
  382. * @param {vec2} b the second operand
  383. * @param {Number} t interpolation amount between the two inputs
  384. * @returns {vec2} out
  385. */
  386. vec2.lerp = function (out, a, b, t) {
  387. var ax = a[0],
  388. ay = a[1];
  389. out[0] = ax + t * (b[0] - ax);
  390. out[1] = ay + t * (b[1] - ay);
  391. return out;
  392. };
  393. /**
  394. * Transforms the vec2 with a mat2
  395. *
  396. * @param {vec2} out the receiving vector
  397. * @param {vec2} a the vector to transform
  398. * @param {mat2} m matrix to transform with
  399. * @returns {vec2} out
  400. */
  401. vec2.transformMat2 = function(out, a, m) {
  402. var x = a[0],
  403. y = a[1];
  404. out[0] = m[0] * x + m[2] * y;
  405. out[1] = m[1] * x + m[3] * y;
  406. return out;
  407. };
  408. /**
  409. * Transforms the vec2 with a mat2d
  410. *
  411. * @param {vec2} out the receiving vector
  412. * @param {vec2} a the vector to transform
  413. * @param {mat2d} m matrix to transform with
  414. * @returns {vec2} out
  415. */
  416. vec2.transformMat2d = function(out, a, m) {
  417. var x = a[0],
  418. y = a[1];
  419. out[0] = m[0] * x + m[2] * y + m[4];
  420. out[1] = m[1] * x + m[3] * y + m[5];
  421. return out;
  422. };
  423. /**
  424. * Transforms the vec2 with a mat3
  425. * 3rd vector component is implicitly '1'
  426. *
  427. * @param {vec2} out the receiving vector
  428. * @param {vec2} a the vector to transform
  429. * @param {mat3} m matrix to transform with
  430. * @returns {vec2} out
  431. */
  432. vec2.transformMat3 = function(out, a, m) {
  433. var x = a[0],
  434. y = a[1];
  435. out[0] = m[0] * x + m[3] * y + m[6];
  436. out[1] = m[1] * x + m[4] * y + m[7];
  437. return out;
  438. };
  439. /**
  440. * Transforms the vec2 with a mat4
  441. * 3rd vector component is implicitly '0'
  442. * 4th vector component is implicitly '1'
  443. *
  444. * @param {vec2} out the receiving vector
  445. * @param {vec2} a the vector to transform
  446. * @param {mat4} m matrix to transform with
  447. * @returns {vec2} out
  448. */
  449. vec2.transformMat4 = function(out, a, m) {
  450. var x = a[0],
  451. y = a[1];
  452. out[0] = m[0] * x + m[4] * y + m[12];
  453. out[1] = m[1] * x + m[5] * y + m[13];
  454. return out;
  455. };
  456. /**
  457. * Perform some operation over an array of vec2s.
  458. *
  459. * @param {Array} a the array of vectors to iterate over
  460. * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
  461. * @param {Number} offset Number of elements to skip at the beginning of the array
  462. * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
  463. * @param {Function} fn Function to call for each vector in the array
  464. * @param {Object} [arg] additional argument to pass to fn
  465. * @returns {Array} a
  466. * @function
  467. */
  468. vec2.forEach = (function() {
  469. var vec = vec2.create();
  470. return function(a, stride, offset, count, fn, arg) {
  471. var i, l;
  472. if(!stride) {
  473. stride = 2;
  474. }
  475. if(!offset) {
  476. offset = 0;
  477. }
  478. if(count) {
  479. l = Math.min((count * stride) + offset, a.length);
  480. } else {
  481. l = a.length;
  482. }
  483. for(i = offset; i < l; i += stride) {
  484. vec[0] = a[i]; vec[1] = a[i+1];
  485. fn(vec, vec, arg);
  486. a[i] = vec[0]; a[i+1] = vec[1];
  487. }
  488. return a;
  489. };
  490. })();
  491. /**
  492. * Returns a string representation of a vector
  493. *
  494. * @param {vec2} vec vector to represent as a string
  495. * @returns {String} string representation of the vector
  496. */
  497. vec2.str = function (a) {
  498. return 'vec2(' + a[0] + ', ' + a[1] + ')';
  499. };
  500. if(typeof(exports) !== 'undefined') {
  501. exports.vec2 = vec2;
  502. }
  503. },{}],2:[function(require,module,exports){
  504. var Scalar = require('./Scalar');
  505. module.exports = Line;
  506. /**
  507. * Container for line-related functions
  508. * @class Line
  509. */
  510. function Line(){};
  511. /**
  512. * Compute the intersection between two lines.
  513. * @static
  514. * @method lineInt
  515. * @param {Array} l1 Line vector 1
  516. * @param {Array} l2 Line vector 2
  517. * @param {Number} precision Precision to use when checking if the lines are parallel
  518. * @return {Array} The intersection point.
  519. */
  520. Line.lineInt = function(l1,l2,precision){
  521. precision = precision || 0;
  522. var i = [0,0]; // point
  523. var a1, b1, c1, a2, b2, c2, det; // scalars
  524. a1 = l1[1][1] - l1[0][1];
  525. b1 = l1[0][0] - l1[1][0];
  526. c1 = a1 * l1[0][0] + b1 * l1[0][1];
  527. a2 = l2[1][1] - l2[0][1];
  528. b2 = l2[0][0] - l2[1][0];
  529. c2 = a2 * l2[0][0] + b2 * l2[0][1];
  530. det = a1 * b2 - a2*b1;
  531. if (!Scalar.eq(det, 0, precision)) { // lines are not parallel
  532. i[0] = (b2 * c1 - b1 * c2) / det;
  533. i[1] = (a1 * c2 - a2 * c1) / det;
  534. }
  535. return i;
  536. };
  537. /**
  538. * Checks if two line segments intersects.
  539. * @method segmentsIntersect
  540. * @param {Array} p1 The start vertex of the first line segment.
  541. * @param {Array} p2 The end vertex of the first line segment.
  542. * @param {Array} q1 The start vertex of the second line segment.
  543. * @param {Array} q2 The end vertex of the second line segment.
  544. * @return {Boolean} True if the two line segments intersect
  545. */
  546. Line.segmentsIntersect = function(p1, p2, q1, q2){
  547. var dx = p2[0] - p1[0];
  548. var dy = p2[1] - p1[1];
  549. var da = q2[0] - q1[0];
  550. var db = q2[1] - q1[1];
  551. // segments are parallel
  552. if(da*dy - db*dx == 0)
  553. return false;
  554. var s = (dx * (q1[1] - p1[1]) + dy * (p1[0] - q1[0])) / (da * dy - db * dx)
  555. var t = (da * (p1[1] - q1[1]) + db * (q1[0] - p1[0])) / (db * dx - da * dy)
  556. return (s>=0 && s<=1 && t>=0 && t<=1);
  557. };
  558. },{"./Scalar":5}],3:[function(require,module,exports){
  559. module.exports = Point;
  560. /**
  561. * Point related functions
  562. * @class Point
  563. */
  564. function Point(){};
  565. /**
  566. * Get the area of a triangle spanned by the three given points. Note that the area will be negative if the points are not given in counter-clockwise order.
  567. * @static
  568. * @method area
  569. * @param {Array} a
  570. * @param {Array} b
  571. * @param {Array} c
  572. * @return {Number}
  573. */
  574. Point.area = function(a,b,c){
  575. return (((b[0] - a[0])*(c[1] - a[1]))-((c[0] - a[0])*(b[1] - a[1])));
  576. };
  577. Point.left = function(a,b,c){
  578. return Point.area(a,b,c) > 0;
  579. };
  580. Point.leftOn = function(a,b,c) {
  581. return Point.area(a, b, c) >= 0;
  582. };
  583. Point.right = function(a,b,c) {
  584. return Point.area(a, b, c) < 0;
  585. };
  586. Point.rightOn = function(a,b,c) {
  587. return Point.area(a, b, c) <= 0;
  588. };
  589. var tmpPoint1 = [],
  590. tmpPoint2 = [];
  591. /**
  592. * Check if three points are collinear
  593. * @method collinear
  594. * @param {Array} a
  595. * @param {Array} b
  596. * @param {Array} c
  597. * @param {Number} [thresholdAngle=0] Threshold angle to use when comparing the vectors. The function will return true if the angle between the resulting vectors is less than this value. Use zero for max precision.
  598. * @return {Boolean}
  599. */
  600. Point.collinear = function(a,b,c,thresholdAngle) {
  601. if(!thresholdAngle)
  602. return Point.area(a, b, c) == 0;
  603. else {
  604. var ab = tmpPoint1,
  605. bc = tmpPoint2;
  606. ab[0] = b[0]-a[0];
  607. ab[1] = b[1]-a[1];
  608. bc[0] = c[0]-b[0];
  609. bc[1] = c[1]-b[1];
  610. var dot = ab[0]*bc[0] + ab[1]*bc[1],
  611. magA = Math.sqrt(ab[0]*ab[0] + ab[1]*ab[1]),
  612. magB = Math.sqrt(bc[0]*bc[0] + bc[1]*bc[1]),
  613. angle = Math.acos(dot/(magA*magB));
  614. return angle < thresholdAngle;
  615. }
  616. };
  617. Point.sqdist = function(a,b){
  618. var dx = b[0] - a[0];
  619. var dy = b[1] - a[1];
  620. return dx * dx + dy * dy;
  621. };
  622. },{}],4:[function(require,module,exports){
  623. var Line = require("./Line")
  624. , Point = require("./Point")
  625. , Scalar = require("./Scalar")
  626. module.exports = Polygon;
  627. /**
  628. * Polygon class.
  629. * @class Polygon
  630. * @constructor
  631. */
  632. function Polygon(){
  633. /**
  634. * Vertices that this polygon consists of. An array of array of numbers, example: [[0,0],[1,0],..]
  635. * @property vertices
  636. * @type {Array}
  637. */
  638. this.vertices = [];
  639. }
  640. /**
  641. * Get a vertex at position i. It does not matter if i is out of bounds, this function will just cycle.
  642. * @method at
  643. * @param {Number} i
  644. * @return {Array}
  645. */
  646. Polygon.prototype.at = function(i){
  647. var v = this.vertices,
  648. s = v.length;
  649. return v[i < 0 ? i % s + s : i % s];
  650. };
  651. /**
  652. * Get first vertex
  653. * @method first
  654. * @return {Array}
  655. */
  656. Polygon.prototype.first = function(){
  657. return this.vertices[0];
  658. };
  659. /**
  660. * Get last vertex
  661. * @method last
  662. * @return {Array}
  663. */
  664. Polygon.prototype.last = function(){
  665. return this.vertices[this.vertices.length-1];
  666. };
  667. /**
  668. * Clear the polygon data
  669. * @method clear
  670. * @return {Array}
  671. */
  672. Polygon.prototype.clear = function(){
  673. this.vertices.length = 0;
  674. };
  675. /**
  676. * Append points "from" to "to"-1 from an other polygon "poly" onto this one.
  677. * @method append
  678. * @param {Polygon} poly The polygon to get points from.
  679. * @param {Number} from The vertex index in "poly".
  680. * @param {Number} to The end vertex index in "poly". Note that this vertex is NOT included when appending.
  681. * @return {Array}
  682. */
  683. Polygon.prototype.append = function(poly,from,to){
  684. if(typeof(from) == "undefined") throw new Error("From is not given!");
  685. if(typeof(to) == "undefined") throw new Error("To is not given!");
  686. if(to-1 < from) throw new Error("lol1");
  687. if(to > poly.vertices.length) throw new Error("lol2");
  688. if(from < 0) throw new Error("lol3");
  689. for(var i=from; i<to; i++){
  690. this.vertices.push(poly.vertices[i]);
  691. }
  692. };
  693. /**
  694. * Make sure that the polygon vertices are ordered counter-clockwise.
  695. * @method makeCCW
  696. */
  697. Polygon.prototype.makeCCW = function(){
  698. var br = 0,
  699. v = this.vertices;
  700. // find bottom right point
  701. for (var i = 1; i < this.vertices.length; ++i) {
  702. if (v[i][1] < v[br][1] || (v[i][1] == v[br][1] && v[i][0] > v[br][0])) {
  703. br = i;
  704. }
  705. }
  706. // reverse poly if clockwise
  707. if (!Point.left(this.at(br - 1), this.at(br), this.at(br + 1))) {
  708. this.reverse();
  709. }
  710. };
  711. /**
  712. * Reverse the vertices in the polygon
  713. * @method reverse
  714. */
  715. Polygon.prototype.reverse = function(){
  716. var tmp = [];
  717. for(var i=0, N=this.vertices.length; i!==N; i++){
  718. tmp.push(this.vertices.pop());
  719. }
  720. this.vertices = tmp;
  721. };
  722. /**
  723. * Check if a point in the polygon is a reflex point
  724. * @method isReflex
  725. * @param {Number} i
  726. * @return {Boolean}
  727. */
  728. Polygon.prototype.isReflex = function(i){
  729. return Point.right(this.at(i - 1), this.at(i), this.at(i + 1));
  730. };
  731. var tmpLine1=[],
  732. tmpLine2=[];
  733. /**
  734. * Check if two vertices in the polygon can see each other
  735. * @method canSee
  736. * @param {Number} a Vertex index 1
  737. * @param {Number} b Vertex index 2
  738. * @return {Boolean}
  739. */
  740. Polygon.prototype.canSee = function(a,b) {
  741. var p, dist, l1=tmpLine1, l2=tmpLine2;
  742. if (Point.leftOn(this.at(a + 1), this.at(a), this.at(b)) && Point.rightOn(this.at(a - 1), this.at(a), this.at(b))) {
  743. return false;
  744. }
  745. dist = Point.sqdist(this.at(a), this.at(b));
  746. for (var i = 0; i !== this.vertices.length; ++i) { // for each edge
  747. if ((i + 1) % this.vertices.length === a || i === a) // ignore incident edges
  748. continue;
  749. if (Point.leftOn(this.at(a), this.at(b), this.at(i + 1)) && Point.rightOn(this.at(a), this.at(b), this.at(i))) { // if diag intersects an edge
  750. l1[0] = this.at(a);
  751. l1[1] = this.at(b);
  752. l2[0] = this.at(i);
  753. l2[1] = this.at(i + 1);
  754. p = Line.lineInt(l1,l2);
  755. if (Point.sqdist(this.at(a), p) < dist) { // if edge is blocking visibility to b
  756. return false;
  757. }
  758. }
  759. }
  760. return true;
  761. };
  762. /**
  763. * Copy the polygon from vertex i to vertex j.
  764. * @method copy
  765. * @param {Number} i
  766. * @param {Number} j
  767. * @param {Polygon} [targetPoly] Optional target polygon to save in.
  768. * @return {Polygon} The resulting copy.
  769. */
  770. Polygon.prototype.copy = function(i,j,targetPoly){
  771. var p = targetPoly || new Polygon();
  772. p.clear();
  773. if (i < j) {
  774. // Insert all vertices from i to j
  775. for(var k=i; k<=j; k++)
  776. p.vertices.push(this.vertices[k]);
  777. } else {
  778. // Insert vertices 0 to j
  779. for(var k=0; k<=j; k++)
  780. p.vertices.push(this.vertices[k]);
  781. // Insert vertices i to end
  782. for(var k=i; k<this.vertices.length; k++)
  783. p.vertices.push(this.vertices[k]);
  784. }
  785. return p;
  786. };
  787. /**
  788. * Decomposes the polygon into convex pieces. Returns a list of edges [[p1,p2],[p2,p3],...] that cuts the polygon.
  789. * Note that this algorithm has complexity O(N^4) and will be very slow for polygons with many vertices.
  790. * @method getCutEdges
  791. * @return {Array}
  792. */
  793. Polygon.prototype.getCutEdges = function() {
  794. var min=[], tmp1=[], tmp2=[], tmpPoly = new Polygon();
  795. var nDiags = Number.MAX_VALUE;
  796. for (var i = 0; i < this.vertices.length; ++i) {
  797. if (this.isReflex(i)) {
  798. for (var j = 0; j < this.vertices.length; ++j) {
  799. if (this.canSee(i, j)) {
  800. tmp1 = this.copy(i, j, tmpPoly).getCutEdges();
  801. tmp2 = this.copy(j, i, tmpPoly).getCutEdges();
  802. for(var k=0; k<tmp2.length; k++)
  803. tmp1.push(tmp2[k]);
  804. if (tmp1.length < nDiags) {
  805. min = tmp1;
  806. nDiags = tmp1.length;
  807. min.push([this.at(i), this.at(j)]);
  808. }
  809. }
  810. }
  811. }
  812. }
  813. return min;
  814. };
  815. /**
  816. * Decomposes the polygon into one or more convex sub-Polygons.
  817. * @method decomp
  818. * @return {Array} An array or Polygon objects.
  819. */
  820. Polygon.prototype.decomp = function(){
  821. var edges = this.getCutEdges();
  822. if(edges.length > 0)
  823. return this.slice(edges);
  824. else
  825. return [this];
  826. };
  827. /**
  828. * Slices the polygon given one or more cut edges. If given one, this function will return two polygons (false on failure). If many, an array of polygons.
  829. * @method slice
  830. * @param {Array} cutEdges A list of edges, as returned by .getCutEdges()
  831. * @return {Array}
  832. */
  833. Polygon.prototype.slice = function(cutEdges){
  834. if(cutEdges.length == 0) return [this];
  835. if(cutEdges instanceof Array && cutEdges.length && cutEdges[0] instanceof Array && cutEdges[0].length==2 && cutEdges[0][0] instanceof Array){
  836. var polys = [this];
  837. for(var i=0; i<cutEdges.length; i++){
  838. var cutEdge = cutEdges[i];
  839. // Cut all polys
  840. for(var j=0; j<polys.length; j++){
  841. var poly = polys[j];
  842. var result = poly.slice(cutEdge);
  843. if(result){
  844. // Found poly! Cut and quit
  845. polys.splice(j,1);
  846. polys.push(result[0],result[1]);
  847. break;
  848. }
  849. }
  850. }
  851. return polys;
  852. } else {
  853. // Was given one edge
  854. var cutEdge = cutEdges;
  855. var i = this.vertices.indexOf(cutEdge[0]);
  856. var j = this.vertices.indexOf(cutEdge[1]);
  857. if(i != -1 && j != -1){
  858. return [this.copy(i,j),
  859. this.copy(j,i)];
  860. } else {
  861. return false;
  862. }
  863. }
  864. };
  865. /**
  866. * Checks that the line segments of this polygon do not intersect each other.
  867. * @method isSimple
  868. * @param {Array} path An array of vertices e.g. [[0,0],[0,1],...]
  869. * @return {Boolean}
  870. * @todo Should it check all segments with all others?
  871. */
  872. Polygon.prototype.isSimple = function(){
  873. var path = this.vertices;
  874. // Check
  875. for(var i=0; i<path.length-1; i++){
  876. for(var j=0; j<i-1; j++){
  877. if(Line.segmentsIntersect(path[i], path[i+1], path[j], path[j+1] )){
  878. return false;
  879. }
  880. }
  881. }
  882. // Check the segment between the last and the first point to all others
  883. for(var i=1; i<path.length-2; i++){
  884. if(Line.segmentsIntersect(path[0], path[path.length-1], path[i], path[i+1] )){
  885. return false;
  886. }
  887. }
  888. return true;
  889. };
  890. function getIntersectionPoint(p1, p2, q1, q2, delta){
  891. delta = delta || 0;
  892. var a1 = p2[1] - p1[1];
  893. var b1 = p1[0] - p2[0];
  894. var c1 = (a1 * p1[0]) + (b1 * p1[1]);
  895. var a2 = q2[1] - q1[1];
  896. var b2 = q1[0] - q2[0];
  897. var c2 = (a2 * q1[0]) + (b2 * q1[1]);
  898. var det = (a1 * b2) - (a2 * b1);
  899. if(!Scalar.eq(det,0,delta))
  900. return [((b2 * c1) - (b1 * c2)) / det, ((a1 * c2) - (a2 * c1)) / det]
  901. else
  902. return [0,0]
  903. }
  904. /**
  905. * Quickly decompose the Polygon into convex sub-polygons.
  906. * @method quickDecomp
  907. * @param {Array} result
  908. * @param {Array} [reflexVertices]
  909. * @param {Array} [steinerPoints]
  910. * @param {Number} [delta]
  911. * @param {Number} [maxlevel]
  912. * @param {Number} [level]
  913. * @return {Array}
  914. */
  915. Polygon.prototype.quickDecomp = function(result,reflexVertices,steinerPoints,delta,maxlevel,level){
  916. maxlevel = maxlevel || 100;
  917. level = level || 0;
  918. delta = delta || 25;
  919. result = typeof(result)!="undefined" ? result : [];
  920. reflexVertices = reflexVertices || [];
  921. steinerPoints = steinerPoints || [];
  922. var upperInt=[0,0], lowerInt=[0,0], p=[0,0]; // Points
  923. var upperDist=0, lowerDist=0, d=0, closestDist=0; // scalars
  924. var upperIndex=0, lowerIndex=0, closestIndex=0; // Integers
  925. var lowerPoly=new Polygon(), upperPoly=new Polygon(); // polygons
  926. var poly = this,
  927. v = this.vertices;
  928. if(v.length < 3) return result;
  929. level++;
  930. if(level > maxlevel){
  931. console.warn("quickDecomp: max level ("+maxlevel+") reached.");
  932. return result;
  933. }
  934. for (var i = 0; i < this.vertices.length; ++i) {
  935. if (poly.isReflex(i)) {
  936. reflexVertices.push(poly.vertices[i]);
  937. upperDist = lowerDist = Number.MAX_VALUE;
  938. for (var j = 0; j < this.vertices.length; ++j) {
  939. if (Point.left(poly.at(i - 1), poly.at(i), poly.at(j))
  940. && Point.rightOn(poly.at(i - 1), poly.at(i), poly.at(j - 1))) { // if line intersects with an edge
  941. p = getIntersectionPoint(poly.at(i - 1), poly.at(i), poly.at(j), poly.at(j - 1)); // find the point of intersection
  942. if (Point.right(poly.at(i + 1), poly.at(i), p)) { // make sure it's inside the poly
  943. d = Point.sqdist(poly.vertices[i], p);
  944. if (d < lowerDist) { // keep only the closest intersection
  945. lowerDist = d;
  946. lowerInt = p;
  947. lowerIndex = j;
  948. }
  949. }
  950. }
  951. if (Point.left(poly.at(i + 1), poly.at(i), poly.at(j + 1))
  952. && Point.rightOn(poly.at(i + 1), poly.at(i), poly.at(j))) {
  953. p = getIntersectionPoint(poly.at(i + 1), poly.at(i), poly.at(j), poly.at(j + 1));
  954. if (Point.left(poly.at(i - 1), poly.at(i), p)) {
  955. d = Point.sqdist(poly.vertices[i], p);
  956. if (d < upperDist) {
  957. upperDist = d;
  958. upperInt = p;
  959. upperIndex = j;
  960. }
  961. }
  962. }
  963. }
  964. // if there are no vertices to connect to, choose a point in the middle
  965. if (lowerIndex == (upperIndex + 1) % this.vertices.length) {
  966. //console.log("Case 1: Vertex("+i+"), lowerIndex("+lowerIndex+"), upperIndex("+upperIndex+"), poly.size("+this.vertices.length+")");
  967. p[0] = (lowerInt[0] + upperInt[0]) / 2;
  968. p[1] = (lowerInt[1] + upperInt[1]) / 2;
  969. steinerPoints.push(p);
  970. if (i < upperIndex) {
  971. //lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.begin() + upperIndex + 1);
  972. lowerPoly.append(poly, i, upperIndex+1);
  973. lowerPoly.vertices.push(p);
  974. upperPoly.vertices.push(p);
  975. if (lowerIndex != 0){
  976. //upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.end());
  977. upperPoly.append(poly,lowerIndex,poly.vertices.length);
  978. }
  979. //upperPoly.insert(upperPoly.end(), poly.begin(), poly.begin() + i + 1);
  980. upperPoly.append(poly,0,i+1);
  981. } else {
  982. if (i != 0){
  983. //lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.end());
  984. lowerPoly.append(poly,i,poly.vertices.length);
  985. }
  986. //lowerPoly.insert(lowerPoly.end(), poly.begin(), poly.begin() + upperIndex + 1);
  987. lowerPoly.append(poly,0,upperIndex+1);
  988. lowerPoly.vertices.push(p);
  989. upperPoly.vertices.push(p);
  990. //upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.begin() + i + 1);
  991. upperPoly.append(poly,lowerIndex,i+1);
  992. }
  993. } else {
  994. // connect to the closest point within the triangle
  995. //console.log("Case 2: Vertex("+i+"), closestIndex("+closestIndex+"), poly.size("+this.vertices.length+")\n");
  996. if (lowerIndex > upperIndex) {
  997. upperIndex += this.vertices.length;
  998. }
  999. closestDist = Number.MAX_VALUE;
  1000. if(upperIndex < lowerIndex){
  1001. return result;
  1002. }
  1003. for (var j = lowerIndex; j <= upperIndex; ++j) {
  1004. if (Point.leftOn(poly.at(i - 1), poly.at(i), poly.at(j))
  1005. && Point.rightOn(poly.at(i + 1), poly.at(i), poly.at(j))) {
  1006. d = Point.sqdist(poly.at(i), poly.at(j));
  1007. if (d < closestDist) {
  1008. closestDist = d;
  1009. closestIndex = j % this.vertices.length;
  1010. }
  1011. }
  1012. }
  1013. if (i < closestIndex) {
  1014. lowerPoly.append(poly,i,closestIndex+1);
  1015. if (closestIndex != 0){
  1016. upperPoly.append(poly,closestIndex,v.length);
  1017. }
  1018. upperPoly.append(poly,0,i+1);
  1019. } else {
  1020. if (i != 0){
  1021. lowerPoly.append(poly,i,v.length);
  1022. }
  1023. lowerPoly.append(poly,0,closestIndex+1);
  1024. upperPoly.append(poly,closestIndex,i+1);
  1025. }
  1026. }
  1027. // solve smallest poly first
  1028. if (lowerPoly.vertices.length < upperPoly.vertices.length) {
  1029. lowerPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  1030. upperPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  1031. } else {
  1032. upperPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  1033. lowerPoly.quickDecomp(result,reflexVertices,steinerPoints,delta,maxlevel,level);
  1034. }
  1035. return result;
  1036. }
  1037. }
  1038. result.push(this);
  1039. return result;
  1040. };
  1041. /**
  1042. * Remove collinear points in the polygon.
  1043. * @method removeCollinearPoints
  1044. * @param {Number} [precision] The threshold angle to use when determining whether two edges are collinear. Use zero for finest precision.
  1045. * @return {Number} The number of points removed
  1046. */
  1047. Polygon.prototype.removeCollinearPoints = function(precision){
  1048. var num = 0;
  1049. for(var i=this.vertices.length-1; this.vertices.length>3 && i>=0; --i){
  1050. if(Point.collinear(this.at(i-1),this.at(i),this.at(i+1),precision)){
  1051. // Remove the middle point
  1052. this.vertices.splice(i%this.vertices.length,1);
  1053. i--; // Jump one point forward. Otherwise we may get a chain removal
  1054. num++;
  1055. }
  1056. }
  1057. return num;
  1058. };
  1059. },{"./Line":2,"./Point":3,"./Scalar":5}],5:[function(require,module,exports){
  1060. module.exports = Scalar;
  1061. /**
  1062. * Scalar functions
  1063. * @class Scalar
  1064. */
  1065. function Scalar(){}
  1066. /**
  1067. * Check if two scalars are equal
  1068. * @static
  1069. * @method eq
  1070. * @param {Number} a
  1071. * @param {Number} b
  1072. * @param {Number} [precision]
  1073. * @return {Boolean}
  1074. */
  1075. Scalar.eq = function(a,b,precision){
  1076. precision = precision || 0;
  1077. return Math.abs(a-b) < precision;
  1078. };
  1079. },{}],6:[function(require,module,exports){
  1080. module.exports = {
  1081. Polygon : require("./Polygon"),
  1082. Point : require("./Point"),
  1083. };
  1084. },{"./Point":3,"./Polygon":4}],7:[function(require,module,exports){
  1085. module.exports={
  1086. "name": "p2",
  1087. "version": "0.5.0",
  1088. "description": "A JavaScript 2D physics engine.",
  1089. "author": "Stefan Hedman <schteppe@gmail.com> (http://steffe.se)",
  1090. "keywords": [
  1091. "p2.js",
  1092. "p2",
  1093. "physics",
  1094. "engine",
  1095. "2d"
  1096. ],
  1097. "main": "./src/p2.js",
  1098. "engines": {
  1099. "node": "*"
  1100. },
  1101. "repository": {
  1102. "type": "git",
  1103. "url": "https://github.com/schteppe/p2.js.git"
  1104. },
  1105. "bugs": {
  1106. "url": "https://github.com/schteppe/p2.js/issues"
  1107. },
  1108. "licenses": [
  1109. {
  1110. "type": "MIT"
  1111. }
  1112. ],
  1113. "devDependencies": {
  1114. "grunt": "~0.4.0",
  1115. "grunt-contrib-jshint": "~0.9.2",
  1116. "grunt-contrib-nodeunit": "~0.1.2",
  1117. "grunt-contrib-uglify": "~0.4.0",
  1118. "grunt-browserify": "~2.0.1",
  1119. "z-schema": "~2.4.6"
  1120. },
  1121. "dependencies": {
  1122. "poly-decomp": "git://github.com/schteppe/poly-decomp.js",
  1123. "gl-matrix": "2.1.0"
  1124. }
  1125. }
  1126. },{}],8:[function(require,module,exports){
  1127. var vec2 = require('../math/vec2')
  1128. , Utils = require('../utils/Utils');
  1129. module.exports = AABB;
  1130. /**
  1131. * Axis aligned bounding box class.
  1132. * @class AABB
  1133. * @constructor
  1134. * @param {Object} [options]
  1135. * @param {Array} [options.upperBound]
  1136. * @param {Array} [options.lowerBound]
  1137. */
  1138. function AABB(options){
  1139. /**
  1140. * The lower bound of the bounding box.
  1141. * @property lowerBound
  1142. * @type {Array}
  1143. */
  1144. this.lowerBound = vec2.create();
  1145. if(options && options.lowerBound){
  1146. vec2.copy(this.lowerBound, options.lowerBound);
  1147. }
  1148. /**
  1149. * The upper bound of the bounding box.
  1150. * @property upperBound
  1151. * @type {Array}
  1152. */
  1153. this.upperBound = vec2.create();
  1154. if(options && options.upperBound){
  1155. vec2.copy(this.upperBound, options.upperBound);
  1156. }
  1157. }
  1158. var tmp = vec2.create();
  1159. /**
  1160. * Set the AABB bounds from a set of points.
  1161. * @method setFromPoints
  1162. * @param {Array} points An array of vec2's.
  1163. */
  1164. AABB.prototype.setFromPoints = function(points,position,angle){
  1165. var l = this.lowerBound,
  1166. u = this.upperBound;
  1167. vec2.set(l, Number.MAX_VALUE, Number.MAX_VALUE);
  1168. vec2.set(u, -Number.MAX_VALUE, -Number.MAX_VALUE);
  1169. for(var i=0; i<points.length; i++){
  1170. var p = points[i];
  1171. if(typeof(angle) === "number"){
  1172. vec2.rotate(tmp,p,angle);
  1173. p = tmp;
  1174. }
  1175. for(var j=0; j<2; j++){
  1176. if(p[j] > u[j]){
  1177. u[j] = p[j];
  1178. }
  1179. if(p[j] < l[j]){
  1180. l[j] = p[j];
  1181. }
  1182. }
  1183. }
  1184. // Add offset
  1185. if(position){
  1186. vec2.add(this.lowerBound, this.lowerBound, position);
  1187. vec2.add(this.upperBound, this.upperBound, position);
  1188. }
  1189. };
  1190. /**
  1191. * Copy bounds from an AABB to this AABB
  1192. * @method copy
  1193. * @param {AABB} aabb
  1194. */
  1195. AABB.prototype.copy = function(aabb){
  1196. vec2.copy(this.lowerBound, aabb.lowerBound);
  1197. vec2.copy(this.upperBound, aabb.upperBound);
  1198. };
  1199. /**
  1200. * Extend this AABB so that it covers the given AABB too.
  1201. * @method extend
  1202. * @param {AABB} aabb
  1203. */
  1204. AABB.prototype.extend = function(aabb){
  1205. // Loop over x and y
  1206. for(var i=0; i<2; i++){
  1207. // Extend lower bound
  1208. if(aabb.lowerBound[i] < this.lowerBound[i]){
  1209. this.lowerBound[i] = aabb.lowerBound[i];
  1210. }
  1211. // Upper
  1212. if(aabb.upperBound[i] > this.upperBound[i]){
  1213. this.upperBound[i] = aabb.upperBound[i];
  1214. }
  1215. }
  1216. };
  1217. /**
  1218. * Returns true if the given AABB overlaps this AABB.
  1219. * @method overlaps
  1220. * @param {AABB} aabb
  1221. * @return {Boolean}
  1222. */
  1223. AABB.prototype.overlaps = function(aabb){
  1224. var l1 = this.lowerBound,
  1225. u1 = this.upperBound,
  1226. l2 = aabb.lowerBound,
  1227. u2 = aabb.upperBound;
  1228. // l2 u2
  1229. // |---------|
  1230. // |--------|
  1231. // l1 u1
  1232. return ((l2[0] <= u1[0] && u1[0] <= u2[0]) || (l1[0] <= u2[0] && u2[0] <= u1[0])) &&
  1233. ((l2[1] <= u1[1] && u1[1] <= u2[1]) || (l1[1] <= u2[1] && u2[1] <= u1[1]));
  1234. };
  1235. },{"../math/vec2":30,"../utils/Utils":45}],9:[function(require,module,exports){
  1236. var vec2 = require('../math/vec2')
  1237. var Body = require('../objects/Body')
  1238. module.exports = Broadphase;
  1239. /**
  1240. * Base class for broadphase implementations.
  1241. * @class Broadphase
  1242. * @constructor
  1243. */
  1244. function Broadphase(type){
  1245. this.type = type;
  1246. /**
  1247. * The resulting overlapping pairs. Will be filled with results during .getCollisionPairs().
  1248. * @property result
  1249. * @type {Array}
  1250. */
  1251. this.result = [];
  1252. /**
  1253. * The world to search for collision pairs in. To change it, use .setWorld()
  1254. * @property world
  1255. * @type {World}
  1256. * @readOnly
  1257. */
  1258. this.world = null;
  1259. /**
  1260. * The bounding volume type to use in the broadphase algorithms.
  1261. * @property {Number} boundingVolumeType
  1262. */
  1263. this.boundingVolumeType = Broadphase.AABB;
  1264. }
  1265. /**
  1266. * Axis aligned bounding box type.
  1267. * @static
  1268. * @property {Number} AABB
  1269. */
  1270. Broadphase.AABB = 1;
  1271. /**
  1272. * Bounding circle type.
  1273. * @static
  1274. * @property {Number} BOUNDING_CIRCLE
  1275. */
  1276. Broadphase.BOUNDING_CIRCLE = 2;
  1277. /**
  1278. * Set the world that we are searching for collision pairs in
  1279. * @method setWorld
  1280. * @param {World} world
  1281. */
  1282. Broadphase.prototype.setWorld = function(world){
  1283. this.world = world;
  1284. };
  1285. /**
  1286. * Get all potential intersecting body pairs.
  1287. * @method getCollisionPairs
  1288. * @param {World} world The world to search in.
  1289. * @return {Array} An array of the bodies, ordered in pairs. Example: A result of [a,b,c,d] means that the potential pairs are: (a,b), (c,d).
  1290. */
  1291. Broadphase.prototype.getCollisionPairs = function(world){
  1292. throw new Error("getCollisionPairs must be implemented in a subclass!");
  1293. };
  1294. var dist = vec2.create();
  1295. /**
  1296. * Check whether the bounding radius of two bodies overlap.
  1297. * @method boundingRadiusCheck
  1298. * @param {Body} bodyA
  1299. * @param {Body} bodyB
  1300. * @return {Boolean}
  1301. */
  1302. Broadphase.boundingRadiusCheck = function(bodyA, bodyB){
  1303. vec2.sub(dist, bodyA.position, bodyB.position);
  1304. var d2 = vec2.squaredLength(dist),
  1305. r = bodyA.boundingRadius + bodyB.boundingRadius;
  1306. return d2 <= r*r;
  1307. };
  1308. /**
  1309. * Check whether the bounding radius of two bodies overlap.
  1310. * @method boundingRadiusCheck
  1311. * @param {Body} bodyA
  1312. * @param {Body} bodyB
  1313. * @return {Boolean}
  1314. */
  1315. Broadphase.aabbCheck = function(bodyA, bodyB){
  1316. if(bodyA.aabbNeedsUpdate){
  1317. bodyA.updateAABB();
  1318. }
  1319. if(bodyB.aabbNeedsUpdate){
  1320. bodyB.updateAABB();
  1321. }
  1322. return bodyA.aabb.overlaps(bodyB.aabb);
  1323. };
  1324. /**
  1325. * Check whether the bounding radius of two bodies overlap.
  1326. * @method boundingRadiusCheck
  1327. * @param {Body} bodyA
  1328. * @param {Body} bodyB
  1329. * @return {Boolean}
  1330. */
  1331. Broadphase.prototype.boundingVolumeCheck = function(bodyA, bodyB){
  1332. var result;
  1333. switch(this.boundingVolumeType){
  1334. case Broadphase.BOUNDING_CIRCLE:
  1335. result = Broadphase.boundingRadiusCheck(bodyA,bodyB);
  1336. break;
  1337. case Broadphase.AABB:
  1338. result = Broadphase.aabbCheck(bodyA,bodyB);
  1339. break;
  1340. default:
  1341. throw new Error('Bounding volume type not recognized: '+this.boundingVolumeType);
  1342. }
  1343. return result;
  1344. };
  1345. /**
  1346. * Check whether two bodies are allowed to collide at all.
  1347. * @method canCollide
  1348. * @param {Body} bodyA
  1349. * @param {Body} bodyB
  1350. * @return {Boolean}
  1351. */
  1352. Broadphase.canCollide = function(bodyA, bodyB){
  1353. // Cannot collide static bodies
  1354. if(bodyA.motionState === Body.STATIC && bodyB.motionState === Body.STATIC){
  1355. return false;
  1356. }
  1357. // Cannot collide static vs kinematic bodies
  1358. if( (bodyA.motionState === Body.KINEMATIC && bodyB.motionState === Body.STATIC) ||
  1359. (bodyA.motionState === Body.STATIC && bodyB.motionState === Body.KINEMATIC)){
  1360. return false;
  1361. }
  1362. // Cannot collide kinematic vs kinematic
  1363. if(bodyA.motionState === Body.KINEMATIC && bodyB.motionState === Body.KINEMATIC){
  1364. return false;
  1365. }
  1366. // Cannot collide both sleeping bodies
  1367. if(bodyA.sleepState === Body.SLEEPING && bodyB.sleepState === Body.SLEEPING){
  1368. return false;
  1369. }
  1370. // Cannot collide if one is static and the other is sleeping
  1371. if( (bodyA.sleepState === Body.SLEEPING && bodyB.motionState === Body.STATIC) ||
  1372. (bodyB.sleepState === Body.SLEEPING && bodyA.motionState === Body.STATIC)){
  1373. return false;
  1374. }
  1375. return true;
  1376. };
  1377. Broadphase.NAIVE = 1;
  1378. Broadphase.SAP = 2;
  1379. },{"../math/vec2":30,"../objects/Body":31}],10:[function(require,module,exports){
  1380. var Circle = require('../shapes/Circle')
  1381. , Plane = require('../shapes/Plane')
  1382. , Particle = require('../shapes/Particle')
  1383. , Broadphase = require('../collision/Broadphase')
  1384. , vec2 = require('../math/vec2')
  1385. , Utils = require('../utils/Utils')
  1386. module.exports = GridBroadphase;
  1387. /**
  1388. * Broadphase that uses axis-aligned bins.
  1389. * @class GridBroadphase
  1390. * @constructor
  1391. * @extends Broadphase
  1392. * @param {object} [options]
  1393. * @param {number} [options.xmin] Lower x bound of the grid
  1394. * @param {number} [options.xmax] Upper x bound
  1395. * @param {number} [options.ymin] Lower y bound
  1396. * @param {number} [options.ymax] Upper y bound
  1397. * @param {number} [options.nx] Number of bins along x axis
  1398. * @param {number} [options.ny] Number of bins along y axis
  1399. * @todo Should have an option for dynamic scene size
  1400. */
  1401. function GridBroadphase(options){
  1402. options = options || {};
  1403. Broadphase.apply(this);
  1404. Utils.extend(options,{
  1405. xmin: -100,
  1406. xmax: 100,
  1407. ymin: -100,
  1408. ymax: 100,
  1409. nx: 10,
  1410. ny: 10
  1411. });
  1412. this.xmin = options.xmin;
  1413. this.ymin = options.ymin;
  1414. this.xmax = options.xmax;
  1415. this.ymax = options.ymax;
  1416. this.nx = options.nx;
  1417. this.ny = options.ny;
  1418. this.binsizeX = (this.xmax-this.xmin) / this.nx;
  1419. this.binsizeY = (this.ymax-this.ymin) / this.ny;
  1420. }
  1421. GridBroadphase.prototype = new Broadphase();
  1422. /**
  1423. * Get collision pairs.
  1424. * @method getCollisionPairs
  1425. * @param {World} world
  1426. * @return {Array}
  1427. */
  1428. GridBroadphase.prototype.getCollisionPairs = function(world){
  1429. var result = [],
  1430. bodies = world.bodies,
  1431. Ncolliding = bodies.length,
  1432. binsizeX = this.binsizeX,
  1433. binsizeY = this.binsizeY,
  1434. nx = this.nx,
  1435. ny = this.ny,
  1436. xmin = this.xmin,
  1437. ymin = this.ymin,
  1438. xmax = this.xmax,
  1439. ymax = this.ymax;
  1440. // Todo: make garbage free
  1441. var bins=[], Nbins=nx*ny;
  1442. for(var i=0; i<Nbins; i++){
  1443. bins.push([]);
  1444. }
  1445. var xmult = nx / (xmax-xmin);
  1446. var ymult = ny / (ymax-ymin);
  1447. // Put all bodies into bins
  1448. for(var i=0; i!==Ncolliding; i++){
  1449. var bi = bodies[i];
  1450. var aabb = bi.aabb;
  1451. var lowerX = Math.max(aabb.lowerBound[0], xmin);
  1452. var lowerY = Math.max(aabb.lowerBound[1], ymin);
  1453. var upperX = Math.min(aabb.upperBound[0], xmax);
  1454. var upperY = Math.min(aabb.upperBound[1], ymax);
  1455. var xi1 = Math.floor(xmult * (lowerX - xmin));
  1456. var yi1 = Math.floor(ymult * (lowerY - ymin));
  1457. var xi2 = Math.floor(xmult * (upperX - xmin));
  1458. var yi2 = Math.floor(ymult * (upperY - ymin));
  1459. // Put in bin
  1460. for(var j=xi1; j<=xi2; j++){
  1461. for(var k=yi1; k<=yi2; k++){
  1462. var xi = j;
  1463. var yi = k;
  1464. var idx = xi*(ny-1) + yi;
  1465. if(idx >= 0 && idx < Nbins){
  1466. bins[ idx ].push(bi);
  1467. }
  1468. }
  1469. }
  1470. }
  1471. // Check each bin
  1472. for(var i=0; i!==Nbins; i++){
  1473. var bin = bins[i];
  1474. for(var j=0, NbodiesInBin=bin.length; j!==NbodiesInBin; j++){
  1475. var bi = bin[j];
  1476. for(var k=0; k!==j; k++){
  1477. var bj = bin[k];
  1478. if(Broadphase.canCollide(bi,bj) && this.boundingVolumeCheck(bi,bj)){
  1479. result.push(bi,bj);
  1480. }
  1481. }
  1482. }
  1483. }
  1484. return result;
  1485. };
  1486. },{"../collision/Broadphase":9,"../math/vec2":30,"../shapes/Circle":35,"../shapes/Particle":39,"../shapes/Plane":40,"../utils/Utils":45}],11:[function(require,module,exports){
  1487. var Circle = require('../shapes/Circle'),
  1488. Plane = require('../shapes/Plane'),
  1489. Shape = require('../shapes/Shape'),
  1490. Particle = require('../shapes/Particle'),
  1491. Broadphase = require('../collision/Broadphase'),
  1492. vec2 = require('../math/vec2');
  1493. module.exports = NaiveBroadphase;
  1494. /**
  1495. * Naive broadphase implementation. Does N^2 tests.
  1496. *
  1497. * @class NaiveBroadphase
  1498. * @constructor
  1499. * @extends Broadphase
  1500. */
  1501. function NaiveBroadphase(){
  1502. Broadphase.call(this, Broadphase.NAIVE);
  1503. }
  1504. NaiveBroadphase.prototype = new Broadphase();
  1505. /**
  1506. * Get the colliding pairs
  1507. * @method getCollisionPairs
  1508. * @param {World} world
  1509. * @return {Array}
  1510. */
  1511. NaiveBroadphase.prototype.getCollisionPairs = function(world){
  1512. var bodies = world.bodies,
  1513. result = this.result;
  1514. result.length = 0;
  1515. for(var i=0, Ncolliding=bodies.length; i!==Ncolliding; i++){
  1516. var bi = bodies[i];
  1517. for(var j=0; j<i; j++){
  1518. var bj = bodies[j];
  1519. if(Broadphase.canCollide(bi,bj) && this.boundingVolumeCheck(bi,bj)){
  1520. result.push(bi,bj);
  1521. }
  1522. }
  1523. }
  1524. return result;
  1525. };
  1526. },{"../collision/Broadphase":9,"../math/vec2":30,"../shapes/Circle":35,"../shapes/Particle":39,"../shapes/Plane":40,"../shapes/Shape":42}],12:[function(require,module,exports){
  1527. var vec2 = require('../math/vec2')
  1528. , sub = vec2.sub
  1529. , add = vec2.add
  1530. , dot = vec2.dot
  1531. , Utils = require('../utils/Utils')
  1532. , ContactEquation = require('../equations/ContactEquation')
  1533. , FrictionEquation = require('../equations/FrictionEquation')
  1534. , Circle = require('../shapes/Circle')
  1535. , Shape = require('../shapes/Shape')
  1536. , Body = require('../objects/Body')
  1537. , Rectangle = require('../shapes/Rectangle')
  1538. module.exports = Narrowphase;
  1539. // Temp things
  1540. var yAxis = vec2.fromValues(0,1);
  1541. var tmp1 = vec2.fromValues(0,0)
  1542. , tmp2 = vec2.fromValues(0,0)
  1543. , tmp3 = vec2.fromValues(0,0)
  1544. , tmp4 = vec2.fromValues(0,0)
  1545. , tmp5 = vec2.fromValues(0,0)
  1546. , tmp6 = vec2.fromValues(0,0)
  1547. , tmp7 = vec2.fromValues(0,0)
  1548. , tmp8 = vec2.fromValues(0,0)
  1549. , tmp9 = vec2.fromValues(0,0)
  1550. , tmp10 = vec2.fromValues(0,0)
  1551. , tmp11 = vec2.fromValues(0,0)
  1552. , tmp12 = vec2.fromValues(0,0)
  1553. , tmp13 = vec2.fromValues(0,0)
  1554. , tmp14 = vec2.fromValues(0,0)
  1555. , tmp15 = vec2.fromValues(0,0)
  1556. , tmp16 = vec2.fromValues(0,0)
  1557. , tmp17 = vec2.fromValues(0,0)
  1558. , tmp18 = vec2.fromValues(0,0)
  1559. , tmpArray = []
  1560. /**
  1561. * Narrowphase. Creates contacts and friction given shapes and transforms.
  1562. * @class Narrowphase
  1563. * @constructor
  1564. */
  1565. function Narrowphase(){
  1566. /**
  1567. * @property contactEquations
  1568. * @type {Array}
  1569. */
  1570. this.contactEquations = [];
  1571. /**
  1572. * @property frictionEquations
  1573. * @type {Array}
  1574. */
  1575. this.frictionEquations = [];
  1576. /**
  1577. * Whether to make friction equations in the upcoming contacts.
  1578. * @property enableFriction
  1579. * @type {Boolean}
  1580. */
  1581. this.enableFriction = true;
  1582. /**
  1583. * The friction slip force to use when creating friction equations.
  1584. * @property slipForce
  1585. * @type {Number}
  1586. */
  1587. this.slipForce = 10.0;
  1588. /**
  1589. * The friction value to use in the upcoming friction equations.
  1590. * @property frictionCoefficient
  1591. * @type {Number}
  1592. */
  1593. this.frictionCoefficient = 0.3;
  1594. /**
  1595. * Will be the .relativeVelocity in each produced FrictionEquation.
  1596. * @property {Number} surfaceVelocity
  1597. */
  1598. this.surfaceVelocity = 0;
  1599. this.reuseObjects = true;
  1600. this.reusableContactEquations = [];
  1601. this.reusableFrictionEquations = [];
  1602. /**
  1603. * The restitution value to use in the next contact equations.
  1604. * @property restitution
  1605. * @type {Number}
  1606. */
  1607. this.restitution = 0;
  1608. /**
  1609. * The stiffness value to use in the next contact equations.
  1610. * @property {Number} stiffness
  1611. */
  1612. this.stiffness = 1e7;
  1613. /**
  1614. * The stiffness value to use in the next contact equations.
  1615. * @property {Number} stiffness
  1616. */
  1617. this.relaxation = 3;
  1618. /**
  1619. * The stiffness value to use in the next friction equations.
  1620. * @property frictionStiffness
  1621. * @type {Number}
  1622. */
  1623. this.frictionStiffness = 1e7;
  1624. /**
  1625. * The relaxation value to use in the next friction equations.
  1626. * @property frictionRelaxation
  1627. * @type {Number}
  1628. */
  1629. this.frictionRelaxation = 3;
  1630. // Keep track of the colliding bodies last step
  1631. this.collidingBodiesLastStep = { keys:[] };
  1632. };
  1633. /**
  1634. * Check if the bodies were in contact since the last reset().
  1635. * @method collidedLastStep
  1636. * @param {Body} bi
  1637. * @param {Body} bj
  1638. * @return {Boolean}
  1639. */
  1640. Narrowphase.prototype.collidedLastStep = function(bi,bj){
  1641. var id1 = bi.id,
  1642. id2 = bj.id;
  1643. if(id1 > id2){
  1644. var tmp = id1;
  1645. id1 = id2;
  1646. id2 = tmp;
  1647. }
  1648. return !!this.collidingBodiesLastStep[id1 + " " + id2];
  1649. };
  1650. // "for in" loops aren't optimised in chrome... is there a better way to handle last-step collision memory?
  1651. // Maybe do this: http://jsperf.com/reflection-vs-array-of-keys
  1652. function clearObject(obj){
  1653. for(var i = 0, l = obj.keys.length; i < l; i++) {
  1654. delete obj[obj.keys[i]];
  1655. }
  1656. obj.keys.length = 0;
  1657. /*
  1658. for(var key in this.collidingBodiesLastStep)
  1659. delete this.collidingBodiesLastStep[key];
  1660. */
  1661. }
  1662. /**
  1663. * Throws away the old equations and gets ready to create new
  1664. * @method reset
  1665. * @param {World} world
  1666. */
  1667. Narrowphase.prototype.reset = function(world){
  1668. // Save the colliding bodies data
  1669. clearObject(this.collidingBodiesLastStep);
  1670. for(var i=0; i!==this.contactEquations.length; i++){
  1671. var eq = this.contactEquations[i],
  1672. id1 = eq.bodyA.id,
  1673. id2 = eq.bodyB.id;
  1674. if(id1 > id2){
  1675. var tmp = id1;
  1676. id1 = id2;
  1677. id2 = tmp;
  1678. }
  1679. var key = id1 + " " + id2;
  1680. if(!this.collidingBodiesLastStep[key]){
  1681. this.collidingBodiesLastStep[key] = true;
  1682. this.collidingBodiesLastStep.keys.push(key);
  1683. }
  1684. }
  1685. if(this.reuseObjects){
  1686. var ce = this.contactEquations,
  1687. fe = this.frictionEquations,
  1688. rfe = this.reusableFrictionEquations,
  1689. rce = this.reusableContactEquations;
  1690. Utils.appendArray(rce,ce);
  1691. Utils.appendArray(rfe,fe);
  1692. }
  1693. // Reset
  1694. this.contactEquations.length = this.frictionEquations.length = 0;
  1695. };
  1696. /**
  1697. * Creates a ContactEquation, either by reusing an existing object or creating a new one.
  1698. * @method createContactEquation
  1699. * @param {Body} bodyA
  1700. * @param {Body} bodyB
  1701. * @return {ContactEquation}
  1702. */
  1703. Narrowphase.prototype.createContactEquation = function(bodyA,bodyB,shapeA,shapeB){
  1704. var c = this.reusableContactEquations.length ? this.reusableContactEquations.pop() : new ContactEquation(bodyA,bodyB);
  1705. c.bodyA = bodyA;
  1706. c.bodyB = bodyB;
  1707. c.shapeA = shapeA;
  1708. c.shapeB = shapeB;
  1709. c.restitution = this.restitution;
  1710. c.firstImpact = !this.collidedLastStep(bodyA,bodyB);
  1711. c.stiffness = this.stiffness;
  1712. c.relaxation = this.relaxation;
  1713. c.needsUpdate = true;
  1714. c.enabled = true;
  1715. return c;
  1716. };
  1717. /**
  1718. * Creates a FrictionEquation, either by reusing an existing object or creating a new one.
  1719. * @method createFrictionEquation
  1720. * @param {Body} bodyA
  1721. * @param {Body} bodyB
  1722. * @return {FrictionEquation}
  1723. */
  1724. Narrowphase.prototype.createFrictionEquation = function(bodyA,bodyB,shapeA,shapeB){
  1725. var c = this.reusableFrictionEquations.length ? this.reusableFrictionEquations.pop() : new FrictionEquation(bodyA,bodyB);
  1726. c.bodyA = bodyA;
  1727. c.bodyB = bodyB;
  1728. c.shapeA = shapeA;
  1729. c.shapeB = shapeB;
  1730. c.setSlipForce(this.slipForce);
  1731. c.frictionCoefficient = this.frictionCoefficient;
  1732. c.relativeVelocity = this.surfaceVelocity;
  1733. c.enabled = true;
  1734. c.needsUpdate = true;
  1735. c.stiffness = this.frictionStiffness;
  1736. c.relaxation = this.frictionRelaxation;
  1737. return c;
  1738. };
  1739. /**
  1740. * Creates a FrictionEquation given the data in the ContactEquation. Uses same offset vectors ri and rj, but the tangent vector will be constructed from the collision normal.
  1741. * @method createFrictionFromContact
  1742. * @param {ContactEquation} contactEquation
  1743. * @return {FrictionEquation}
  1744. */
  1745. Narrowphase.prototype.createFrictionFromContact = function(c){
  1746. var eq = this.createFrictionEquation(c.bodyA, c.bodyB, c.shapeA, c.shapeB);
  1747. vec2.copy(eq.contactPointA, c.contactPointA);
  1748. vec2.copy(eq.contactPointB, c.contactPointB);
  1749. vec2.rotate(eq.t, c.normalA, -Math.PI / 2);
  1750. eq.contactEquation = c;
  1751. return eq;
  1752. };
  1753. /**
  1754. * Convex/line narrowphase
  1755. * @method convexLine
  1756. * @param {Body} bi
  1757. * @param {Convex} si
  1758. * @param {Array} xi
  1759. * @param {Number} ai
  1760. * @param {Body} bj
  1761. * @param {Line} sj
  1762. * @param {Array} xj
  1763. * @param {Number} aj
  1764. * @todo Implement me!
  1765. */
  1766. Narrowphase.prototype[Shape.LINE | Shape.CONVEX] =
  1767. Narrowphase.prototype.convexLine = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1768. // TODO
  1769. if(justTest)
  1770. return false;
  1771. else
  1772. return 0;
  1773. };
  1774. /**
  1775. * Line/rectangle narrowphase
  1776. * @method lineRectangle
  1777. * @param {Body} bi
  1778. * @param {Line} si
  1779. * @param {Array} xi
  1780. * @param {Number} ai
  1781. * @param {Body} bj
  1782. * @param {Rectangle} sj
  1783. * @param {Array} xj
  1784. * @param {Number} aj
  1785. * @todo Implement me!
  1786. */
  1787. Narrowphase.prototype[Shape.LINE | Shape.RECTANGLE] =
  1788. Narrowphase.prototype.lineRectangle = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1789. // TODO
  1790. if(justTest)
  1791. return false;
  1792. else
  1793. return 0;
  1794. };
  1795. function setConvexToCapsuleShapeMiddle(convexShape, capsuleShape){
  1796. vec2.set(convexShape.vertices[0], -capsuleShape.length * 0.5, -capsuleShape.radius);
  1797. vec2.set(convexShape.vertices[1], capsuleShape.length * 0.5, -capsuleShape.radius);
  1798. vec2.set(convexShape.vertices[2], capsuleShape.length * 0.5, capsuleShape.radius);
  1799. vec2.set(convexShape.vertices[3], -capsuleShape.length * 0.5, capsuleShape.radius);
  1800. }
  1801. var convexCapsule_tempRect = new Rectangle(1,1),
  1802. convexCapsule_tempVec = vec2.create();
  1803. /**
  1804. * Convex/capsule narrowphase
  1805. * @method convexCapsule
  1806. * @param {Body} bi
  1807. * @param {Convex} si
  1808. * @param {Array} xi
  1809. * @param {Number} ai
  1810. * @param {Body} bj
  1811. * @param {Capsule} sj
  1812. * @param {Array} xj
  1813. * @param {Number} aj
  1814. * @todo Implement me!
  1815. */
  1816. Narrowphase.prototype[Shape.CAPSULE | Shape.CONVEX] =
  1817. Narrowphase.prototype[Shape.CAPSULE | Shape.RECTANGLE] =
  1818. Narrowphase.prototype.convexCapsule = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1819. // Check the circles
  1820. // Add offsets!
  1821. var circlePos = convexCapsule_tempVec;
  1822. vec2.set(circlePos, sj.length/2,0);
  1823. vec2.rotate(circlePos,circlePos,aj);
  1824. vec2.add(circlePos,circlePos,xj);
  1825. var result1 = this.circleConvex(bj,sj,circlePos,aj, bi,si,xi,ai, justTest, sj.radius);
  1826. vec2.set(circlePos,-sj.length/2, 0);
  1827. vec2.rotate(circlePos,circlePos,aj);
  1828. vec2.add(circlePos,circlePos,xj);
  1829. var result2 = this.circleConvex(bj,sj,circlePos,aj, bi,si,xi,ai, justTest, sj.radius);
  1830. if(justTest && (result1 || result2))
  1831. return true;
  1832. // Check center rect
  1833. var r = convexCapsule_tempRect;
  1834. setConvexToCapsuleShapeMiddle(r,sj);
  1835. var result = this.convexConvex(bi,si,xi,ai, bj,r,xj,aj, justTest);
  1836. return result + result1 + result2;
  1837. };
  1838. /**
  1839. * Capsule/line narrowphase
  1840. * @method lineCapsule
  1841. * @param {Body} bi
  1842. * @param {Line} si
  1843. * @param {Array} xi
  1844. * @param {Number} ai
  1845. * @param {Body} bj
  1846. * @param {Capsule} sj
  1847. * @param {Array} xj
  1848. * @param {Number} aj
  1849. * @todo Implement me!
  1850. */
  1851. Narrowphase.prototype[Shape.CAPSULE | Shape.LINE] =
  1852. Narrowphase.prototype.lineCapsule = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1853. // TODO
  1854. if(justTest)
  1855. return false;
  1856. else
  1857. return 0;
  1858. };
  1859. var capsuleCapsule_tempVec1 = vec2.create();
  1860. var capsuleCapsule_tempVec2 = vec2.create();
  1861. var capsuleCapsule_tempRect1 = new Rectangle(1,1);
  1862. /**
  1863. * Capsule/capsule narrowphase
  1864. * @method capsuleCapsule
  1865. * @param {Body} bi
  1866. * @param {Capsule} si
  1867. * @param {Array} xi
  1868. * @param {Number} ai
  1869. * @param {Body} bj
  1870. * @param {Capsule} sj
  1871. * @param {Array} xj
  1872. * @param {Number} aj
  1873. * @todo Implement me!
  1874. */
  1875. Narrowphase.prototype[Shape.CAPSULE | Shape.CAPSULE] =
  1876. Narrowphase.prototype.capsuleCapsule = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1877. // Check the circles
  1878. // Add offsets!
  1879. var circlePosi = capsuleCapsule_tempVec1,
  1880. circlePosj = capsuleCapsule_tempVec2;
  1881. var numContacts = 0;
  1882. // Need 4 circle checks, between all
  1883. for(var i=0; i<2; i++){
  1884. vec2.set(circlePosi,(i==0?-1:1)*si.length/2,0);
  1885. vec2.rotate(circlePosi,circlePosi,ai);
  1886. vec2.add(circlePosi,circlePosi,xi);
  1887. for(var j=0; j<2; j++){
  1888. vec2.set(circlePosj,(j==0?-1:1)*sj.length/2, 0);
  1889. vec2.rotate(circlePosj,circlePosj,aj);
  1890. vec2.add(circlePosj,circlePosj,xj);
  1891. var result = this.circleCircle(bi,si,circlePosi,ai, bj,sj,circlePosj,aj, justTest, si.radius, sj.radius);
  1892. if(justTest && result)
  1893. return true;
  1894. numContacts += result;
  1895. }
  1896. }
  1897. // Check circles against the center rectangles
  1898. var rect = capsuleCapsule_tempRect1;
  1899. setConvexToCapsuleShapeMiddle(rect,si);
  1900. var result1 = this.convexCapsule(bi,rect,xi,ai, bj,sj,xj,aj, justTest);
  1901. if(justTest && result1) return true;
  1902. numContacts += result1;
  1903. setConvexToCapsuleShapeMiddle(rect,sj);
  1904. var result2 = this.convexCapsule(bj,rect,xj,aj, bi,si,xi,ai, justTest);
  1905. if(justTest && result2) return true;
  1906. numContacts += result2;
  1907. return numContacts;
  1908. };
  1909. /**
  1910. * Line/line narrowphase
  1911. * @method lineLine
  1912. * @param {Body} bi
  1913. * @param {Line} si
  1914. * @param {Array} xi
  1915. * @param {Number} ai
  1916. * @param {Body} bj
  1917. * @param {Line} sj
  1918. * @param {Array} xj
  1919. * @param {Number} aj
  1920. * @todo Implement me!
  1921. */
  1922. Narrowphase.prototype[Shape.LINE | Shape.LINE] =
  1923. Narrowphase.prototype.lineLine = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  1924. // TODO
  1925. if(justTest)
  1926. return false;
  1927. else
  1928. return 0;
  1929. };
  1930. /**
  1931. * Plane/line Narrowphase
  1932. * @method planeLine
  1933. * @param {Body} planeBody
  1934. * @param {Plane} planeShape
  1935. * @param {Array} planeOffset
  1936. * @param {Number} planeAngle
  1937. * @param {Body} lineBody
  1938. * @param {Line} lineShape
  1939. * @param {Array} lineOffset
  1940. * @param {Number} lineAngle
  1941. */
  1942. Narrowphase.prototype[Shape.PLANE | Shape.LINE] =
  1943. Narrowphase.prototype.planeLine = function(planeBody, planeShape, planeOffset, planeAngle,
  1944. lineBody, lineShape, lineOffset, lineAngle, justTest){
  1945. var worldVertex0 = tmp1,
  1946. worldVertex1 = tmp2,
  1947. worldVertex01 = tmp3,
  1948. worldVertex11 = tmp4,
  1949. worldEdge = tmp5,
  1950. worldEdgeUnit = tmp6,
  1951. dist = tmp7,
  1952. worldNormal = tmp8,
  1953. worldTangent = tmp9,
  1954. verts = tmpArray
  1955. numContacts = 0;
  1956. // Get start and end points
  1957. vec2.set(worldVertex0, -lineShape.length/2, 0);
  1958. vec2.set(worldVertex1, lineShape.length/2, 0);
  1959. // Not sure why we have to use worldVertex*1 here, but it won't work otherwise. Tired.
  1960. vec2.rotate(worldVertex01, worldVertex0, lineAngle);
  1961. vec2.rotate(worldVertex11, worldVertex1, lineAngle);
  1962. add(worldVertex01, worldVertex01, lineOffset);
  1963. add(worldVertex11, worldVertex11, lineOffset);
  1964. vec2.copy(worldVertex0,worldVertex01);
  1965. vec2.copy(worldVertex1,worldVertex11);
  1966. // Get vector along the line
  1967. sub(worldEdge, worldVertex1, worldVertex0);
  1968. vec2.normalize(worldEdgeUnit, worldEdge);
  1969. // Get tangent to the edge.
  1970. vec2.rotate(worldTangent, worldEdgeUnit, -Math.PI/2);
  1971. vec2.rotate(worldNormal, yAxis, planeAngle);
  1972. // Check line ends
  1973. verts[0] = worldVertex0;
  1974. verts[1] = worldVertex1;
  1975. for(var i=0; i<verts.length; i++){
  1976. var v = verts[i];
  1977. sub(dist, v, planeOffset);
  1978. var d = dot(dist,worldNormal);
  1979. if(d < 0){
  1980. if(justTest)
  1981. return true;
  1982. var c = this.createContactEquation(planeBody,lineBody,planeShape,lineShape);
  1983. numContacts++;
  1984. vec2.copy(c.normalA, worldNormal);
  1985. vec2.normalize(c.normalA,c.normalA);
  1986. // distance vector along plane normal
  1987. vec2.scale(dist, worldNormal, d);
  1988. // Vector from plane center to contact
  1989. sub(c.contactPointA, v, dist);
  1990. sub(c.contactPointA, c.contactPointA, planeBody.position);
  1991. // From line center to contact
  1992. sub(c.contactPointB, v, lineOffset);
  1993. add(c.contactPointB, c.contactPointB, lineOffset);
  1994. sub(c.contactPointB, c.contactPointB, lineBody.position);
  1995. this.contactEquations.push(c);
  1996. // TODO : only need one friction equation if both points touch
  1997. if(this.enableFriction){
  1998. this.frictionEquations.push(this.createFrictionFromContact(c));
  1999. }
  2000. }
  2001. }
  2002. return numContacts;
  2003. };
  2004. Narrowphase.prototype[Shape.PARTICLE | Shape.CAPSULE] =
  2005. Narrowphase.prototype.particleCapsule = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  2006. return this.circleLine(bi,si,xi,ai, bj,sj,xj,aj, justTest, sj.radius, 0);
  2007. };
  2008. /**
  2009. * Circle/line Narrowphase
  2010. * @method circleLine
  2011. * @param {Body} bi
  2012. * @param {Circle} si
  2013. * @param {Array} xi
  2014. * @param {Number} ai
  2015. * @param {Body} bj
  2016. * @param {Line} sj
  2017. * @param {Array} xj
  2018. * @param {Number} aj
  2019. * @param {Boolean} justTest If set to true, this function will return the result (intersection or not) without adding equations.
  2020. * @param {Number} lineRadius Radius to add to the line. Can be used to test Capsules.
  2021. * @param {Number} circleRadius If set, this value overrides the circle shape radius.
  2022. */
  2023. Narrowphase.prototype[Shape.CIRCLE | Shape.LINE] =
  2024. Narrowphase.prototype.circleLine = function(bi,si,xi,ai, bj,sj,xj,aj, justTest, lineRadius, circleRadius){
  2025. var lineShape = sj,
  2026. lineAngle = aj,
  2027. lineBody = bj,
  2028. lineOffset = xj,
  2029. circleOffset = xi,
  2030. circleBody = bi,
  2031. circleShape = si,
  2032. lineRadius = lineRadius || 0,
  2033. circleRadius = typeof(circleRadius)!="undefined" ? circleRadius : circleShape.radius,
  2034. orthoDist = tmp1,
  2035. lineToCircleOrthoUnit = tmp2,
  2036. projectedPoint = tmp3,
  2037. centerDist = tmp4,
  2038. worldTangent = tmp5,
  2039. worldEdge = tmp6,
  2040. worldEdgeUnit = tmp7,
  2041. worldVertex0 = tmp8,
  2042. worldVertex1 = tmp9,
  2043. worldVertex01 = tmp10,
  2044. worldVertex11 = tmp11,
  2045. dist = tmp12,
  2046. lineToCircle = tmp13,
  2047. lineEndToLineRadius = tmp14,
  2048. verts = tmpArray;
  2049. // Get start and end points
  2050. vec2.set(worldVertex0, -lineShape.length/2, 0);
  2051. vec2.set(worldVertex1, lineShape.length/2, 0);
  2052. // Not sure why we have to use worldVertex*1 here, but it won't work otherwise. Tired.
  2053. vec2.rotate(worldVertex01, worldVertex0, lineAngle);
  2054. vec2.rotate(worldVertex11, worldVertex1, lineAngle);
  2055. add(worldVertex01, worldVertex01, lineOffset);
  2056. add(worldVertex11, worldVertex11, lineOffset);
  2057. vec2.copy(worldVertex0,worldVertex01);
  2058. vec2.copy(worldVertex1,worldVertex11);
  2059. // Get vector along the line
  2060. sub(worldEdge, worldVertex1, worldVertex0);
  2061. vec2.normalize(worldEdgeUnit, worldEdge);
  2062. // Get tangent to the edge.
  2063. vec2.rotate(worldTangent, worldEdgeUnit, -Math.PI/2);
  2064. // Check distance from the plane spanned by the edge vs the circle
  2065. sub(dist, circleOffset, worldVertex0);
  2066. var d = dot(dist, worldTangent); // Distance from center of line to circle center
  2067. sub(centerDist, worldVertex0, lineOffset);
  2068. sub(lineToCircle, circleOffset, lineOffset);
  2069. if(Math.abs(d) < circleRadius+lineRadius){
  2070. // Now project the circle onto the edge
  2071. vec2.scale(orthoDist, worldTangent, d);
  2072. sub(projectedPoint, circleOffset, orthoDist);
  2073. // Add the missing line radius
  2074. vec2.scale(lineToCircleOrthoUnit, worldTangent, dot(worldTangent, lineToCircle));
  2075. vec2.normalize(lineToCircleOrthoUnit,lineToCircleOrthoUnit);
  2076. vec2.scale(lineToCircleOrthoUnit, lineToCircleOrthoUnit, lineRadius);
  2077. add(projectedPoint,projectedPoint,lineToCircleOrthoUnit);
  2078. // Check if the point is within the edge span
  2079. var pos = dot(worldEdgeUnit, projectedPoint);
  2080. var pos0 = dot(worldEdgeUnit, worldVertex0);
  2081. var pos1 = dot(worldEdgeUnit, worldVertex1);
  2082. if(pos > pos0 && pos < pos1){
  2083. // We got contact!
  2084. if(justTest) return true;
  2085. var c = this.createContactEquation(circleBody,lineBody,si,sj);
  2086. vec2.scale(c.normalA, orthoDist, -1);
  2087. vec2.normalize(c.normalA, c.normalA);
  2088. vec2.scale( c.contactPointA, c.normalA, circleRadius);
  2089. add(c.contactPointA, c.contactPointA, circleOffset);
  2090. sub(c.contactPointA, c.contactPointA, circleBody.position);
  2091. sub(c.contactPointB, projectedPoint, lineOffset);
  2092. add(c.contactPointB, c.contactPointB, lineOffset);
  2093. sub(c.contactPointB, c.contactPointB, lineBody.position);
  2094. this.contactEquations.push(c);
  2095. if(this.enableFriction){
  2096. this.frictionEquations.push(this.createFrictionFromContact(c));
  2097. }
  2098. return 1;
  2099. }
  2100. }
  2101. // Add corner
  2102. // @todo reuse array object
  2103. verts[0] = worldVertex0;
  2104. verts[1] = worldVertex1;
  2105. for(var i=0; i<verts.length; i++){
  2106. var v = verts[i];
  2107. sub(dist, v, circleOffset);
  2108. if(vec2.squaredLength(dist) < (circleRadius+lineRadius)*(circleRadius+lineRadius)){
  2109. if(justTest) return true;
  2110. var c = this.createContactEquation(circleBody,lineBody,si,sj);
  2111. vec2.copy(c.normalA, dist);
  2112. vec2.normalize(c.normalA,c.normalA);
  2113. // Vector from circle to contact point is the normal times the circle radius
  2114. vec2.scale(c.contactPointA, c.normalA, circleRadius);
  2115. add(c.contactPointA, c.contactPointA, circleOffset);
  2116. sub(c.contactPointA, c.contactPointA, circleBody.position);
  2117. sub(c.contactPointB, v, lineOffset);
  2118. vec2.scale(lineEndToLineRadius, c.normalA, -lineRadius);
  2119. add(c.contactPointB, c.contactPointB, lineEndToLineRadius);
  2120. add(c.contactPointB, c.contactPointB, lineOffset);
  2121. sub(c.contactPointB, c.contactPointB, lineBody.position);
  2122. this.contactEquations.push(c);
  2123. if(this.enableFriction){
  2124. this.frictionEquations.push(this.createFrictionFromContact(c));
  2125. }
  2126. return 1;
  2127. }
  2128. }
  2129. return 0;
  2130. };
  2131. /**
  2132. * Circle/capsule Narrowphase
  2133. * @method circleCapsule
  2134. * @param {Body} bi
  2135. * @param {Circle} si
  2136. * @param {Array} xi
  2137. * @param {Number} ai
  2138. * @param {Body} bj
  2139. * @param {Line} sj
  2140. * @param {Array} xj
  2141. * @param {Number} aj
  2142. */
  2143. Narrowphase.prototype[Shape.CIRCLE | Shape.CAPSULE] =
  2144. Narrowphase.prototype.circleCapsule = function(bi,si,xi,ai, bj,sj,xj,aj, justTest){
  2145. return this.circleLine(bi,si,xi,ai, bj,sj,xj,aj, justTest, sj.radius);
  2146. };
  2147. /**
  2148. * Circle/convex Narrowphase
  2149. * @method circleConvex
  2150. * @param {Body} bi
  2151. * @param {Circle} si
  2152. * @param {Array} xi
  2153. * @param {Number} ai
  2154. * @param {Body} bj
  2155. * @param {Convex} sj
  2156. * @param {Array} xj
  2157. * @param {Number} aj
  2158. */
  2159. Narrowphase.prototype[Shape.CIRCLE | Shape.CONVEX] =
  2160. Narrowphase.prototype[Shape.CIRCLE | Shape.RECTANGLE] =
  2161. Narrowphase.prototype.circleConvex = function( bi,si,xi,ai, bj,sj,xj,aj, justTest, circleRadius){
  2162. var convexShape = sj,
  2163. convexAngle = aj,
  2164. convexBody = bj,
  2165. convexOffset = xj,
  2166. circleOffset = xi,
  2167. circleBody = bi,
  2168. circleShape = si,
  2169. circleRadius = typeof(circleRadius)=="number" ? circleRadius : circleShape.radius;
  2170. var worldVertex0 = tmp1,
  2171. worldVertex1 = tmp2,
  2172. worldEdge = tmp3,
  2173. worldEdgeUnit = tmp4,
  2174. worldTangent = tmp5,
  2175. centerDist = tmp6,
  2176. convexToCircle = tmp7,
  2177. orthoDist = tmp8,
  2178. projectedPoint = tmp9,
  2179. dist = tmp10,
  2180. worldVertex = tmp11,
  2181. closestEdge = -1,
  2182. closestEdgeDistance = null,
  2183. closestEdgeOrthoDist = tmp12,
  2184. closestEdgeProjectedPoint = tmp13,
  2185. candidate = tmp14,
  2186. candidateDist = tmp15,
  2187. minCandidate = tmp16,
  2188. found = false,
  2189. minCandidateDistance = Number.MAX_VALUE;
  2190. var numReported = 0;
  2191. // New algorithm:
  2192. // 1. Check so center of circle is not inside the polygon. If it is, this wont work...
  2193. // 2. For each edge
  2194. // 2. 1. Get point on circle that is closest to the edge (scale normal with -radius)
  2195. // 2. 2. Check if point is inside.
  2196. verts = convexShape.vertices;
  2197. // Check all edges first
  2198. for(var i=0; i!==verts.length+1; i++){
  2199. var v0 = verts[i%verts.length],
  2200. v1 = verts[(i+1)%verts.length];
  2201. vec2.rotate(worldVertex0, v0, convexAngle);
  2202. vec2.rotate(worldVertex1, v1, convexAngle);
  2203. add(worldVertex0, worldVertex0, convexOffset);
  2204. add(worldVertex1, worldVertex1, convexOffset);
  2205. sub(worldEdge, worldVertex1, worldVertex0);
  2206. vec2.normalize(worldEdgeUnit, worldEdge);
  2207. // Get tangent to the edge. Points out of the Convex
  2208. vec2.rotate(worldTangent, worldEdgeUnit, -Math.PI/2);
  2209. // Get point on circle, closest to the polygon
  2210. vec2.scale(candidate,worldTangent,-circleShape.radius);
  2211. add(candidate,candidate,circleOffset);
  2212. if(pointInConvex(candidate,convexShape,convexOffset,convexAngle)){
  2213. vec2.sub(candidateDist,worldVertex0,candidate);
  2214. var candidateDistance = Math.abs(vec2.dot(candidateDist,worldTangent));
  2215. /*
  2216. // Check distance from the plane spanned by the edge vs the circle
  2217. sub(dist, circleOffset, worldVertex0);
  2218. var d = dot(dist, worldTangent);
  2219. sub(centerDist, worldVertex0, convexOffset);
  2220. sub(convexToCircle, circleOffset, convexOffset);
  2221. if(d < circleRadius && dot(centerDist,convexToCircle) > 0){
  2222. // Now project the circle onto the edge
  2223. vec2.scale(orthoDist, worldTangent, d);
  2224. sub(projectedPoint, circleOffset, orthoDist);
  2225. // Check if the point is within the edge span
  2226. var pos = dot(worldEdgeUnit, projectedPoint);
  2227. var pos0 = dot(worldEdgeUnit, worldVertex0);
  2228. var pos1 = dot(worldEdgeUnit, worldVertex1);
  2229. if(pos > pos0 && pos < pos1){
  2230. // We got contact!
  2231. if(justTest) return true;
  2232. if(closestEdgeDistance === null || d*d<closestEdgeDistance*closestEdgeDistance){
  2233. closestEdgeDistance = d;
  2234. closestEdge = i;
  2235. vec2.copy(closestEdgeOrthoDist, orthoDist);
  2236. vec2.copy(closestEdgeProjectedPoint, projectedPoint);
  2237. }
  2238. }
  2239. }
  2240. */
  2241. if(candidateDistance < minCandidateDistance){
  2242. vec2.copy(minCandidate,candidate);
  2243. minCandidateDistance = candidateDistance;
  2244. vec2.scale(closestEdgeProjectedPoint,worldTangent,candidateDistance);
  2245. vec2.add(closestEdgeProjectedPoint,closestEdgeProjectedPoint,candidate);
  2246. found = true;
  2247. }
  2248. }
  2249. }
  2250. if(found){
  2251. if(justTest)
  2252. return true;
  2253. var c = this.createContactEquation(circleBody,convexBody,si,sj);
  2254. vec2.sub(c.normalA, minCandidate, circleOffset)
  2255. vec2.normalize(c.normalA, c.normalA);
  2256. vec2.scale(c.contactPointA, c.normalA, circleRadius);
  2257. add(c.contactPointA, c.contactPointA, circleOffset);
  2258. sub(c.contactPointA, c.contactPointA, circleBody.position);
  2259. sub(c.contactPointB, closestEdgeProjectedPoint, convexOffset);
  2260. add(c.contactPointB, c.contactPointB, convexOffset);
  2261. sub(c.contactPointB, c.contactPointB, convexBody.position);
  2262. this.contactEquations.push(c);
  2263. if(this.enableFriction)
  2264. this.frictionEquations.push( this.createFrictionFromContact(c) );
  2265. return 1;
  2266. }
  2267. /*
  2268. if(closestEdge != -1){
  2269. var c = this.createContactEquation(circleBody,convexBody);
  2270. vec2.scale(c.normalA, closestEdgeOrthoDist, -1);
  2271. vec2.normalize(c.normalA, c.normalA);
  2272. vec2.scale(c.contactPointA, c.normalA, circleRadius);
  2273. add(c.contactPointA, c.contactPointA, circleOffset);
  2274. sub(c.contactPointA, c.contactPointA, circleBody.position);
  2275. sub(c.contactPointB, closestEdgeProjectedPoint, convexOffset);
  2276. add(c.contactPointB, c.contactPointB, convexOffset);
  2277. sub(c.contactPointB, c.contactPointB, convexBody.position);
  2278. this.contactEquations.push(c);
  2279. if(this.enableFriction)
  2280. this.frictionEquations.push( this.createFrictionFromContact(c) );
  2281. return true;
  2282. }
  2283. */
  2284. // Check all vertices
  2285. if(circleRadius > 0){
  2286. for(var i=0; i<verts.length; i++){
  2287. var localVertex = verts[i];
  2288. vec2.rotate(worldVertex, localVertex, convexAngle);
  2289. add(worldVertex, worldVertex, convexOffset);
  2290. sub(dist, worldVertex, circleOffset);
  2291. if(vec2.squaredLength(dist) < circleRadius*circleRadius){
  2292. if(justTest) return true;
  2293. var c = this.createContactEquation(circleBody,convexBody,si,sj);
  2294. vec2.copy(c.normalA, dist);
  2295. vec2.normalize(c.normalA,c.normalA);
  2296. // Vector from circle to contact point is the normal times the circle radius
  2297. vec2.scale(c.contactPointA, c.normalA, circleRadius);
  2298. add(c.contactPointA, c.contactPointA, circleOffset);
  2299. sub(c.contactPointA, c.contactPointA, circleBody.position);
  2300. sub(c.contactPointB, worldVertex, convexOffset);
  2301. add(c.contactPointB, c.contactPointB, convexOffset);
  2302. sub(c.contactPointB, c.contactPointB, convexBody.position);
  2303. this.contactEquations.push(c);
  2304. if(this.enableFriction){
  2305. this.frictionEquations.push(this.createFrictionFromContact(c));
  2306. }
  2307. return 1;
  2308. }
  2309. }
  2310. }
  2311. return 0;
  2312. };
  2313. // Check if a point is in a polygon
  2314. var pic_worldVertex0 = vec2.create(),
  2315. pic_worldVertex1 = vec2.create(),
  2316. pic_r0 = vec2.create(),
  2317. pic_r1 = vec2.create();
  2318. function pointInConvex(worldPoint,convexShape,convexOffset,convexAngle){
  2319. var worldVertex0 = pic_worldVertex0,
  2320. worldVertex1 = pic_worldVertex1,
  2321. r0 = pic_r0,
  2322. r1 = pic_r1,
  2323. point = worldPoint,
  2324. verts = convexShape.vertices,
  2325. lastCross = null;
  2326. for(var i=0; i!==verts.length+1; i++){
  2327. var v0 = verts[i%verts.length],
  2328. v1 = verts[(i+1)%verts.length];
  2329. // Transform vertices to world
  2330. // can we instead transform point to local of the convex???
  2331. vec2.rotate(worldVertex0, v0, convexAngle);
  2332. vec2.rotate(worldVertex1, v1, convexAngle);
  2333. add(worldVertex0, worldVertex0, convexOffset);
  2334. add(worldVertex1, worldVertex1, convexOffset);
  2335. sub(r0, worldVertex0, point);
  2336. sub(r1, worldVertex1, point);
  2337. var cross = vec2.crossLength(r0,r1);
  2338. if(lastCross===null) lastCross = cross;
  2339. // If we got a different sign of the distance vector, the point is out of the polygon
  2340. if(cross*lastCross <= 0){
  2341. return false;
  2342. }
  2343. lastCross = cross;
  2344. }
  2345. return true;
  2346. };
  2347. /**
  2348. * Particle/convex Narrowphase
  2349. * @method particleConvex
  2350. * @param {Body} bi
  2351. * @param {Particle} si
  2352. * @param {Array} xi
  2353. * @param {Number} ai
  2354. * @param {Body} bj
  2355. * @param {Convex} sj
  2356. * @param {Array} xj
  2357. * @param {Number} aj
  2358. * @todo use pointInConvex and code more similar to circleConvex
  2359. */
  2360. Narrowphase.prototype[Shape.PARTICLE | Shape.CONVEX] =
  2361. Narrowphase.prototype[Shape.PARTICLE | Shape.RECTANGLE] =
  2362. Narrowphase.prototype.particleConvex = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2363. var convexShape = sj,
  2364. convexAngle = aj,
  2365. convexBody = bj,
  2366. convexOffset = xj,
  2367. particleOffset = xi,
  2368. particleBody = bi,
  2369. particleShape = si,
  2370. worldVertex0 = tmp1,
  2371. worldVertex1 = tmp2,
  2372. worldEdge = tmp3,
  2373. worldEdgeUnit = tmp4,
  2374. worldTangent = tmp5,
  2375. centerDist = tmp6,
  2376. convexToparticle = tmp7,
  2377. orthoDist = tmp8,
  2378. projectedPoint = tmp9,
  2379. dist = tmp10,
  2380. worldVertex = tmp11,
  2381. closestEdge = -1,
  2382. closestEdgeDistance = null,
  2383. closestEdgeOrthoDist = tmp12,
  2384. closestEdgeProjectedPoint = tmp13,
  2385. r0 = tmp14, // vector from particle to vertex0
  2386. r1 = tmp15,
  2387. localPoint = tmp16,
  2388. candidateDist = tmp17,
  2389. minEdgeNormal = tmp18,
  2390. minCandidateDistance = Number.MAX_VALUE;
  2391. var numReported = 0,
  2392. found = false,
  2393. verts = convexShape.vertices;
  2394. // Check if the particle is in the polygon at all
  2395. if(!pointInConvex(particleOffset,convexShape,convexOffset,convexAngle))
  2396. return 0;
  2397. if(justTest) return true;
  2398. // Check edges first
  2399. var lastCross = null;
  2400. for(var i=0; i!==verts.length+1; i++){
  2401. var v0 = verts[i%verts.length],
  2402. v1 = verts[(i+1)%verts.length];
  2403. // Transform vertices to world
  2404. vec2.rotate(worldVertex0, v0, convexAngle);
  2405. vec2.rotate(worldVertex1, v1, convexAngle);
  2406. add(worldVertex0, worldVertex0, convexOffset);
  2407. add(worldVertex1, worldVertex1, convexOffset);
  2408. // Get world edge
  2409. sub(worldEdge, worldVertex1, worldVertex0);
  2410. vec2.normalize(worldEdgeUnit, worldEdge);
  2411. // Get tangent to the edge. Points out of the Convex
  2412. vec2.rotate(worldTangent, worldEdgeUnit, -Math.PI/2);
  2413. // Check distance from the infinite line (spanned by the edge) to the particle
  2414. sub(dist, particleOffset, worldVertex0);
  2415. var d = dot(dist, worldTangent);
  2416. sub(centerDist, worldVertex0, convexOffset);
  2417. sub(convexToparticle, particleOffset, convexOffset);
  2418. /*
  2419. if(d < 0 && dot(centerDist,convexToparticle) >= 0){
  2420. // Now project the particle onto the edge
  2421. vec2.scale(orthoDist, worldTangent, d);
  2422. sub(projectedPoint, particleOffset, orthoDist);
  2423. // Check if the point is within the edge span
  2424. var pos = dot(worldEdgeUnit, projectedPoint);
  2425. var pos0 = dot(worldEdgeUnit, worldVertex0);
  2426. var pos1 = dot(worldEdgeUnit, worldVertex1);
  2427. if(pos > pos0 && pos < pos1){
  2428. // We got contact!
  2429. if(justTest) return true;
  2430. if(closestEdgeDistance === null || d*d<closestEdgeDistance*closestEdgeDistance){
  2431. closestEdgeDistance = d;
  2432. closestEdge = i;
  2433. vec2.copy(closestEdgeOrthoDist, orthoDist);
  2434. vec2.copy(closestEdgeProjectedPoint, projectedPoint);
  2435. }
  2436. }
  2437. }
  2438. */
  2439. vec2.sub(candidateDist,worldVertex0,particleOffset);
  2440. var candidateDistance = Math.abs(vec2.dot(candidateDist,worldTangent));
  2441. if(candidateDistance < minCandidateDistance){
  2442. minCandidateDistance = candidateDistance;
  2443. vec2.scale(closestEdgeProjectedPoint,worldTangent,candidateDistance);
  2444. vec2.add(closestEdgeProjectedPoint,closestEdgeProjectedPoint,particleOffset);
  2445. vec2.copy(minEdgeNormal,worldTangent);
  2446. found = true;
  2447. }
  2448. }
  2449. if(found){
  2450. var c = this.createContactEquation(particleBody,convexBody,si,sj);
  2451. vec2.scale(c.normalA, minEdgeNormal, -1);
  2452. vec2.normalize(c.normalA, c.normalA);
  2453. // Particle has no extent to the contact point
  2454. vec2.set(c.contactPointA, 0, 0);
  2455. add(c.contactPointA, c.contactPointA, particleOffset);
  2456. sub(c.contactPointA, c.contactPointA, particleBody.position);
  2457. // From convex center to point
  2458. sub(c.contactPointB, closestEdgeProjectedPoint, convexOffset);
  2459. add(c.contactPointB, c.contactPointB, convexOffset);
  2460. sub(c.contactPointB, c.contactPointB, convexBody.position);
  2461. this.contactEquations.push(c);
  2462. if(this.enableFriction)
  2463. this.frictionEquations.push( this.createFrictionFromContact(c) );
  2464. return 1;
  2465. }
  2466. return 0;
  2467. };
  2468. /**
  2469. * Circle/circle Narrowphase
  2470. * @method circleCircle
  2471. * @param {Body} bi
  2472. * @param {Circle} si
  2473. * @param {Array} xi
  2474. * @param {Number} ai
  2475. * @param {Body} bj
  2476. * @param {Circle} sj
  2477. * @param {Array} xj
  2478. * @param {Number} aj
  2479. */
  2480. Narrowphase.prototype[Shape.CIRCLE] =
  2481. Narrowphase.prototype.circleCircle = function( bi,si,xi,ai, bj,sj,xj,aj, justTest, radiusA, radiusB){
  2482. var bodyA = bi,
  2483. shapeA = si,
  2484. offsetA = xi,
  2485. bodyB = bj,
  2486. shapeB = sj,
  2487. offsetB = xj,
  2488. dist = tmp1,
  2489. radiusA = radiusA || shapeA.radius,
  2490. radiusB = radiusB || shapeB.radius;
  2491. sub(dist,xi,xj);
  2492. var r = radiusA + radiusB;
  2493. if(vec2.squaredLength(dist) > r*r){
  2494. return 0;
  2495. }
  2496. if(justTest){
  2497. return true;
  2498. }
  2499. var c = this.createContactEquation(bodyA,bodyB,si,sj);
  2500. sub(c.normalA, offsetB, offsetA);
  2501. vec2.normalize(c.normalA,c.normalA);
  2502. vec2.scale( c.contactPointA, c.normalA, radiusA);
  2503. vec2.scale( c.contactPointB, c.normalA, -radiusB);
  2504. add(c.contactPointA, c.contactPointA, offsetA);
  2505. sub(c.contactPointA, c.contactPointA, bodyA.position);
  2506. add(c.contactPointB, c.contactPointB, offsetB);
  2507. sub(c.contactPointB, c.contactPointB, bodyB.position);
  2508. this.contactEquations.push(c);
  2509. if(this.enableFriction){
  2510. this.frictionEquations.push(this.createFrictionFromContact(c));
  2511. }
  2512. return 1;
  2513. };
  2514. /**
  2515. * Plane/Convex Narrowphase
  2516. * @method planeConvex
  2517. * @param {Body} bi
  2518. * @param {Plane} si
  2519. * @param {Array} xi
  2520. * @param {Number} ai
  2521. * @param {Body} bj
  2522. * @param {Convex} sj
  2523. * @param {Array} xj
  2524. * @param {Number} aj
  2525. */
  2526. Narrowphase.prototype[Shape.PLANE | Shape.CONVEX] =
  2527. Narrowphase.prototype[Shape.PLANE | Shape.RECTANGLE] =
  2528. Narrowphase.prototype.planeConvex = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2529. var convexBody = bj,
  2530. convexOffset = xj,
  2531. convexShape = sj,
  2532. convexAngle = aj,
  2533. planeBody = bi,
  2534. planeShape = si,
  2535. planeOffset = xi,
  2536. planeAngle = ai;
  2537. var worldVertex = tmp1,
  2538. worldNormal = tmp2,
  2539. dist = tmp3;
  2540. var numReported = 0;
  2541. vec2.rotate(worldNormal, yAxis, planeAngle);
  2542. for(var i=0; i<convexShape.vertices.length; i++){
  2543. var v = convexShape.vertices[i];
  2544. vec2.rotate(worldVertex, v, convexAngle);
  2545. add(worldVertex, worldVertex, convexOffset);
  2546. sub(dist, worldVertex, planeOffset);
  2547. if(dot(dist,worldNormal) <= Narrowphase.convexPrecision){
  2548. if(justTest){
  2549. return true;
  2550. }
  2551. // Found vertex
  2552. numReported++;
  2553. var c = this.createContactEquation(planeBody,convexBody,planeShape,convexShape);
  2554. sub(dist, worldVertex, planeOffset);
  2555. vec2.copy(c.normalA, worldNormal);
  2556. var d = dot(dist, c.normalA);
  2557. vec2.scale(dist, c.normalA, d);
  2558. // rj is from convex center to contact
  2559. sub(c.contactPointB, worldVertex, convexBody.position);
  2560. // ri is from plane center to contact
  2561. sub( c.contactPointA, worldVertex, dist);
  2562. sub( c.contactPointA, c.contactPointA, planeBody.position);
  2563. this.contactEquations.push(c);
  2564. if(this.enableFriction){
  2565. this.frictionEquations.push(this.createFrictionFromContact(c));
  2566. }
  2567. }
  2568. }
  2569. return numReported;
  2570. };
  2571. /**
  2572. * @method convexPlane
  2573. * @deprecated Use .planeConvex() instead!
  2574. */
  2575. Narrowphase.prototype.convexPlane = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2576. console.warn("Narrowphase.prototype.convexPlane is deprecated. Use planeConvex instead!");
  2577. return this.planeConvex( bj,sj,xj,aj, bi,si,xi,ai, justTest );
  2578. }
  2579. /**
  2580. * Narrowphase for particle vs plane
  2581. * @method particlePlane
  2582. * @param {Body} bi The particle body
  2583. * @param {Particle} si Particle shape
  2584. * @param {Array} xi World position for the particle
  2585. * @param {Number} ai World angle for the particle
  2586. * @param {Body} bj Plane body
  2587. * @param {Plane} sj Plane shape
  2588. * @param {Array} xj World position for the plane
  2589. * @param {Number} aj World angle for the plane
  2590. */
  2591. Narrowphase.prototype[Shape.PARTICLE | Shape.PLANE] =
  2592. Narrowphase.prototype.particlePlane = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2593. var particleBody = bi,
  2594. particleShape = si,
  2595. particleOffset = xi,
  2596. planeBody = bj,
  2597. planeShape = sj,
  2598. planeOffset = xj,
  2599. planeAngle = aj;
  2600. var dist = tmp1,
  2601. worldNormal = tmp2;
  2602. planeAngle = planeAngle || 0;
  2603. sub(dist, particleOffset, planeOffset);
  2604. vec2.rotate(worldNormal, yAxis, planeAngle);
  2605. var d = dot(dist, worldNormal);
  2606. if(d > 0) return 0;
  2607. if(justTest) return true;
  2608. var c = this.createContactEquation(planeBody,particleBody,sj,si);
  2609. vec2.copy(c.normalA, worldNormal);
  2610. vec2.scale( dist, c.normalA, d );
  2611. // dist is now the distance vector in the normal direction
  2612. // ri is the particle position projected down onto the plane, from the plane center
  2613. sub( c.contactPointA, particleOffset, dist);
  2614. sub( c.contactPointA, c.contactPointA, planeBody.position);
  2615. // rj is from the body center to the particle center
  2616. sub( c.contactPointB, particleOffset, particleBody.position );
  2617. this.contactEquations.push(c);
  2618. if(this.enableFriction){
  2619. this.frictionEquations.push(this.createFrictionFromContact(c));
  2620. }
  2621. return 1;
  2622. };
  2623. /**
  2624. * Circle/Particle Narrowphase
  2625. * @method circleParticle
  2626. * @param {Body} bi
  2627. * @param {Circle} si
  2628. * @param {Array} xi
  2629. * @param {Number} ai
  2630. * @param {Body} bj
  2631. * @param {Particle} sj
  2632. * @param {Array} xj
  2633. * @param {Number} aj
  2634. */
  2635. Narrowphase.prototype[Shape.CIRCLE | Shape.PARTICLE] =
  2636. Narrowphase.prototype.circleParticle = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2637. var circleBody = bi,
  2638. circleShape = si,
  2639. circleOffset = xi,
  2640. particleBody = bj,
  2641. particleShape = sj,
  2642. particleOffset = xj,
  2643. dist = tmp1;
  2644. sub(dist, particleOffset, circleOffset);
  2645. if(vec2.squaredLength(dist) > circleShape.radius*circleShape.radius) return 0;
  2646. if(justTest) return true;
  2647. var c = this.createContactEquation(circleBody,particleBody,si,sj);
  2648. vec2.copy(c.normalA, dist);
  2649. vec2.normalize(c.normalA,c.normalA);
  2650. // Vector from circle to contact point is the normal times the circle radius
  2651. vec2.scale(c.contactPointA, c.normalA, circleShape.radius);
  2652. add(c.contactPointA, c.contactPointA, circleOffset);
  2653. sub(c.contactPointA, c.contactPointA, circleBody.position);
  2654. // Vector from particle center to contact point is zero
  2655. sub(c.contactPointB, particleOffset, particleBody.position);
  2656. this.contactEquations.push(c);
  2657. if(this.enableFriction){
  2658. this.frictionEquations.push(this.createFrictionFromContact(c));
  2659. }
  2660. return 1;
  2661. };
  2662. var capsulePlane_tmpCircle = new Circle(1),
  2663. capsulePlane_tmp1 = vec2.create(),
  2664. capsulePlane_tmp2 = vec2.create(),
  2665. capsulePlane_tmp3 = vec2.create();
  2666. Narrowphase.prototype[Shape.PLANE | Shape.CAPSULE] =
  2667. Narrowphase.prototype.planeCapsule = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2668. var end1 = capsulePlane_tmp1,
  2669. end2 = capsulePlane_tmp2,
  2670. circle = capsulePlane_tmpCircle,
  2671. dst = capsulePlane_tmp3;
  2672. // Compute world end positions
  2673. vec2.set(end1, -sj.length/2, 0);
  2674. vec2.rotate(end1,end1,aj);
  2675. add(end1,end1,xj);
  2676. vec2.set(end2, sj.length/2, 0);
  2677. vec2.rotate(end2,end2,aj);
  2678. add(end2,end2,xj);
  2679. circle.radius = sj.radius;
  2680. // Do Narrowphase as two circles
  2681. var numContacts1 = this.circlePlane(bj,circle,end1,0, bi,si,xi,ai, justTest),
  2682. numContacts2 = this.circlePlane(bj,circle,end2,0, bi,si,xi,ai, justTest);
  2683. if(justTest)
  2684. return numContacts1 || numContacts2;
  2685. else
  2686. return numContacts1 + numContacts2;
  2687. };
  2688. /**
  2689. * @method capsulePlane
  2690. * @deprecated Use .planeCapsule() instead!
  2691. */
  2692. Narrowphase.prototype.capsulePlane = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2693. console.warn("Narrowphase.prototype.capsulePlane() is deprecated. Use .planeCapsule() instead!");
  2694. return this.planeCapsule( bj,sj,xj,aj, bi,si,xi,ai, justTest );
  2695. }
  2696. /**
  2697. * Creates ContactEquations and FrictionEquations for a collision.
  2698. * @method circlePlane
  2699. * @param {Body} bi The first body that should be connected to the equations.
  2700. * @param {Circle} si The circle shape participating in the collision.
  2701. * @param {Array} xi Extra offset to take into account for the Shape, in addition to the one in circleBody.position. Will *not* be rotated by circleBody.angle (maybe it should, for sake of homogenity?). Set to null if none.
  2702. * @param {Body} bj The second body that should be connected to the equations.
  2703. * @param {Plane} sj The Plane shape that is participating
  2704. * @param {Array} xj Extra offset for the plane shape.
  2705. * @param {Number} aj Extra angle to apply to the plane
  2706. */
  2707. Narrowphase.prototype[Shape.CIRCLE | Shape.PLANE] =
  2708. Narrowphase.prototype.circlePlane = function( bi,si,xi,ai, bj,sj,xj,aj, justTest ){
  2709. var circleBody = bi,
  2710. circleShape = si,
  2711. circleOffset = xi, // Offset from body center, rotated!
  2712. planeBody = bj,
  2713. shapeB = sj,
  2714. planeOffset = xj,
  2715. planeAngle = aj;
  2716. planeAngle = planeAngle || 0;
  2717. // Vector from plane to circle
  2718. var planeToCircle = tmp1,
  2719. worldNormal = tmp2,
  2720. temp = tmp3;
  2721. sub(planeToCircle, circleOffset, planeOffset);
  2722. // World plane normal
  2723. vec2.rotate(worldNormal, yAxis, planeAngle);
  2724. // Normal direction distance
  2725. var d = dot(worldNormal, planeToCircle);
  2726. if(d > circleShape.radius){
  2727. return 0; // No overlap. Abort.
  2728. }
  2729. if(justTest){
  2730. return true;
  2731. }
  2732. // Create contact
  2733. var contact = this.createContactEquation(planeBody,circleBody,sj,si);
  2734. // ni is the plane world normal
  2735. vec2.copy(contact.normalA, worldNormal);
  2736. // rj is the vector from circle center to the contact point
  2737. vec2.scale(contact.contactPointB, contact.normalA, -circleShape.radius);
  2738. add(contact.contactPointB, contact.contactPointB, circleOffset);
  2739. sub(contact.contactPointB, contact.contactPointB, circleBody.position);
  2740. // ri is the distance from plane center to contact.
  2741. vec2.scale(temp, contact.normalA, d);
  2742. sub(contact.contactPointA, planeToCircle, temp ); // Subtract normal distance vector from the distance vector
  2743. add(contact.contactPointA, contact.contactPointA, planeOffset);
  2744. sub(contact.contactPointA, contact.contactPointA, planeBody.position);
  2745. this.contactEquations.push(contact);
  2746. if(this.enableFriction){
  2747. this.frictionEquations.push( this.createFrictionFromContact(contact) );
  2748. }
  2749. return 1;
  2750. };
  2751. Narrowphase.convexPrecision = 1e-7;
  2752. /**
  2753. * Convex/convex Narrowphase.See <a href="http://www.altdevblogaday.com/2011/05/13/contact-generation-between-3d-convex-meshes/">this article</a> for more info.
  2754. * @method convexConvex
  2755. * @param {Body} bi
  2756. * @param {Convex} si
  2757. * @param {Array} xi
  2758. * @param {Number} ai
  2759. * @param {Body} bj
  2760. * @param {Convex} sj
  2761. * @param {Array} xj
  2762. * @param {Number} aj
  2763. */
  2764. Narrowphase.prototype[Shape.CONVEX] =
  2765. Narrowphase.prototype[Shape.CONVEX | Shape.RECTANGLE] =
  2766. Narrowphase.prototype[Shape.RECTANGLE] =
  2767. Narrowphase.prototype.convexConvex = function( bi,si,xi,ai, bj,sj,xj,aj, justTest, precision ){
  2768. var sepAxis = tmp1,
  2769. worldPoint = tmp2,
  2770. worldPoint0 = tmp3,
  2771. worldPoint1 = tmp4,
  2772. worldEdge = tmp5,
  2773. projected = tmp6,
  2774. penetrationVec = tmp7,
  2775. dist = tmp8,
  2776. worldNormal = tmp9,
  2777. numContacts = 0,
  2778. precision = precision || Narrowphase.convexPrecision;
  2779. var found = Narrowphase.findSeparatingAxis(si,xi,ai,sj,xj,aj,sepAxis);
  2780. if(!found){
  2781. return 0;
  2782. }
  2783. // Make sure the separating axis is directed from shape i to shape j
  2784. sub(dist,xj,xi);
  2785. if(dot(sepAxis,dist) > 0){
  2786. vec2.scale(sepAxis,sepAxis,-1);
  2787. }
  2788. // Find edges with normals closest to the separating axis
  2789. var closestEdge1 = Narrowphase.getClosestEdge(si,ai,sepAxis,true), // Flipped axis
  2790. closestEdge2 = Narrowphase.getClosestEdge(sj,aj,sepAxis);
  2791. if(closestEdge1 === -1 || closestEdge2 === -1){
  2792. return 0;
  2793. }
  2794. // Loop over the shapes
  2795. for(var k=0; k<2; k++){
  2796. var closestEdgeA = closestEdge1,
  2797. closestEdgeB = closestEdge2,
  2798. shapeA = si, shapeB = sj,
  2799. offsetA = xi, offsetB = xj,
  2800. angleA = ai, angleB = aj,
  2801. bodyA = bi, bodyB = bj;
  2802. if(k === 0){
  2803. // Swap!
  2804. var tmp;
  2805. tmp = closestEdgeA; closestEdgeA = closestEdgeB; closestEdgeB = tmp;
  2806. tmp = shapeA; shapeA = shapeB; shapeB = tmp;
  2807. tmp = offsetA; offsetA = offsetB; offsetB = tmp;
  2808. tmp = angleA; angleA = angleB; angleB = tmp;
  2809. tmp = bodyA; bodyA = bodyB; bodyB = tmp;
  2810. }
  2811. // Loop over 2 points in convex B
  2812. for(var j=closestEdgeB; j<closestEdgeB+2; j++){
  2813. // Get world point
  2814. var v = shapeB.vertices[(j+shapeB.vertices.length)%shapeB.vertices.length];
  2815. vec2.rotate(worldPoint, v, angleB);
  2816. add(worldPoint, worldPoint, offsetB);
  2817. var insideNumEdges = 0;
  2818. // Loop over the 3 closest edges in convex A
  2819. for(var i=closestEdgeA-1; i<closestEdgeA+2; i++){
  2820. var v0 = shapeA.vertices[(i +shapeA.vertices.length)%shapeA.vertices.length],
  2821. v1 = shapeA.vertices[(i+1+shapeA.vertices.length)%shapeA.vertices.length];
  2822. // Construct the edge
  2823. vec2.rotate(worldPoint0, v0, angleA);
  2824. vec2.rotate(worldPoint1, v1, angleA);
  2825. add(worldPoint0, worldPoint0, offsetA);
  2826. add(worldPoint1, worldPoint1, offsetA);
  2827. sub(worldEdge, worldPoint1, worldPoint0);
  2828. vec2.rotate(worldNormal, worldEdge, -Math.PI/2); // Normal points out of convex 1
  2829. vec2.normalize(worldNormal,worldNormal);
  2830. sub(dist, worldPoint, worldPoint0);
  2831. var d = dot(worldNormal,dist);
  2832. if(d <= precision){
  2833. insideNumEdges++;
  2834. }
  2835. }
  2836. if(insideNumEdges >= 3){
  2837. if(justTest){
  2838. return true;
  2839. }
  2840. // worldPoint was on the "inside" side of each of the 3 checked edges.
  2841. // Project it to the center edge and use the projection direction as normal
  2842. // Create contact
  2843. var c = this.createContactEquation(bodyA,bodyB,shapeA,shapeB);
  2844. numContacts++;
  2845. // Get center edge from body A
  2846. var v0 = shapeA.vertices[(closestEdgeA) % shapeA.vertices.length],
  2847. v1 = shapeA.vertices[(closestEdgeA+1) % shapeA.vertices.length];
  2848. // Construct the edge
  2849. vec2.rotate(worldPoint0, v0, angleA);
  2850. vec2.rotate(worldPoint1, v1, angleA);
  2851. add(worldPoint0, worldPoint0, offsetA);
  2852. add(worldPoint1, worldPoint1, offsetA);
  2853. sub(worldEdge, worldPoint1, worldPoint0);
  2854. vec2.rotate(c.normalA, worldEdge, -Math.PI/2); // Normal points out of convex A
  2855. vec2.normalize(c.normalA,c.normalA);
  2856. sub(dist, worldPoint, worldPoint0); // From edge point to the penetrating point
  2857. var d = dot(c.normalA,dist); // Penetration
  2858. vec2.scale(penetrationVec, c.normalA, d); // Vector penetration
  2859. sub(c.contactPointA, worldPoint, offsetA);
  2860. sub(c.contactPointA, c.contactPointA, penetrationVec);
  2861. add(c.contactPointA, c.contactPointA, offsetA);
  2862. sub(c.contactPointA, c.contactPointA, bodyA.position);
  2863. sub(c.contactPointB, worldPoint, offsetB);
  2864. add(c.contactPointB, c.contactPointB, offsetB);
  2865. sub(c.contactPointB, c.contactPointB, bodyB.position);
  2866. this.contactEquations.push(c);
  2867. // Todo reduce to 1 friction equation if we have 2 contact points
  2868. if(this.enableFriction)
  2869. this.frictionEquations.push(this.createFrictionFromContact(c));
  2870. }
  2871. }
  2872. }
  2873. return numContacts;
  2874. };
  2875. // .projectConvex is called by other functions, need local tmp vectors
  2876. var pcoa_tmp1 = vec2.fromValues(0,0);
  2877. /**
  2878. * Project a Convex onto a world-oriented axis
  2879. * @method projectConvexOntoAxis
  2880. * @static
  2881. * @param {Convex} convexShape
  2882. * @param {Array} convexOffset
  2883. * @param {Number} convexAngle
  2884. * @param {Array} worldAxis
  2885. * @param {Array} result
  2886. */
  2887. Narrowphase.projectConvexOntoAxis = function(convexShape, convexOffset, convexAngle, worldAxis, result){
  2888. var max=null,
  2889. min=null,
  2890. v,
  2891. value,
  2892. localAxis = pcoa_tmp1;
  2893. // Convert the axis to local coords of the body
  2894. vec2.rotate(localAxis, worldAxis, -convexAngle);
  2895. // Get projected position of all vertices
  2896. for(var i=0; i<convexShape.vertices.length; i++){
  2897. v = convexShape.vertices[i];
  2898. value = dot(v,localAxis);
  2899. if(max === null || value > max) max = value;
  2900. if(min === null || value < min) min = value;
  2901. }
  2902. if(min > max){
  2903. var t = min;
  2904. min = max;
  2905. max = t;
  2906. }
  2907. // Project the position of the body onto the axis - need to add this to the result
  2908. var offset = dot(convexOffset, worldAxis);
  2909. vec2.set( result, min + offset, max + offset);
  2910. };
  2911. // .findSeparatingAxis is called by other functions, need local tmp vectors
  2912. var fsa_tmp1 = vec2.fromValues(0,0)
  2913. , fsa_tmp2 = vec2.fromValues(0,0)
  2914. , fsa_tmp3 = vec2.fromValues(0,0)
  2915. , fsa_tmp4 = vec2.fromValues(0,0)
  2916. , fsa_tmp5 = vec2.fromValues(0,0)
  2917. , fsa_tmp6 = vec2.fromValues(0,0)
  2918. /**
  2919. * Find a separating axis between the shapes, that maximizes the separating distance between them.
  2920. * @method findSeparatingAxis
  2921. * @static
  2922. * @param {Convex} c1
  2923. * @param {Array} offset1
  2924. * @param {Number} angle1
  2925. * @param {Convex} c2
  2926. * @param {Array} offset2
  2927. * @param {Number} angle2
  2928. * @param {Array} sepAxis The resulting axis
  2929. * @return {Boolean} Whether the axis could be found.
  2930. */
  2931. Narrowphase.findSeparatingAxis = function(c1,offset1,angle1,c2,offset2,angle2,sepAxis){
  2932. var maxDist = null,
  2933. overlap = false,
  2934. found = false,
  2935. edge = fsa_tmp1,
  2936. worldPoint0 = fsa_tmp2,
  2937. worldPoint1 = fsa_tmp3,
  2938. normal = fsa_tmp4,
  2939. span1 = fsa_tmp5,
  2940. span2 = fsa_tmp6;
  2941. for(var j=0; j!==2; j++){
  2942. var c = c1,
  2943. angle = angle1;
  2944. if(j===1){
  2945. c = c2;
  2946. angle = angle2;
  2947. }
  2948. for(var i=0; i!==c.vertices.length; i++){
  2949. // Get the world edge
  2950. vec2.rotate(worldPoint0, c.vertices[i], angle);
  2951. vec2.rotate(worldPoint1, c.vertices[(i+1)%c.vertices.length], angle);
  2952. sub(edge, worldPoint1, worldPoint0);
  2953. // Get normal - just rotate 90 degrees since vertices are given in CCW
  2954. vec2.rotate(normal, edge, -Math.PI / 2);
  2955. vec2.normalize(normal,normal);
  2956. // Project hulls onto that normal
  2957. Narrowphase.projectConvexOntoAxis(c1,offset1,angle1,normal,span1);
  2958. Narrowphase.projectConvexOntoAxis(c2,offset2,angle2,normal,span2);
  2959. // Order by span position
  2960. var a=span1,
  2961. b=span2,
  2962. swapped = false;
  2963. if(span1[0] > span2[0]){
  2964. b=span1;
  2965. a=span2;
  2966. swapped = true;
  2967. }
  2968. // Get separating distance
  2969. var dist = b[0] - a[1];
  2970. overlap = (dist <= Narrowphase.convexPrecision);
  2971. if(maxDist===null || dist > maxDist){
  2972. vec2.copy(sepAxis, normal);
  2973. maxDist = dist;
  2974. found = overlap;
  2975. }
  2976. }
  2977. }
  2978. return found;
  2979. };
  2980. // .getClosestEdge is called by other functions, need local tmp vectors
  2981. var gce_tmp1 = vec2.fromValues(0,0)
  2982. , gce_tmp2 = vec2.fromValues(0,0)
  2983. , gce_tmp3 = vec2.fromValues(0,0)
  2984. /**
  2985. * Get the edge that has a normal closest to an axis.
  2986. * @method getClosestEdge
  2987. * @static
  2988. * @param {Convex} c
  2989. * @param {Number} angle
  2990. * @param {Array} axis
  2991. * @param {Boolean} flip
  2992. * @return {Number} Index of the edge that is closest. This index and the next spans the resulting edge. Returns -1 if failed.
  2993. */
  2994. Narrowphase.getClosestEdge = function(c,angle,axis,flip){
  2995. var localAxis = gce_tmp1,
  2996. edge = gce_tmp2,
  2997. normal = gce_tmp3;
  2998. // Convert the axis to local coords of the body
  2999. vec2.rotate(localAxis, axis, -angle);
  3000. if(flip){
  3001. vec2.scale(localAxis,localAxis,-1);
  3002. }
  3003. var closestEdge = -1,
  3004. N = c.vertices.length,
  3005. halfPi = Math.PI / 2;
  3006. for(var i=0; i!==N; i++){
  3007. // Get the edge
  3008. sub(edge, c.vertices[(i+1)%N], c.vertices[i%N]);
  3009. // Get normal - just rotate 90 degrees since vertices are given in CCW
  3010. vec2.rotate(normal, edge, -halfPi);
  3011. vec2.normalize(normal,normal);
  3012. var d = dot(normal,localAxis);
  3013. if(closestEdge == -1 || d > maxDot){
  3014. closestEdge = i % N;
  3015. maxDot = d;
  3016. }
  3017. }
  3018. return closestEdge;
  3019. };
  3020. var circleHeightfield_candidate = vec2.create(),
  3021. circleHeightfield_dist = vec2.create(),
  3022. circleHeightfield_v0 = vec2.create(),
  3023. circleHeightfield_v1 = vec2.create(),
  3024. circleHeightfield_minCandidate = vec2.create(),
  3025. circleHeightfield_worldNormal = vec2.create(),
  3026. circleHeightfield_minCandidateNormal = vec2.create();
  3027. /**
  3028. * @method circleHeightfield
  3029. * @param {Body} bi
  3030. * @param {Circle} si
  3031. * @param {Array} xi
  3032. * @param {Body} bj
  3033. * @param {Heightfield} sj
  3034. * @param {Array} xj
  3035. * @param {Number} aj
  3036. */
  3037. Narrowphase.prototype[Shape.CIRCLE | Shape.HEIGHTFIELD] =
  3038. Narrowphase.prototype.circleHeightfield = function( circleBody,circleShape,circlePos,circleAngle,
  3039. hfBody,hfShape,hfPos,hfAngle, justTest, radius ){
  3040. var data = hfShape.data,
  3041. radius = radius || circleShape.radius,
  3042. w = hfShape.elementWidth,
  3043. dist = circleHeightfield_dist,
  3044. candidate = circleHeightfield_candidate,
  3045. minCandidate = circleHeightfield_minCandidate,
  3046. minCandidateNormal = circleHeightfield_minCandidateNormal,
  3047. worldNormal = circleHeightfield_worldNormal,
  3048. v0 = circleHeightfield_v0,
  3049. v1 = circleHeightfield_v1;
  3050. // Get the index of the points to test against
  3051. var idxA = Math.floor( (circlePos[0] - radius - hfPos[0]) / w ),
  3052. idxB = Math.ceil( (circlePos[0] + radius - hfPos[0]) / w );
  3053. /*if(idxB < 0 || idxA >= data.length)
  3054. return justTest ? false : 0;*/
  3055. if(idxA < 0) idxA = 0;
  3056. if(idxB >= data.length) idxB = data.length-1;
  3057. // Get max and min
  3058. var max = data[idxA],
  3059. min = data[idxB];
  3060. for(var i=idxA; i<idxB; i++){
  3061. if(data[i] < min) min = data[i];
  3062. if(data[i] > max) max = data[i];
  3063. }
  3064. if(circlePos[1]-radius > max)
  3065. return justTest ? false : 0;
  3066. if(circlePos[1]+radius < min){
  3067. // Below the minimum point... We can just guess.
  3068. // TODO
  3069. }
  3070. // 1. Check so center of circle is not inside the field. If it is, this wont work...
  3071. // 2. For each edge
  3072. // 2. 1. Get point on circle that is closest to the edge (scale normal with -radius)
  3073. // 2. 2. Check if point is inside.
  3074. var found = false,
  3075. minDist = false;
  3076. // Check all edges first
  3077. for(var i=idxA; i<idxB; i++){
  3078. // Get points
  3079. vec2.set(v0, i*w, data[i] );
  3080. vec2.set(v1, (i+1)*w, data[i+1]);
  3081. vec2.add(v0,v0,hfPos);
  3082. vec2.add(v1,v1,hfPos);
  3083. // Get normal
  3084. vec2.sub(worldNormal, v1, v0);
  3085. vec2.rotate(worldNormal, worldNormal, Math.PI/2);
  3086. vec2.normalize(worldNormal,worldNormal);
  3087. // Get point on circle, closest to the edge
  3088. vec2.scale(candidate,worldNormal,-radius);
  3089. vec2.add(candidate,candidate,circlePos);
  3090. // Distance from v0 to the candidate point
  3091. vec2.sub(dist,candidate,v0);
  3092. // Check if it is in the element "stick"
  3093. var d = vec2.dot(dist,worldNormal);
  3094. if(candidate[0] >= v0[0] && candidate[0] < v1[0] && d <= 0){
  3095. if(minDist === false || Math.abs(d) < minDist){
  3096. // Store the candidate point, projected to the edge
  3097. vec2.scale(dist,worldNormal,-d);
  3098. vec2.add(minCandidate,candidate,dist);
  3099. vec2.copy(minCandidateNormal,worldNormal);
  3100. found = true;
  3101. minDist = Math.abs(d);
  3102. if(justTest)
  3103. return true;
  3104. }
  3105. }
  3106. }
  3107. if(found){
  3108. var c = this.createContactEquation(hfBody,circleBody,hfShape,circleShape);
  3109. // Normal is out of the heightfield
  3110. vec2.copy(c.normalA, minCandidateNormal);
  3111. // Vector from circle to heightfield
  3112. vec2.scale(c.contactPointB, c.normalA, -radius);
  3113. add(c.contactPointB, c.contactPointB, circlePos);
  3114. sub(c.contactPointB, c.contactPointB, circleBody.position);
  3115. vec2.copy(c.contactPointA, minCandidate);
  3116. //vec2.sub(c.contactPointA, c.contactPointA, hfPos);
  3117. vec2.sub(c.contactPointA, c.contactPointA, hfBody.position);
  3118. this.contactEquations.push(c);
  3119. if(this.enableFriction)
  3120. this.frictionEquations.push( this.createFrictionFromContact(c) );
  3121. return 1;
  3122. }
  3123. // Check all vertices
  3124. if(radius > 0){
  3125. for(var i=idxA; i<=idxB; i++){
  3126. // Get point
  3127. vec2.set(v0, i*w, data[i]);
  3128. vec2.add(v0,v0,hfPos);
  3129. vec2.sub(dist, circlePos, v0);
  3130. if(vec2.squaredLength(dist) < radius*radius){
  3131. if(justTest) return true;
  3132. var c = this.createContactEquation(hfBody,circleBody,hfShape,circleShape);
  3133. // Construct normal - out of heightfield
  3134. vec2.copy(c.normalA, dist);
  3135. vec2.normalize(c.normalA,c.normalA);
  3136. vec2.scale(c.contactPointB, c.normalA, -radius);
  3137. add(c.contactPointB, c.contactPointB, circlePos);
  3138. sub(c.contactPointB, c.contactPointB, circleBody.position);
  3139. sub(c.contactPointA, v0, hfPos);
  3140. add(c.contactPointA, c.contactPointA, hfPos);
  3141. sub(c.contactPointA, c.contactPointA, hfBody.position);
  3142. this.contactEquations.push(c);
  3143. if(this.enableFriction){
  3144. this.frictionEquations.push(this.createFrictionFromContact(c));
  3145. }
  3146. return 1;
  3147. }
  3148. }
  3149. }
  3150. return 0;
  3151. };
  3152. },{"../equations/ContactEquation":21,"../equations/FrictionEquation":23,"../math/vec2":30,"../objects/Body":31,"../shapes/Circle":35,"../shapes/Rectangle":41,"../shapes/Shape":42,"../utils/Utils":45}],13:[function(require,module,exports){
  3153. var Circle = require('../shapes/Circle')
  3154. , Plane = require('../shapes/Plane')
  3155. , Shape = require('../shapes/Shape')
  3156. , Particle = require('../shapes/Particle')
  3157. , Utils = require('../utils/Utils')
  3158. , Broadphase = require('../collision/Broadphase')
  3159. , vec2 = require('../math/vec2')
  3160. module.exports = SAPBroadphase;
  3161. /**
  3162. * Sweep and prune broadphase along one axis.
  3163. *
  3164. * @class SAPBroadphase
  3165. * @constructor
  3166. * @extends Broadphase
  3167. */
  3168. function SAPBroadphase(){
  3169. Broadphase.call(this,Broadphase.SAP);
  3170. /**
  3171. * List of bodies currently in the broadphase.
  3172. * @property axisListX
  3173. * @type {Array}
  3174. */
  3175. this.axisListX = [];
  3176. /**
  3177. * List of bodies currently in the broadphase.
  3178. * @property axisListY
  3179. * @type {Array}
  3180. */
  3181. this.axisListY = [];
  3182. /**
  3183. * The world to search in.
  3184. * @property world
  3185. * @type {World}
  3186. */
  3187. this.world = null;
  3188. var axisListX = this.axisListX,
  3189. axisListY = this.axisListY;
  3190. this._addBodyHandler = function(e){
  3191. axisListX.push(e.body);
  3192. axisListY.push(e.body);
  3193. };
  3194. this._removeBodyHandler = function(e){
  3195. // Remove from X list
  3196. var idx = axisListX.indexOf(e.body);
  3197. if(idx !== -1) axisListX.splice(idx,1);
  3198. // Remove from Y list
  3199. idx = axisListY.indexOf(e.body);
  3200. if(idx !== -1) axisListY.splice(idx,1);
  3201. }
  3202. };
  3203. SAPBroadphase.prototype = new Broadphase();
  3204. /**
  3205. * Change the world
  3206. * @method setWorld
  3207. * @param {World} world
  3208. */
  3209. SAPBroadphase.prototype.setWorld = function(world){
  3210. // Clear the old axis array
  3211. this.axisListX.length = this.axisListY.length = 0;
  3212. // Add all bodies from the new world
  3213. Utils.appendArray(this.axisListX,world.bodies);
  3214. Utils.appendArray(this.axisListY,world.bodies);
  3215. // Remove old handlers, if any
  3216. world
  3217. .off("addBody",this._addBodyHandler)
  3218. .off("removeBody",this._removeBodyHandler);
  3219. // Add handlers to update the list of bodies.
  3220. world.on("addBody",this._addBodyHandler).on("removeBody",this._removeBodyHandler);
  3221. this.world = world;
  3222. };
  3223. /**
  3224. * Sorts bodies along the X axis.
  3225. * @method sortAxisListX
  3226. * @param {Array} a
  3227. * @return {Array}
  3228. */
  3229. SAPBroadphase.sortAxisListX = function(a){
  3230. for(var i=1,l=a.length;i<l;i++) {
  3231. var v = a[i];
  3232. for(var j=i - 1;j>=0;j--) {
  3233. if(a[j].aabb.lowerBound[0] <= v.aabb.lowerBound[0])
  3234. break;
  3235. a[j+1] = a[j];
  3236. }
  3237. a[j+1] = v;
  3238. }
  3239. return a;
  3240. };
  3241. /**
  3242. * Sorts bodies along the Y axis.
  3243. * @method sortAxisListY
  3244. * @param {Array} a
  3245. * @return {Array}
  3246. */
  3247. SAPBroadphase.sortAxisListY = function(a){
  3248. for(var i=1,l=a.length;i<l;i++) {
  3249. var v = a[i];
  3250. for(var j=i - 1;j>=0;j--) {
  3251. if(a[j].aabb.lowerBound[1] <= v.aabb.lowerBound[1])
  3252. break;
  3253. a[j+1] = a[j];
  3254. }
  3255. a[j+1] = v;
  3256. }
  3257. return a;
  3258. };
  3259. var preliminaryList = { keys:[] };
  3260. /**
  3261. * Get the colliding pairs
  3262. * @method getCollisionPairs
  3263. * @param {World} world
  3264. * @return {Array}
  3265. */
  3266. SAPBroadphase.prototype.getCollisionPairs = function(world){
  3267. var bodiesX = this.axisListX,
  3268. bodiesY = this.axisListY,
  3269. result = this.result,
  3270. axisIndex = this.axisIndex;
  3271. result.length = 0;
  3272. // Update all AABBs if needed
  3273. for(var i=0; i!==bodiesX.length; i++){
  3274. var b = bodiesX[i];
  3275. if(b.aabbNeedsUpdate) b.updateAABB();
  3276. }
  3277. // Sort the lists
  3278. SAPBroadphase.sortAxisListX(bodiesX);
  3279. SAPBroadphase.sortAxisListY(bodiesY);
  3280. // Look through the X list
  3281. for(var i=0, N=bodiesX.length; i!==N; i++){
  3282. var bi = bodiesX[i];
  3283. for(var j=i+1; j<N; j++){
  3284. var bj = bodiesX[j];
  3285. // Bounds overlap?
  3286. if(!SAPBroadphase.checkBounds(bi,bj,0))
  3287. break;
  3288. // add pair to preliminary list
  3289. if(Broadphase.canCollide(bi,bj)){
  3290. var key = bi.id < bj.id ? bi.id+' '+bj.id : bj.id+' '+bi.id;
  3291. preliminaryList[key] = true;
  3292. preliminaryList.keys.push(key);
  3293. }
  3294. }
  3295. }
  3296. // Look through the Y list
  3297. for(var i=0, N=bodiesY.length; i!==N; i++){
  3298. var bi = bodiesY[i];
  3299. for(var j=i+1; j<N; j++){
  3300. var bj = bodiesY[j];
  3301. if(!SAPBroadphase.checkBounds(bi,bj,1)){
  3302. break;
  3303. }
  3304. // If in preliminary list, add to final result
  3305. if(Broadphase.canCollide(bi,bj)){
  3306. var key = bi.id < bj.id ? bi.id+' '+bj.id : bj.id+' '+bi.id;
  3307. if(preliminaryList[key] && this.boundingVolumeCheck(bi,bj)){
  3308. result.push(bi,bj);
  3309. }
  3310. }
  3311. }
  3312. }
  3313. // Empty prel list
  3314. var keys = preliminaryList.keys;
  3315. for(var i=0, N=keys.length; i!==N; i++){
  3316. delete preliminaryList[keys[i]];
  3317. }
  3318. keys.length = 0;
  3319. return result;
  3320. };
  3321. /**
  3322. * Check if the bounds of two bodies overlap, along the given SAP axis.
  3323. * @static
  3324. * @method checkBounds
  3325. * @param {Body} bi
  3326. * @param {Body} bj
  3327. * @param {Number} axisIndex
  3328. * @return {Boolean}
  3329. */
  3330. SAPBroadphase.checkBounds = function(bi,bj,axisIndex){
  3331. /*
  3332. var biPos = bi.position[axisIndex],
  3333. ri = bi.boundingRadius,
  3334. bjPos = bj.position[axisIndex],
  3335. rj = bj.boundingRadius,
  3336. boundA1 = biPos-ri,
  3337. boundA2 = biPos+ri,
  3338. boundB1 = bjPos-rj,
  3339. boundB2 = bjPos+rj;
  3340. return boundB1 < boundA2;
  3341. */
  3342. return bj.aabb.lowerBound[axisIndex] <= bi.aabb.upperBound[axisIndex];
  3343. };
  3344. },{"../collision/Broadphase":9,"../math/vec2":30,"../shapes/Circle":35,"../shapes/Particle":39,"../shapes/Plane":40,"../shapes/Shape":42,"../utils/Utils":45}],14:[function(require,module,exports){
  3345. module.exports = Constraint;
  3346. /**
  3347. * Base constraint class.
  3348. *
  3349. * @class Constraint
  3350. * @constructor
  3351. * @author schteppe
  3352. * @param {Body} bodyA
  3353. * @param {Body} bodyB
  3354. * @param {Number} type
  3355. * @param {Object} [options]
  3356. * @param {Object} [options.collideConnected=true]
  3357. */
  3358. function Constraint(bodyA, bodyB, type, options){
  3359. options = options || {};
  3360. this.type = type;
  3361. /**
  3362. * Equations to be solved in this constraint
  3363. *
  3364. * @property equations
  3365. * @type {Array}
  3366. */
  3367. this.equations = [];
  3368. /**
  3369. * First body participating in the constraint.
  3370. * @property bodyA
  3371. * @type {Body}
  3372. */
  3373. this.bodyA = bodyA;
  3374. /**
  3375. * Second body participating in the constraint.
  3376. * @property bodyB
  3377. * @type {Body}
  3378. */
  3379. this.bodyB = bodyB;
  3380. /**
  3381. * Set to true if you want the connected bodies to collide.
  3382. * @property collideConnected
  3383. * @type {Boolean}
  3384. * @default true
  3385. */
  3386. this.collideConnected = typeof(options.collideConnected)!=="undefined" ? options.collideConnected : true;
  3387. // Wake up bodies when connected
  3388. if(bodyA) bodyA.wakeUp();
  3389. if(bodyB) bodyB.wakeUp();
  3390. };
  3391. /**
  3392. * Updates the internal constraint parameters before solve.
  3393. * @method update
  3394. */
  3395. Constraint.prototype.update = function(){
  3396. throw new Error("method update() not implmemented in this Constraint subclass!");
  3397. };
  3398. Constraint.DISTANCE = 1;
  3399. Constraint.GEAR = 2;
  3400. Constraint.LOCK = 3;
  3401. Constraint.PRISMATIC = 4;
  3402. Constraint.REVOLUTE = 5;
  3403. /**
  3404. * Set stiffness for this constraint.
  3405. * @method setStiffness
  3406. * @param {Number} stiffness
  3407. */
  3408. Constraint.prototype.setStiffness = function(stiffness){
  3409. var eqs = this.equations;
  3410. for(var i=0; i !== eqs.length; i++){
  3411. var eq = eqs[i];
  3412. eq.stiffness = stiffness;
  3413. eq.needsUpdate = true;
  3414. }
  3415. };
  3416. /**
  3417. * Set relaxation for this constraint.
  3418. * @method setRelaxation
  3419. * @param {Number} relaxation
  3420. */
  3421. Constraint.prototype.setRelaxation = function(relaxation){
  3422. var eqs = this.equations;
  3423. for(var i=0; i !== eqs.length; i++){
  3424. var eq = eqs[i];
  3425. eq.relaxation = relaxation;
  3426. eq.needsUpdate = true;
  3427. }
  3428. };
  3429. },{}],15:[function(require,module,exports){
  3430. var Constraint = require('./Constraint')
  3431. , Equation = require('../equations/Equation')
  3432. , vec2 = require('../math/vec2')
  3433. module.exports = DistanceConstraint;
  3434. /**
  3435. * Constraint that tries to keep the distance between two bodies constant.
  3436. *
  3437. * @class DistanceConstraint
  3438. * @constructor
  3439. * @author schteppe
  3440. * @param {Body} bodyA
  3441. * @param {Body} bodyB
  3442. * @param {number} distance The distance to keep between the bodies.
  3443. * @param {object} [options]
  3444. * @param {object} [options.maxForce=Number.MAX_VALUE] Maximum force to apply.
  3445. * @extends Constraint
  3446. */
  3447. function DistanceConstraint(bodyA,bodyB,distance,options){
  3448. options = options || {};
  3449. Constraint.call(this,bodyA,bodyB,Constraint.DISTANCE,options);
  3450. /**
  3451. * The distance to keep.
  3452. * @property distance
  3453. * @type {Number}
  3454. */
  3455. this.distance = distance;
  3456. var maxForce;
  3457. if(typeof(options.maxForce)==="undefined" ){
  3458. maxForce = Number.MAX_VALUE;
  3459. } else {
  3460. maxForce = options.maxForce;
  3461. }
  3462. var normal = new Equation(bodyA,bodyB,-maxForce,maxForce); // Just in the normal direction
  3463. this.equations = [ normal ];
  3464. var r = vec2.create();
  3465. normal.computeGq = function(){
  3466. vec2.sub(r, bodyB.position, bodyA.position);
  3467. return vec2.length(r)-distance;
  3468. };
  3469. // Make the contact constraint bilateral
  3470. this.setMaxForce(maxForce);
  3471. }
  3472. DistanceConstraint.prototype = new Constraint();
  3473. /**
  3474. * Update the constraint equations. Should be done if any of the bodies changed position, before solving.
  3475. * @method update
  3476. */
  3477. var n = vec2.create();
  3478. DistanceConstraint.prototype.update = function(){
  3479. var normal = this.equations[0],
  3480. bodyA = this.bodyA,
  3481. bodyB = this.bodyB,
  3482. distance = this.distance,
  3483. G = normal.G;
  3484. vec2.sub(n, bodyB.position, bodyA.position);
  3485. vec2.normalize(n,n);
  3486. G[0] = -n[0];
  3487. G[1] = -n[1];
  3488. G[3] = n[0];
  3489. G[4] = n[1];
  3490. };
  3491. /**
  3492. * Set the max force to be used
  3493. * @method setMaxForce
  3494. * @param {Number} f
  3495. */
  3496. DistanceConstraint.prototype.setMaxForce = function(f){
  3497. var normal = this.equations[0];
  3498. normal.minForce = -f;
  3499. normal.maxForce = f;
  3500. };
  3501. /**
  3502. * Get the max force
  3503. * @method getMaxForce
  3504. * @return {Number}
  3505. */
  3506. DistanceConstraint.prototype.getMaxForce = function(f){
  3507. var normal = this.equations[0];
  3508. return normal.maxForce;
  3509. };
  3510. },{"../equations/Equation":22,"../math/vec2":30,"./Constraint":14}],16:[function(require,module,exports){
  3511. var Constraint = require('./Constraint')
  3512. , Equation = require('../equations/Equation')
  3513. , AngleLockEquation = require('../equations/AngleLockEquation')
  3514. , vec2 = require('../math/vec2')
  3515. module.exports = GearConstraint;
  3516. /**
  3517. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  3518. * @class GearConstraint
  3519. * @constructor
  3520. * @author schteppe
  3521. * @param {Body} bodyA
  3522. * @param {Body} bodyB
  3523. * @param {Object} [options]
  3524. * @param {Number} [options.angle=0] Relative angle between the bodies.
  3525. * @param {Number} [options.ratio=1] Gear ratio.
  3526. * @param {Number} [options.maxTorque] Maximum torque to apply.
  3527. * @extends Constraint
  3528. * @todo Ability to specify world points
  3529. */
  3530. function GearConstraint(bodyA, bodyB, options){
  3531. options = options || {};
  3532. Constraint.call(this, bodyA, bodyB, Constraint.GEAR, options);
  3533. this.equations = [
  3534. new AngleLockEquation(bodyA,bodyB,options),
  3535. ];
  3536. /**
  3537. * The relative angle
  3538. * @property angle
  3539. * @type {Number}
  3540. */
  3541. this.angle = typeof(options.angle) === "number" ? options.angle : 0;
  3542. /**
  3543. * The gear ratio.
  3544. * @property ratio
  3545. * @type {Number}
  3546. */
  3547. this.ratio = typeof(options.ratio) === "number" ? options.ratio : 1;
  3548. // Set max torque
  3549. if(typeof(options.maxTorque) === "number"){
  3550. this.setMaxTorque(options.maxTorque);
  3551. }
  3552. }
  3553. GearConstraint.prototype = new Constraint();
  3554. GearConstraint.prototype.update = function(){
  3555. var eq = this.equations[0];
  3556. if(eq.ratio !== this.ratio){
  3557. eq.setRatio(this.ratio);
  3558. }
  3559. eq.angle = this.angle;
  3560. };
  3561. /**
  3562. * Set the max torque for the constraint.
  3563. * @method setMaxTorque
  3564. * @param {Number} torque
  3565. */
  3566. GearConstraint.prototype.setMaxTorque = function(torque){
  3567. this.equations[0].setMaxTorque(torque);
  3568. };
  3569. /**
  3570. * Get the max torque for the constraint.
  3571. * @method getMaxTorque
  3572. * @return {Number}
  3573. */
  3574. GearConstraint.prototype.getMaxTorque = function(torque){
  3575. return this.equations[0].maxForce;
  3576. };
  3577. },{"../equations/AngleLockEquation":20,"../equations/Equation":22,"../math/vec2":30,"./Constraint":14}],17:[function(require,module,exports){
  3578. var Constraint = require('./Constraint')
  3579. , vec2 = require('../math/vec2')
  3580. , Equation = require('../equations/Equation')
  3581. module.exports = LockConstraint;
  3582. /**
  3583. * Locks the relative position between two bodies.
  3584. *
  3585. * @class LockConstraint
  3586. * @constructor
  3587. * @author schteppe
  3588. * @param {Body} bodyA
  3589. * @param {Body} bodyB
  3590. * @param {Object} [options]
  3591. * @param {Array} [options.localOffsetB] The offset of bodyB in bodyA's frame. Default is the zero vector.
  3592. * @param {number} [options.localAngleB=0] The angle of bodyB in bodyA's frame.
  3593. * @param {number} [options.maxForce]
  3594. * @extends Constraint
  3595. */
  3596. function LockConstraint(bodyA, bodyB, options){
  3597. options = options || {};
  3598. Constraint.call(this,bodyA,bodyB,Constraint.LOCK,options);
  3599. var maxForce = ( typeof(options.maxForce)==="undefined" ? Number.MAX_VALUE : options.maxForce );
  3600. var localOffsetB = options.localOffsetB || vec2.fromValues(0,0);
  3601. localOffsetB = vec2.fromValues(localOffsetB[0],localOffsetB[1]);
  3602. var localAngleB = options.localAngleB || 0;
  3603. // Use 3 equations:
  3604. // gx = (xj - xi - l) * xhat = 0
  3605. // gy = (xj - xi - l) * yhat = 0
  3606. // gr = (xi - xj + r) * that = 0
  3607. //
  3608. // ...where:
  3609. // l is the localOffsetB vector rotated to world in bodyA frame
  3610. // r is the same vector but reversed and rotated from bodyB frame
  3611. // xhat, yhat are world axis vectors
  3612. // that is the tangent of r
  3613. //
  3614. // For the first two constraints, we get
  3615. // G*W = (vj - vi - ldot ) * xhat
  3616. // = (vj - vi - wi x l) * xhat
  3617. //
  3618. // Since (wi x l) * xhat = (l x xhat) * wi, we get
  3619. // G*W = [ -1 0 (-l x xhat) 1 0 0] * [vi wi vj wj]
  3620. //
  3621. // The last constraint gives
  3622. // GW = (vi - vj + wj x r) * that
  3623. // = [ that 0 -that (r x t) ]
  3624. var x = new Equation(bodyA,bodyB,-maxForce,maxForce),
  3625. y = new Equation(bodyA,bodyB,-maxForce,maxForce),
  3626. rot = new Equation(bodyA,bodyB,-maxForce,maxForce);
  3627. var l = vec2.create(),
  3628. g = vec2.create(),
  3629. that = this;
  3630. x.computeGq = function(){
  3631. vec2.rotate(l, that.localOffsetB, bodyA.angle);
  3632. vec2.sub(g, bodyB.position, bodyA.position);
  3633. vec2.sub(g, g, l);
  3634. return g[0];
  3635. };
  3636. y.computeGq = function(){
  3637. vec2.rotate(l, that.localOffsetB, bodyA.angle);
  3638. vec2.sub(g, bodyB.position, bodyA.position);
  3639. vec2.sub(g, g, l);
  3640. return g[1];
  3641. };
  3642. var r = vec2.create(),
  3643. t = vec2.create();
  3644. rot.computeGq = function(){
  3645. vec2.rotate(r, that.localOffsetB, bodyB.angle - that.localAngleB);
  3646. vec2.scale(r,r,-1);
  3647. vec2.sub(g,bodyA.position,bodyB.position);
  3648. vec2.add(g,g,r);
  3649. vec2.rotate(t,r,-Math.PI/2);
  3650. vec2.normalize(t,t);
  3651. return vec2.dot(g,t);
  3652. };
  3653. /**
  3654. * The offset of bodyB in bodyA's frame.
  3655. * @property {Array} localOffsetB
  3656. */
  3657. this.localOffsetB = localOffsetB;
  3658. /**
  3659. * The offset angle of bodyB in bodyA's frame.
  3660. * @property {Number} localAngleB
  3661. */
  3662. this.localAngleB = localAngleB;
  3663. this.equations.push(x, y, rot);
  3664. this.setMaxForce(maxForce);
  3665. }
  3666. LockConstraint.prototype = new Constraint();
  3667. /**
  3668. * Set the maximum force to be applied.
  3669. * @method setMaxForce
  3670. * @param {Number} force
  3671. */
  3672. LockConstraint.prototype.setMaxForce = function(force){
  3673. var eqs = this.equations;
  3674. for(var i=0; i<this.equations.length; i++){
  3675. eqs[i].maxForce = force;
  3676. eqs[i].minForce = -force;
  3677. }
  3678. };
  3679. /**
  3680. * Get the max force.
  3681. * @method getMaxForce
  3682. * @return {Number}
  3683. */
  3684. LockConstraint.prototype.getMaxForce = function(){
  3685. return this.equations[0].maxForce;
  3686. };
  3687. var l = vec2.create();
  3688. var r = vec2.create();
  3689. var t = vec2.create();
  3690. var xAxis = vec2.fromValues(1,0);
  3691. var yAxis = vec2.fromValues(0,1);
  3692. LockConstraint.prototype.update = function(){
  3693. var x = this.equations[0],
  3694. y = this.equations[1],
  3695. rot = this.equations[2],
  3696. bodyA = this.bodyA,
  3697. bodyB = this.bodyB;
  3698. vec2.rotate(l,this.localOffsetB,bodyA.angle);
  3699. vec2.rotate(r,this.localOffsetB,bodyB.angle - this.localAngleB);
  3700. vec2.scale(r,r,-1);
  3701. vec2.rotate(t,r,Math.PI/2);
  3702. vec2.normalize(t,t);
  3703. x.G[0] = -1;
  3704. x.G[1] = 0;
  3705. x.G[2] = -vec2.crossLength(l,xAxis);
  3706. x.G[3] = 1;
  3707. y.G[0] = 0;
  3708. y.G[1] = -1;
  3709. y.G[2] = -vec2.crossLength(l,yAxis);
  3710. y.G[4] = 1;
  3711. rot.G[0] = -t[0];
  3712. rot.G[1] = -t[1];
  3713. rot.G[3] = t[0];
  3714. rot.G[4] = t[1];
  3715. rot.G[5] = vec2.crossLength(r,t);
  3716. };
  3717. },{"../equations/Equation":22,"../math/vec2":30,"./Constraint":14}],18:[function(require,module,exports){
  3718. var Constraint = require('./Constraint')
  3719. , ContactEquation = require('../equations/ContactEquation')
  3720. , Equation = require('../equations/Equation')
  3721. , vec2 = require('../math/vec2')
  3722. , RotationalLockEquation = require('../equations/RotationalLockEquation')
  3723. module.exports = PrismaticConstraint;
  3724. /**
  3725. * Constraint that only allows bodies to move along a line, relative to each other. See <a href="http://www.iforce2d.net/b2dtut/joints-prismatic">this tutorial</a>.
  3726. *
  3727. * @class PrismaticConstraint
  3728. * @constructor
  3729. * @extends Constraint
  3730. * @author schteppe
  3731. * @param {Body} bodyA
  3732. * @param {Body} bodyB
  3733. * @param {Object} [options]
  3734. * @param {Number} [options.maxForce] Max force to be applied by the constraint
  3735. * @param {Array} [options.localAnchorA] Body A's anchor point, defined in its own local frame.
  3736. * @param {Array} [options.localAnchorB] Body B's anchor point, defined in its own local frame.
  3737. * @param {Array} [options.localAxisA] An axis, defined in body A frame, that body B's anchor point may slide along.
  3738. * @param {Boolean} [options.disableRotationalLock] If set to true, bodyB will be free to rotate around its anchor point.
  3739. * @param {Number} [options.upperLimit]
  3740. * @param {Number} [options.lowerLimit]
  3741. */
  3742. function PrismaticConstraint(bodyA, bodyB, options){
  3743. options = options || {};
  3744. Constraint.call(this,bodyA,bodyB,Constraint.PRISMATIC,options);
  3745. // Get anchors
  3746. var localAnchorA = vec2.fromValues(0,0),
  3747. localAxisA = vec2.fromValues(1,0),
  3748. localAnchorB = vec2.fromValues(0,0);
  3749. if(options.localAnchorA) vec2.copy(localAnchorA, options.localAnchorA);
  3750. if(options.localAxisA) vec2.copy(localAxisA, options.localAxisA);
  3751. if(options.localAnchorB) vec2.copy(localAnchorB, options.localAnchorB);
  3752. /**
  3753. * @property localAnchorA
  3754. * @type {Array}
  3755. */
  3756. this.localAnchorA = localAnchorA;
  3757. /**
  3758. * @property localAnchorB
  3759. * @type {Array}
  3760. */
  3761. this.localAnchorB = localAnchorB;
  3762. /**
  3763. * @property localAxisA
  3764. * @type {Array}
  3765. */
  3766. this.localAxisA = localAxisA;
  3767. /*
  3768. The constraint violation for the common axis point is
  3769. g = ( xj + rj - xi - ri ) * t := gg*t
  3770. where r are body-local anchor points, and t is a tangent to the constraint axis defined in body i frame.
  3771. gdot = ( vj + wj x rj - vi - wi x ri ) * t + ( xj + rj - xi - ri ) * ( wi x t )
  3772. Note the use of the chain rule. Now we identify the jacobian
  3773. G*W = [ -t -ri x t + t x gg t rj x t ] * [vi wi vj wj]
  3774. The rotational part is just a rotation lock.
  3775. */
  3776. var maxForce = this.maxForce = typeof(options.maxForce)!="undefined" ? options.maxForce : Number.MAX_VALUE;
  3777. // Translational part
  3778. var trans = new Equation(bodyA,bodyB,-maxForce,maxForce);
  3779. var ri = new vec2.create(),
  3780. rj = new vec2.create(),
  3781. gg = new vec2.create(),
  3782. t = new vec2.create();
  3783. trans.computeGq = function(){
  3784. // g = ( xj + rj - xi - ri ) * t
  3785. return vec2.dot(gg,t);
  3786. };
  3787. trans.updateJacobian = function(){
  3788. var G = this.G,
  3789. xi = bodyA.position,
  3790. xj = bodyB.position;
  3791. vec2.rotate(ri,localAnchorA,bodyA.angle);
  3792. vec2.rotate(rj,localAnchorB,bodyB.angle);
  3793. vec2.add(gg,xj,rj);
  3794. vec2.sub(gg,gg,xi);
  3795. vec2.sub(gg,gg,ri);
  3796. vec2.rotate(t,localAxisA,bodyA.angle+Math.PI/2);
  3797. G[0] = -t[0];
  3798. G[1] = -t[1];
  3799. G[2] = -vec2.crossLength(ri,t) + vec2.crossLength(t,gg);
  3800. G[3] = t[0];
  3801. G[4] = t[1];
  3802. G[5] = vec2.crossLength(rj,t);
  3803. };
  3804. this.equations.push(trans);
  3805. // Rotational part
  3806. if(!options.disableRotationalLock){
  3807. var rot = new RotationalLockEquation(bodyA,bodyB,-maxForce,maxForce);
  3808. this.equations.push(rot);
  3809. }
  3810. /**
  3811. * The position of anchor A relative to anchor B, along the constraint axis.
  3812. * @property position
  3813. * @type {Number}
  3814. */
  3815. this.position = 0;
  3816. this.velocity = 0;
  3817. /**
  3818. * Set to true to enable lower limit.
  3819. * @property lowerLimitEnabled
  3820. * @type {Boolean}
  3821. */
  3822. this.lowerLimitEnabled = typeof(options.lowerLimit)!=="undefined" ? true : false;
  3823. /**
  3824. * Set to true to enable upper limit.
  3825. * @property upperLimitEnabled
  3826. * @type {Boolean}
  3827. */
  3828. this.upperLimitEnabled = typeof(options.upperLimit)!=="undefined" ? true : false;
  3829. /**
  3830. * Lower constraint limit. The constraint position is forced to be larger than this value.
  3831. * @property lowerLimit
  3832. * @type {Number}
  3833. */
  3834. this.lowerLimit = typeof(options.lowerLimit)!=="undefined" ? options.lowerLimit : 0;
  3835. /**
  3836. * Upper constraint limit. The constraint position is forced to be smaller than this value.
  3837. * @property upperLimit
  3838. * @type {Number}
  3839. */
  3840. this.upperLimit = typeof(options.upperLimit)!=="undefined" ? options.upperLimit : 1;
  3841. // Equations used for limits
  3842. this.upperLimitEquation = new ContactEquation(bodyA,bodyB);
  3843. this.lowerLimitEquation = new ContactEquation(bodyA,bodyB);
  3844. // Set max/min forces
  3845. this.upperLimitEquation.minForce = this.lowerLimitEquation.minForce = 0;
  3846. this.upperLimitEquation.maxForce = this.lowerLimitEquation.maxForce = maxForce;
  3847. /**
  3848. * Equation used for the motor.
  3849. * @property motorEquation
  3850. * @type {Equation}
  3851. */
  3852. this.motorEquation = new Equation(bodyA,bodyB);
  3853. /**
  3854. * The current motor state. Enable or disable the motor using .enableMotor
  3855. * @property motorEnabled
  3856. * @type {Boolean}
  3857. */
  3858. this.motorEnabled = false;
  3859. /**
  3860. * Set the target speed for the motor.
  3861. * @property motorSpeed
  3862. * @type {Number}
  3863. */
  3864. this.motorSpeed = 0;
  3865. var that = this;
  3866. var motorEquation = this.motorEquation;
  3867. var old = motorEquation.computeGW;
  3868. motorEquation.computeGq = function(){ return 0; };
  3869. motorEquation.computeGW = function(){
  3870. var G = this.G,
  3871. bi = this.bodyA,
  3872. bj = this.bodyB,
  3873. vi = bi.velocity,
  3874. vj = bj.velocity,
  3875. wi = bi.angularVelocity,
  3876. wj = bj.angularVelocity;
  3877. return this.transformedGmult(G,vi,wi,vj,wj) + that.motorSpeed;
  3878. };
  3879. }
  3880. PrismaticConstraint.prototype = new Constraint();
  3881. var worldAxisA = vec2.create(),
  3882. worldAnchorA = vec2.create(),
  3883. worldAnchorB = vec2.create(),
  3884. orientedAnchorA = vec2.create(),
  3885. orientedAnchorB = vec2.create(),
  3886. tmp = vec2.create();
  3887. /**
  3888. * Update the constraint equations. Should be done if any of the bodies changed position, before solving.
  3889. * @method update
  3890. */
  3891. PrismaticConstraint.prototype.update = function(){
  3892. var eqs = this.equations,
  3893. trans = eqs[0],
  3894. upperLimit = this.upperLimit,
  3895. lowerLimit = this.lowerLimit,
  3896. upperLimitEquation = this.upperLimitEquation,
  3897. lowerLimitEquation = this.lowerLimitEquation,
  3898. bodyA = this.bodyA,
  3899. bodyB = this.bodyB,
  3900. localAxisA = this.localAxisA,
  3901. localAnchorA = this.localAnchorA,
  3902. localAnchorB = this.localAnchorB;
  3903. trans.updateJacobian();
  3904. // Transform local things to world
  3905. vec2.rotate(worldAxisA, localAxisA, bodyA.angle);
  3906. vec2.rotate(orientedAnchorA, localAnchorA, bodyA.angle);
  3907. vec2.add(worldAnchorA, orientedAnchorA, bodyA.position);
  3908. vec2.rotate(orientedAnchorB, localAnchorB, bodyB.angle);
  3909. vec2.add(worldAnchorB, orientedAnchorB, bodyB.position);
  3910. var relPosition = this.position = vec2.dot(worldAnchorB,worldAxisA) - vec2.dot(worldAnchorA,worldAxisA);
  3911. // Motor
  3912. if(this.motorEnabled){
  3913. // G = [ a a x ri -a -a x rj ]
  3914. var G = this.motorEquation.G;
  3915. G[0] = worldAxisA[0];
  3916. G[1] = worldAxisA[1];
  3917. G[2] = vec2.crossLength(worldAxisA,orientedAnchorB);
  3918. G[3] = -worldAxisA[0];
  3919. G[4] = -worldAxisA[1];
  3920. G[5] = -vec2.crossLength(worldAxisA,orientedAnchorA);
  3921. }
  3922. /*
  3923. Limits strategy:
  3924. Add contact equation, with normal along the constraint axis.
  3925. min/maxForce is set so the constraint is repulsive in the correct direction.
  3926. Some offset is added to either equation.contactPointA or .contactPointB to get the correct upper/lower limit.
  3927. ^
  3928. |
  3929. upperLimit x
  3930. | ------
  3931. anchorB x<---| B |
  3932. | | |
  3933. ------ | ------
  3934. | | |
  3935. | A |-->x anchorA
  3936. ------ |
  3937. x lowerLimit
  3938. |
  3939. axis
  3940. */
  3941. if(this.upperLimitEnabled && relPosition > upperLimit){
  3942. // Update contact constraint normal, etc
  3943. vec2.scale(upperLimitEquation.normalA, worldAxisA, -1);
  3944. vec2.sub(upperLimitEquation.contactPointA, worldAnchorA, bodyA.position);
  3945. vec2.sub(upperLimitEquation.contactPointB, worldAnchorB, bodyB.position);
  3946. vec2.scale(tmp,worldAxisA,upperLimit);
  3947. vec2.add(upperLimitEquation.contactPointA,upperLimitEquation.contactPointA,tmp);
  3948. if(eqs.indexOf(upperLimitEquation)==-1)
  3949. eqs.push(upperLimitEquation);
  3950. } else {
  3951. var idx = eqs.indexOf(upperLimitEquation);
  3952. if(idx != -1) eqs.splice(idx,1);
  3953. }
  3954. if(this.lowerLimitEnabled && relPosition < lowerLimit){
  3955. // Update contact constraint normal, etc
  3956. vec2.scale(lowerLimitEquation.normalA, worldAxisA, 1);
  3957. vec2.sub(lowerLimitEquation.contactPointA, worldAnchorA, bodyA.position);
  3958. vec2.sub(lowerLimitEquation.contactPointB, worldAnchorB, bodyB.position);
  3959. vec2.scale(tmp,worldAxisA,lowerLimit);
  3960. vec2.sub(lowerLimitEquation.contactPointB,lowerLimitEquation.contactPointB,tmp);
  3961. if(eqs.indexOf(lowerLimitEquation)==-1)
  3962. eqs.push(lowerLimitEquation);
  3963. } else {
  3964. var idx = eqs.indexOf(lowerLimitEquation);
  3965. if(idx != -1) eqs.splice(idx,1);
  3966. }
  3967. };
  3968. /**
  3969. * Enable the motor
  3970. * @method enableMotor
  3971. */
  3972. PrismaticConstraint.prototype.enableMotor = function(){
  3973. if(this.motorEnabled) return;
  3974. this.equations.push(this.motorEquation);
  3975. this.motorEnabled = true;
  3976. };
  3977. /**
  3978. * Disable the rotational motor
  3979. * @method disableMotor
  3980. */
  3981. PrismaticConstraint.prototype.disableMotor = function(){
  3982. if(!this.motorEnabled) return;
  3983. var i = this.equations.indexOf(this.motorEquation);
  3984. this.equations.splice(i,1);
  3985. this.motorEnabled = false;
  3986. };
  3987. },{"../equations/ContactEquation":21,"../equations/Equation":22,"../equations/RotationalLockEquation":24,"../math/vec2":30,"./Constraint":14}],19:[function(require,module,exports){
  3988. var Constraint = require('./Constraint')
  3989. , Equation = require('../equations/Equation')
  3990. , RotationalVelocityEquation = require('../equations/RotationalVelocityEquation')
  3991. , RotationalLockEquation = require('../equations/RotationalLockEquation')
  3992. , vec2 = require('../math/vec2')
  3993. module.exports = RevoluteConstraint;
  3994. var worldPivotA = vec2.create(),
  3995. worldPivotB = vec2.create(),
  3996. xAxis = vec2.fromValues(1,0),
  3997. yAxis = vec2.fromValues(0,1),
  3998. g = vec2.create();
  3999. /**
  4000. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  4001. * @class RevoluteConstraint
  4002. * @constructor
  4003. * @author schteppe
  4004. * @param {Body} bodyA
  4005. * @param {Array} pivotA The point relative to the center of mass of bodyA which bodyA is constrained to.
  4006. * @param {Body} bodyB Body that will be constrained in a similar way to the same point as bodyA. We will therefore get sort of a link between bodyA and bodyB. If not specified, bodyA will be constrained to a static point.
  4007. * @param {Array} pivotB See pivotA.
  4008. * @param {Object} [options]
  4009. * @param {Number} [options.maxForce] The maximum force that should be applied to constrain the bodies.
  4010. * @extends Constraint
  4011. * @todo Ability to specify world points
  4012. */
  4013. function RevoluteConstraint(bodyA, pivotA, bodyB, pivotB, options){
  4014. options = options || {};
  4015. Constraint.call(this,bodyA,bodyB,Constraint.REVOLUTE,options);
  4016. var maxForce = this.maxForce = typeof(options.maxForce) !== "undefined" ? options.maxForce : Number.MAX_VALUE;
  4017. /**
  4018. * @property {Array} pivotA
  4019. */
  4020. this.pivotA = pivotA;
  4021. /**
  4022. * @property {Array} pivotB
  4023. */
  4024. this.pivotB = pivotB;
  4025. // Equations to be fed to the solver
  4026. var eqs = this.equations = [
  4027. new Equation(bodyA,bodyB,-maxForce,maxForce),
  4028. new Equation(bodyA,bodyB,-maxForce,maxForce),
  4029. ];
  4030. var x = eqs[0];
  4031. var y = eqs[1];
  4032. var that = this;
  4033. x.computeGq = function(){
  4034. vec2.rotate(worldPivotA, that.pivotA, bodyA.angle);
  4035. vec2.rotate(worldPivotB, that.pivotB, bodyB.angle);
  4036. vec2.add(g, bodyB.position, worldPivotB);
  4037. vec2.sub(g, g, bodyA.position);
  4038. vec2.sub(g, g, worldPivotA);
  4039. return vec2.dot(g,xAxis);
  4040. };
  4041. y.computeGq = function(){
  4042. vec2.rotate(worldPivotA, that.pivotA, bodyA.angle);
  4043. vec2.rotate(worldPivotB, that.pivotB, bodyB.angle);
  4044. vec2.add(g, bodyB.position, worldPivotB);
  4045. vec2.sub(g, g, bodyA.position);
  4046. vec2.sub(g, g, worldPivotA);
  4047. return vec2.dot(g,yAxis);
  4048. };
  4049. y.minForce = x.minForce = -maxForce;
  4050. y.maxForce = x.maxForce = maxForce;
  4051. this.motorEquation = new RotationalVelocityEquation(bodyA,bodyB);
  4052. /**
  4053. * Indicates whether the motor is enabled. Use .enableMotor() to enable the constraint motor.
  4054. * @property {Boolean} motorEnabled
  4055. * @readOnly
  4056. */
  4057. this.motorEnabled = false;
  4058. /**
  4059. * The constraint position.
  4060. * @property angle
  4061. * @type {Number}
  4062. * @readOnly
  4063. */
  4064. this.angle = 0;
  4065. /**
  4066. * Set to true to enable lower limit
  4067. * @property lowerLimitEnabled
  4068. * @type {Boolean}
  4069. */
  4070. this.lowerLimitEnabled = false;
  4071. /**
  4072. * Set to true to enable upper limit
  4073. * @property upperLimitEnabled
  4074. * @type {Boolean}
  4075. */
  4076. this.upperLimitEnabled = false;
  4077. /**
  4078. * The lower limit on the constraint angle.
  4079. * @property lowerLimit
  4080. * @type {Boolean}
  4081. */
  4082. this.lowerLimit = 0;
  4083. /**
  4084. * The upper limit on the constraint angle.
  4085. * @property upperLimit
  4086. * @type {Boolean}
  4087. */
  4088. this.upperLimit = 0;
  4089. this.upperLimitEquation = new RotationalLockEquation(bodyA,bodyB);
  4090. this.lowerLimitEquation = new RotationalLockEquation(bodyA,bodyB);
  4091. this.upperLimitEquation.minForce = 0;
  4092. this.lowerLimitEquation.maxForce = 0;
  4093. }
  4094. RevoluteConstraint.prototype = new Constraint();
  4095. RevoluteConstraint.prototype.update = function(){
  4096. var bodyA = this.bodyA,
  4097. bodyB = this.bodyB,
  4098. pivotA = this.pivotA,
  4099. pivotB = this.pivotB,
  4100. eqs = this.equations,
  4101. normal = eqs[0],
  4102. tangent= eqs[1],
  4103. x = eqs[0],
  4104. y = eqs[1],
  4105. upperLimit = this.upperLimit,
  4106. lowerLimit = this.lowerLimit,
  4107. upperLimitEquation = this.upperLimitEquation,
  4108. lowerLimitEquation = this.lowerLimitEquation;
  4109. var relAngle = this.angle = bodyB.angle - bodyA.angle;
  4110. if(this.upperLimitEnabled && relAngle > upperLimit){
  4111. upperLimitEquation.angle = upperLimit;
  4112. if(eqs.indexOf(upperLimitEquation)==-1)
  4113. eqs.push(upperLimitEquation);
  4114. } else {
  4115. var idx = eqs.indexOf(upperLimitEquation);
  4116. if(idx != -1) eqs.splice(idx,1);
  4117. }
  4118. if(this.lowerLimitEnabled && relAngle < lowerLimit){
  4119. lowerLimitEquation.angle = lowerLimit;
  4120. if(eqs.indexOf(lowerLimitEquation)==-1)
  4121. eqs.push(lowerLimitEquation);
  4122. } else {
  4123. var idx = eqs.indexOf(lowerLimitEquation);
  4124. if(idx != -1) eqs.splice(idx,1);
  4125. }
  4126. /*
  4127. The constraint violation is
  4128. g = xj + rj - xi - ri
  4129. ...where xi and xj are the body positions and ri and rj world-oriented offset vectors. Differentiate:
  4130. gdot = vj + wj x rj - vi - wi x ri
  4131. We split this into x and y directions. (let x and y be unit vectors along the respective axes)
  4132. gdot * x = ( vj + wj x rj - vi - wi x ri ) * x
  4133. = ( vj*x + (wj x rj)*x -vi*x -(wi x ri)*x
  4134. = ( vj*x + (rj x x)*wj -vi*x -(ri x x)*wi
  4135. = [ -x -(ri x x) x (rj x x)] * [vi wi vj wj]
  4136. = G*W
  4137. ...and similar for y. We have then identified the jacobian entries for x and y directions:
  4138. Gx = [ x (rj x x) -x -(ri x x)]
  4139. Gy = [ y (rj x y) -y -(ri x y)]
  4140. */
  4141. vec2.rotate(worldPivotA, pivotA, bodyA.angle);
  4142. vec2.rotate(worldPivotB, pivotB, bodyB.angle);
  4143. // todo: these are a bit sparse. We could save some computations on making custom eq.computeGW functions, etc
  4144. x.G[0] = -1;
  4145. x.G[1] = 0;
  4146. x.G[2] = -vec2.crossLength(worldPivotA,xAxis);
  4147. x.G[3] = 1;
  4148. x.G[4] = 0;
  4149. x.G[5] = vec2.crossLength(worldPivotB,xAxis);
  4150. y.G[0] = 0;
  4151. y.G[1] = -1;
  4152. y.G[2] = -vec2.crossLength(worldPivotA,yAxis);
  4153. y.G[3] = 0;
  4154. y.G[4] = 1;
  4155. y.G[5] = vec2.crossLength(worldPivotB,yAxis);
  4156. };
  4157. /**
  4158. * Enable the rotational motor
  4159. * @method enableMotor
  4160. */
  4161. RevoluteConstraint.prototype.enableMotor = function(){
  4162. if(this.motorEnabled) return;
  4163. this.equations.push(this.motorEquation);
  4164. this.motorEnabled = true;
  4165. };
  4166. /**
  4167. * Disable the rotational motor
  4168. * @method disableMotor
  4169. */
  4170. RevoluteConstraint.prototype.disableMotor = function(){
  4171. if(!this.motorEnabled) return;
  4172. var i = this.equations.indexOf(this.motorEquation);
  4173. this.equations.splice(i,1);
  4174. this.motorEnabled = false;
  4175. };
  4176. /**
  4177. * Check if the motor is enabled.
  4178. * @method motorIsEnabled
  4179. * @return {Boolean}
  4180. */
  4181. RevoluteConstraint.prototype.motorIsEnabled = function(){
  4182. return !!this.motorEnabled;
  4183. };
  4184. /**
  4185. * Set the speed of the rotational constraint motor
  4186. * @method setMotorSpeed
  4187. * @param {Number} speed
  4188. */
  4189. RevoluteConstraint.prototype.setMotorSpeed = function(speed){
  4190. if(!this.motorEnabled){
  4191. return;
  4192. }
  4193. var i = this.equations.indexOf(this.motorEquation);
  4194. this.equations[i].relativeVelocity = speed;
  4195. };
  4196. /**
  4197. * Get the speed of the rotational constraint motor
  4198. * @method getMotorSpeed
  4199. * @return {Number} The current speed, or false if the motor is not enabled.
  4200. */
  4201. RevoluteConstraint.prototype.getMotorSpeed = function(){
  4202. if(!this.motorEnabled) return false;
  4203. return this.motorEquation.relativeVelocity;
  4204. };
  4205. },{"../equations/Equation":22,"../equations/RotationalLockEquation":24,"../equations/RotationalVelocityEquation":25,"../math/vec2":30,"./Constraint":14}],20:[function(require,module,exports){
  4206. var Equation = require("./Equation"),
  4207. vec2 = require('../math/vec2');
  4208. module.exports = AngleLockEquation;
  4209. /**
  4210. * Locks the relative angle between two bodies. The constraint tries to keep the dot product between two vectors, local in each body, to zero. The local angle in body i is a parameter.
  4211. *
  4212. * @class AngleLockEquation
  4213. * @constructor
  4214. * @extends Equation
  4215. * @param {Body} bodyA
  4216. * @param {Body} bodyB
  4217. * @param {Object} [options]
  4218. * @param {Number} [options.angle] Angle to add to the local vector in body A.
  4219. * @param {Number} [options.ratio] Gear ratio
  4220. */
  4221. function AngleLockEquation(bodyA, bodyB, options){
  4222. options = options || {};
  4223. Equation.call(this,bodyA,bodyB,-Number.MAX_VALUE,Number.MAX_VALUE);
  4224. this.angle = options.angle || 0;
  4225. /**
  4226. * The gear ratio.
  4227. * @property {Number} ratio
  4228. * @private
  4229. * @see setRatio
  4230. */
  4231. this.ratio = typeof(options.ratio)==="number" ? options.ratio : 1;
  4232. this.setRatio(this.ratio);
  4233. }
  4234. AngleLockEquation.prototype = new Equation();
  4235. AngleLockEquation.prototype.constructor = AngleLockEquation;
  4236. AngleLockEquation.prototype.computeGq = function(){
  4237. return this.ratio * this.bodyA.angle - this.bodyB.angle + this.angle;
  4238. };
  4239. /**
  4240. * Set the gear ratio for this equation
  4241. * @method setRatio
  4242. * @param {Number} ratio
  4243. */
  4244. AngleLockEquation.prototype.setRatio = function(ratio){
  4245. var G = this.G;
  4246. G[2] = ratio;
  4247. G[5] = -1;
  4248. this.ratio = ratio;
  4249. };
  4250. /**
  4251. * Set the max force for the equation.
  4252. * @method setMaxTorque
  4253. * @param {Number} torque
  4254. */
  4255. AngleLockEquation.prototype.setMaxTorque = function(torque){
  4256. this.maxForce = torque;
  4257. this.minForce = -torque;
  4258. };
  4259. },{"../math/vec2":30,"./Equation":22}],21:[function(require,module,exports){
  4260. var Equation = require("./Equation"),
  4261. vec2 = require('../math/vec2');
  4262. module.exports = ContactEquation;
  4263. /**
  4264. * Non-penetration constraint equation. Tries to make the ri and rj vectors the same point.
  4265. *
  4266. * @class ContactEquation
  4267. * @constructor
  4268. * @extends Equation
  4269. * @param {Body} bodyA
  4270. * @param {Body} bodyB
  4271. */
  4272. function ContactEquation(bodyA, bodyB){
  4273. Equation.call(this, bodyA, bodyB, 0, Number.MAX_VALUE);
  4274. /**
  4275. * Vector from body i center of mass to the contact point.
  4276. * @property contactPointA
  4277. * @type {Array}
  4278. */
  4279. this.contactPointA = vec2.create();
  4280. this.penetrationVec = vec2.create();
  4281. /**
  4282. * World-oriented vector from body A center of mass to the contact point.
  4283. * @property contactPointB
  4284. * @type {Array}
  4285. */
  4286. this.contactPointB = vec2.create();
  4287. /**
  4288. * The normal vector, pointing out of body i
  4289. * @property normalA
  4290. * @type {Array}
  4291. */
  4292. this.normalA = vec2.create();
  4293. /**
  4294. * The restitution to use (0=no bounciness, 1=max bounciness).
  4295. * @property restitution
  4296. * @type {Number}
  4297. */
  4298. this.restitution = 0;
  4299. /**
  4300. * This property is set to true if this is the first impact between the bodies (not persistant contact).
  4301. * @property firstImpact
  4302. * @type {Boolean}
  4303. * @readOnly
  4304. */
  4305. this.firstImpact = false;
  4306. /**
  4307. * The shape in body i that triggered this contact.
  4308. * @property shapeA
  4309. * @type {Shape}
  4310. */
  4311. this.shapeA = null;
  4312. /**
  4313. * The shape in body j that triggered this contact.
  4314. * @property shapeB
  4315. * @type {Shape}
  4316. */
  4317. this.shapeB = null;
  4318. }
  4319. ContactEquation.prototype = new Equation();
  4320. ContactEquation.prototype.constructor = ContactEquation;
  4321. ContactEquation.prototype.computeB = function(a,b,h){
  4322. var bi = this.bodyA,
  4323. bj = this.bodyB,
  4324. ri = this.contactPointA,
  4325. rj = this.contactPointB,
  4326. xi = bi.position,
  4327. xj = bj.position;
  4328. var penetrationVec = this.penetrationVec,
  4329. n = this.normalA,
  4330. G = this.G;
  4331. // Caluclate cross products
  4332. var rixn = vec2.crossLength(ri,n),
  4333. rjxn = vec2.crossLength(rj,n);
  4334. // G = [-n -rixn n rjxn]
  4335. G[0] = -n[0];
  4336. G[1] = -n[1];
  4337. G[2] = -rixn;
  4338. G[3] = n[0];
  4339. G[4] = n[1];
  4340. G[5] = rjxn;
  4341. // Calculate q = xj+rj -(xi+ri) i.e. the penetration vector
  4342. vec2.add(penetrationVec,xj,rj);
  4343. vec2.sub(penetrationVec,penetrationVec,xi);
  4344. vec2.sub(penetrationVec,penetrationVec,ri);
  4345. // Compute iteration
  4346. var GW, Gq;
  4347. if(this.firstImpact && this.restitution !== 0){
  4348. Gq = 0;
  4349. GW = (1/b)*(1+this.restitution) * this.computeGW();
  4350. } else {
  4351. Gq = vec2.dot(n,penetrationVec);
  4352. GW = this.computeGW();
  4353. }
  4354. var GiMf = this.computeGiMf();
  4355. var B = - Gq * a - GW * b - h*GiMf;
  4356. return B;
  4357. };
  4358. },{"../math/vec2":30,"./Equation":22}],22:[function(require,module,exports){
  4359. module.exports = Equation;
  4360. var vec2 = require('../math/vec2'),
  4361. Utils = require('../utils/Utils'),
  4362. Body = require('../objects/Body');
  4363. /**
  4364. * Base class for constraint equations.
  4365. * @class Equation
  4366. * @constructor
  4367. * @param {Body} bodyA First body participating in the equation
  4368. * @param {Body} bodyB Second body participating in the equation
  4369. * @param {number} minForce Minimum force to apply. Default: -Number.MAX_VALUE
  4370. * @param {number} maxForce Maximum force to apply. Default: Number.MAX_VALUE
  4371. */
  4372. function Equation(bodyA, bodyB, minForce, maxForce){
  4373. /**
  4374. * Minimum force to apply when solving.
  4375. * @property minForce
  4376. * @type {Number}
  4377. */
  4378. this.minForce = typeof(minForce)==="undefined" ? -Number.MAX_VALUE : minForce;
  4379. /**
  4380. * Max force to apply when solving.
  4381. * @property maxForce
  4382. * @type {Number}
  4383. */
  4384. this.maxForce = typeof(maxForce)==="undefined" ? Number.MAX_VALUE : maxForce;
  4385. /**
  4386. * First body participating in the constraint
  4387. * @property bodyA
  4388. * @type {Body}
  4389. */
  4390. this.bodyA = bodyA;
  4391. /**
  4392. * Second body participating in the constraint
  4393. * @property bodyB
  4394. * @type {Body}
  4395. */
  4396. this.bodyB = bodyB;
  4397. /**
  4398. * The stiffness of this equation. Typically chosen to a large number (~1e7), but can be chosen somewhat freely to get a stable simulation.
  4399. * @property stiffness
  4400. * @type {Number}
  4401. */
  4402. this.stiffness = Equation.DEFAULT_STIFFNESS;
  4403. /**
  4404. * The number of time steps needed to stabilize the constraint equation. Typically between 3 and 5 time steps.
  4405. * @property relaxation
  4406. * @type {Number}
  4407. */
  4408. this.relaxation = Equation.DEFAULT_RELAXATION;
  4409. /**
  4410. * The Jacobian entry of this equation. 6 numbers, 3 per body (x,y,angle).
  4411. * @property G
  4412. * @type {Array}
  4413. */
  4414. this.G = new Utils.ARRAY_TYPE(6);
  4415. for(var i=0; i<6; i++){
  4416. this.G[i]=0;
  4417. }
  4418. // Constraint frames for body i and j
  4419. /*
  4420. this.xi = vec2.create();
  4421. this.xj = vec2.create();
  4422. this.ai = 0;
  4423. this.aj = 0;
  4424. */
  4425. this.offset = 0;
  4426. this.a = 0;
  4427. this.b = 0;
  4428. this.epsilon = 0;
  4429. this.timeStep = 1/60;
  4430. /**
  4431. * Indicates if stiffness or relaxation was changed.
  4432. * @property {Boolean} needsUpdate
  4433. */
  4434. this.needsUpdate = true;
  4435. /**
  4436. * The resulting constraint multiplier from the last solve. This is mostly equivalent to the force produced by the constraint.
  4437. * @property multiplier
  4438. * @type {Number}
  4439. */
  4440. this.multiplier = 0;
  4441. /**
  4442. * Relative velocity.
  4443. * @property {Number} relativeVelocity
  4444. */
  4445. this.relativeVelocity = 0;
  4446. /**
  4447. * Whether this equation is enabled or not. If true, it will be added to the solver.
  4448. * @property {Boolean} enabled
  4449. */
  4450. this.enabled = true;
  4451. }
  4452. Equation.prototype.constructor = Equation;
  4453. /**
  4454. * The default stiffness when creating a new Equation.
  4455. * @static
  4456. * @property {Number} DEFAULT_STIFFNESS
  4457. * @default 1e6
  4458. */
  4459. Equation.DEFAULT_STIFFNESS = 1e6;
  4460. /**
  4461. * The default relaxation when creating a new Equation.
  4462. * @static
  4463. * @property {Number} DEFAULT_RELAXATION
  4464. * @default 4
  4465. */
  4466. Equation.DEFAULT_RELAXATION = 4;
  4467. /**
  4468. * Compute SPOOK parameters .a, .b and .epsilon according to the current parameters. See equations 9, 10 and 11 in the <a href="http://www8.cs.umu.se/kurser/5DV058/VT09/lectures/spooknotes.pdf">SPOOK notes</a>.
  4469. * @method update
  4470. */
  4471. Equation.prototype.update = function(){
  4472. var k = this.stiffness,
  4473. d = this.relaxation,
  4474. h = this.timeStep;
  4475. this.a = 4.0 / (h * (1 + 4 * d));
  4476. this.b = (4.0 * d) / (1 + 4 * d);
  4477. this.epsilon = 4.0 / (h * h * k * (1 + 4 * d));
  4478. this.needsUpdate = false;
  4479. };
  4480. function Gmult(G,vi,wi,vj,wj){
  4481. return G[0] * vi[0] +
  4482. G[1] * vi[1] +
  4483. G[2] * wi +
  4484. G[3] * vj[0] +
  4485. G[4] * vj[1] +
  4486. G[5] * wj;
  4487. }
  4488. /**
  4489. * Computes the RHS of the SPOOK equation
  4490. * @method computeB
  4491. * @return {Number}
  4492. */
  4493. Equation.prototype.computeB = function(a,b,h){
  4494. var GW = this.computeGW();
  4495. var Gq = this.computeGq();
  4496. var GiMf = this.computeGiMf();
  4497. return - Gq * a - GW * b - GiMf*h;
  4498. };
  4499. /**
  4500. * Computes G*q, where q are the generalized body coordinates
  4501. * @method computeGq
  4502. * @return {Number}
  4503. */
  4504. var qi = vec2.create(),
  4505. qj = vec2.create();
  4506. Equation.prototype.computeGq = function(){
  4507. var G = this.G,
  4508. bi = this.bodyA,
  4509. bj = this.bodyB,
  4510. xi = bi.position,
  4511. xj = bj.position,
  4512. ai = bi.angle,
  4513. aj = bj.angle;
  4514. // Transform to the given body frames
  4515. /*
  4516. vec2.rotate(qi,this.xi,ai);
  4517. vec2.rotate(qj,this.xj,aj);
  4518. vec2.add(qi,qi,xi);
  4519. vec2.add(qj,qj,xj);
  4520. */
  4521. return Gmult(G, qi, ai, qj, aj) + this.offset;
  4522. };
  4523. var tmp_i = vec2.create(),
  4524. tmp_j = vec2.create();
  4525. Equation.prototype.transformedGmult = function(G,vi,wi,vj,wj){
  4526. // Transform velocity to the given body frames
  4527. // v_p = v + w x r
  4528. /*
  4529. vec2.rotate(tmp_i,this.xi,Math.PI / 2 + this.bi.angle); // Get r, and rotate 90 degrees. We get the "x r" part
  4530. vec2.rotate(tmp_j,this.xj,Math.PI / 2 + this.bj.angle);
  4531. vec2.scale(tmp_i,tmp_i,wi); // Temp vectors are now (w x r)
  4532. vec2.scale(tmp_j,tmp_j,wj);
  4533. vec2.add(tmp_i,tmp_i,vi);
  4534. vec2.add(tmp_j,tmp_j,vj);
  4535. */
  4536. // Note: angular velocity is same
  4537. return Gmult(G,vi,wi,vj,wj);
  4538. };
  4539. /**
  4540. * Computes G*W, where W are the body velocities
  4541. * @method computeGW
  4542. * @return {Number}
  4543. */
  4544. Equation.prototype.computeGW = function(){
  4545. var G = this.G,
  4546. bi = this.bodyA,
  4547. bj = this.bodyB,
  4548. vi = bi.velocity,
  4549. vj = bj.velocity,
  4550. wi = bi.angularVelocity,
  4551. wj = bj.angularVelocity;
  4552. return this.transformedGmult(G,vi,wi,vj,wj) + this.relativeVelocity;
  4553. };
  4554. /**
  4555. * Computes G*Wlambda, where W are the body velocities
  4556. * @method computeGWlambda
  4557. * @return {Number}
  4558. */
  4559. Equation.prototype.computeGWlambda = function(){
  4560. var G = this.G,
  4561. bi = this.bodyA,
  4562. bj = this.bodyB,
  4563. vi = bi.vlambda,
  4564. vj = bj.vlambda,
  4565. wi = bi.wlambda,
  4566. wj = bj.wlambda;
  4567. return Gmult(G,vi,wi,vj,wj);
  4568. };
  4569. /**
  4570. * Computes G*inv(M)*f, where M is the mass matrix with diagonal blocks for each body, and f are the forces on the bodies.
  4571. * @method computeGiMf
  4572. * @return {Number}
  4573. */
  4574. var iMfi = vec2.create(),
  4575. iMfj = vec2.create();
  4576. Equation.prototype.computeGiMf = function(){
  4577. var bi = this.bodyA,
  4578. bj = this.bodyB,
  4579. fi = bi.force,
  4580. ti = bi.angularForce,
  4581. fj = bj.force,
  4582. tj = bj.angularForce,
  4583. invMassi = getBodyInvMass(bi),
  4584. invMassj = getBodyInvMass(bj),
  4585. invIi = getBodyInvInertia(bi),
  4586. invIj = getBodyInvInertia(bj),
  4587. G = this.G;
  4588. vec2.scale(iMfi, fi,invMassi);
  4589. vec2.scale(iMfj, fj,invMassj);
  4590. return this.transformedGmult(G,iMfi,ti*invIi,iMfj,tj*invIj);
  4591. };
  4592. function getBodyInvMass(body){
  4593. if(body.sleepState === Body.SLEEPING){
  4594. return 0;
  4595. } else {
  4596. return body.invMass;
  4597. }
  4598. }
  4599. function getBodyInvInertia(body){
  4600. if(body.sleepState === Body.SLEEPING){
  4601. return 0;
  4602. } else {
  4603. return body.invInertia;
  4604. }
  4605. }
  4606. /**
  4607. * Computes G*inv(M)*G'
  4608. * @method computeGiMGt
  4609. * @return {Number}
  4610. */
  4611. Equation.prototype.computeGiMGt = function(){
  4612. var bi = this.bodyA,
  4613. bj = this.bodyB,
  4614. invMassi = getBodyInvMass(bi),
  4615. invMassj = getBodyInvMass(bj),
  4616. invIi = getBodyInvInertia(bi),
  4617. invIj = getBodyInvInertia(bj),
  4618. G = this.G;
  4619. return G[0] * G[0] * invMassi +
  4620. G[1] * G[1] * invMassi +
  4621. G[2] * G[2] * invIi +
  4622. G[3] * G[3] * invMassj +
  4623. G[4] * G[4] * invMassj +
  4624. G[5] * G[5] * invIj;
  4625. };
  4626. var addToWlambda_temp = vec2.create(),
  4627. addToWlambda_Gi = vec2.create(),
  4628. addToWlambda_Gj = vec2.create(),
  4629. addToWlambda_ri = vec2.create(),
  4630. addToWlambda_rj = vec2.create(),
  4631. addToWlambda_Mdiag = vec2.create();
  4632. /**
  4633. * Add constraint velocity to the bodies.
  4634. * @method addToWlambda
  4635. * @param {Number} deltalambda
  4636. */
  4637. Equation.prototype.addToWlambda = function(deltalambda){
  4638. var bi = this.bodyA,
  4639. bj = this.bodyB,
  4640. temp = addToWlambda_temp,
  4641. Gi = addToWlambda_Gi,
  4642. Gj = addToWlambda_Gj,
  4643. ri = addToWlambda_ri,
  4644. rj = addToWlambda_rj,
  4645. invMassi = getBodyInvMass(bi),
  4646. invMassj = getBodyInvMass(bj),
  4647. invIi = getBodyInvInertia(bi),
  4648. invIj = getBodyInvInertia(bj),
  4649. Mdiag = addToWlambda_Mdiag,
  4650. G = this.G;
  4651. Gi[0] = G[0];
  4652. Gi[1] = G[1];
  4653. Gj[0] = G[3];
  4654. Gj[1] = G[4];
  4655. // Add to linear velocity
  4656. // v_lambda += inv(M) * delta_lamba * G
  4657. vec2.scale(temp, Gi, invMassi*deltalambda);
  4658. vec2.add( bi.vlambda, bi.vlambda, temp);
  4659. // This impulse is in the offset frame
  4660. // Also add contribution to angular
  4661. //bi.wlambda -= vec2.crossLength(temp,ri);
  4662. bi.wlambda += invIi * G[2] * deltalambda;
  4663. vec2.scale(temp, Gj, invMassj*deltalambda);
  4664. vec2.add( bj.vlambda, bj.vlambda, temp);
  4665. //bj.wlambda -= vec2.crossLength(temp,rj);
  4666. bj.wlambda += invIj * G[5] * deltalambda;
  4667. };
  4668. /**
  4669. * Compute the denominator part of the SPOOK equation: C = G*inv(M)*G' + eps
  4670. * @method computeInvC
  4671. * @param {Number} eps
  4672. * @return {Number}
  4673. */
  4674. Equation.prototype.computeInvC = function(eps){
  4675. return 1.0 / (this.computeGiMGt() + eps);
  4676. };
  4677. },{"../math/vec2":30,"../objects/Body":31,"../utils/Utils":45}],23:[function(require,module,exports){
  4678. var vec2 = require('../math/vec2')
  4679. , Equation = require('./Equation')
  4680. , Utils = require('../utils/Utils');
  4681. module.exports = FrictionEquation;
  4682. /**
  4683. * Constrains the slipping in a contact along a tangent
  4684. *
  4685. * @class FrictionEquation
  4686. * @constructor
  4687. * @param {Body} bodyA
  4688. * @param {Body} bodyB
  4689. * @param {Number} slipForce
  4690. * @extends Equation
  4691. */
  4692. function FrictionEquation(bodyA, bodyB, slipForce){
  4693. Equation.call(this, bodyA, bodyB, -slipForce, slipForce);
  4694. /**
  4695. * Relative vector from center of body A to the contact point, world oriented.
  4696. * @property contactPointA
  4697. * @type {Array}
  4698. */
  4699. this.contactPointA = vec2.create();
  4700. /**
  4701. * Relative vector from center of body B to the contact point, world oriented.
  4702. * @property contactPointB
  4703. * @type {Array}
  4704. */
  4705. this.contactPointB = vec2.create();
  4706. /**
  4707. * Tangent vector that the friction force will act along. World oriented.
  4708. * @property t
  4709. * @type {Array}
  4710. */
  4711. this.t = vec2.create();
  4712. /**
  4713. * A ContactEquation connected to this friction. The contact equation can be used to rescale the max force for the friction.
  4714. * @property contactEquation
  4715. * @type {ContactEquation}
  4716. */
  4717. this.contactEquation = null;
  4718. /**
  4719. * The shape in body i that triggered this friction.
  4720. * @property shapeA
  4721. * @type {Shape}
  4722. * @todo Needed? The shape can be looked up via contactEquation.shapeA...
  4723. */
  4724. this.shapeA = null;
  4725. /**
  4726. * The shape in body j that triggered this friction.
  4727. * @property shapeB
  4728. * @type {Shape}
  4729. * @todo Needed? The shape can be looked up via contactEquation.shapeB...
  4730. */
  4731. this.shapeB = null;
  4732. /**
  4733. * The friction coefficient to use.
  4734. * @property frictionCoefficient
  4735. * @type {Number}
  4736. */
  4737. this.frictionCoefficient = 0.3;
  4738. }
  4739. FrictionEquation.prototype = new Equation();
  4740. FrictionEquation.prototype.constructor = FrictionEquation;
  4741. /**
  4742. * Set the slipping condition for the constraint. The friction force cannot be
  4743. * larger than this value.
  4744. * @method setSlipForce
  4745. * @param {Number} slipForce
  4746. */
  4747. FrictionEquation.prototype.setSlipForce = function(slipForce){
  4748. this.maxForce = slipForce;
  4749. this.minForce = -slipForce;
  4750. };
  4751. /**
  4752. * Get the max force for the constraint.
  4753. * @method getSlipForce
  4754. * @return {Number}
  4755. */
  4756. FrictionEquation.prototype.getSlipForce = function(){
  4757. return this.maxForce;
  4758. };
  4759. FrictionEquation.prototype.computeB = function(a,b,h){
  4760. var bi = this.bodyA,
  4761. bj = this.bodyB,
  4762. ri = this.contactPointA,
  4763. rj = this.contactPointB,
  4764. t = this.t,
  4765. G = this.G;
  4766. // G = [-t -rixt t rjxt]
  4767. // And remember, this is a pure velocity constraint, g is always zero!
  4768. G[0] = -t[0];
  4769. G[1] = -t[1];
  4770. G[2] = -vec2.crossLength(ri,t);
  4771. G[3] = t[0];
  4772. G[4] = t[1];
  4773. G[5] = vec2.crossLength(rj,t);
  4774. var GW = this.computeGW(),
  4775. GiMf = this.computeGiMf();
  4776. var B = /* - g * a */ - GW * b - h*GiMf;
  4777. return B;
  4778. };
  4779. },{"../math/vec2":30,"../utils/Utils":45,"./Equation":22}],24:[function(require,module,exports){
  4780. var Equation = require("./Equation"),
  4781. vec2 = require('../math/vec2');
  4782. module.exports = RotationalLockEquation;
  4783. /**
  4784. * Locks the relative angle between two bodies. The constraint tries to keep the dot product between two vectors, local in each body, to zero. The local angle in body i is a parameter.
  4785. *
  4786. * @class RotationalLockEquation
  4787. * @constructor
  4788. * @extends Equation
  4789. * @param {Body} bodyA
  4790. * @param {Body} bodyB
  4791. * @param {Object} [options]
  4792. * @param {Number} [options.angle] Angle to add to the local vector in body i.
  4793. */
  4794. function RotationalLockEquation(bodyA, bodyB, options){
  4795. options = options || {};
  4796. Equation.call(this, bodyA, bodyB, -Number.MAX_VALUE, Number.MAX_VALUE);
  4797. this.angle = options.angle || 0;
  4798. var G = this.G;
  4799. G[2] = 1;
  4800. G[5] = -1;
  4801. };
  4802. RotationalLockEquation.prototype = new Equation();
  4803. RotationalLockEquation.prototype.constructor = RotationalLockEquation;
  4804. var worldVectorA = vec2.create(),
  4805. worldVectorB = vec2.create(),
  4806. xAxis = vec2.fromValues(1,0),
  4807. yAxis = vec2.fromValues(0,1);
  4808. RotationalLockEquation.prototype.computeGq = function(){
  4809. vec2.rotate(worldVectorA,xAxis,this.bodyA.angle+this.angle);
  4810. vec2.rotate(worldVectorB,yAxis,this.bodyB.angle);
  4811. return vec2.dot(worldVectorA,worldVectorB);
  4812. };
  4813. },{"../math/vec2":30,"./Equation":22}],25:[function(require,module,exports){
  4814. var Equation = require("./Equation"),
  4815. vec2 = require('../math/vec2');
  4816. module.exports = RotationalVelocityEquation;
  4817. /**
  4818. * Syncs rotational velocity of two bodies, or sets a relative velocity (motor).
  4819. *
  4820. * @class RotationalVelocityEquation
  4821. * @constructor
  4822. * @extends Equation
  4823. * @param {Body} bodyA
  4824. * @param {Body} bodyB
  4825. */
  4826. function RotationalVelocityEquation(bodyA, bodyB){
  4827. Equation.call(this, bodyA, bodyB, -Number.MAX_VALUE, Number.MAX_VALUE);
  4828. this.relativeVelocity = 1;
  4829. this.ratio = 1;
  4830. }
  4831. RotationalVelocityEquation.prototype = new Equation();
  4832. RotationalVelocityEquation.prototype.constructor = RotationalVelocityEquation;
  4833. RotationalVelocityEquation.prototype.computeB = function(a,b,h){
  4834. var G = this.G;
  4835. G[2] = -1;
  4836. G[5] = this.ratio;
  4837. var GiMf = this.computeGiMf();
  4838. var GW = this.computeGW();
  4839. var B = - GW * b - h*GiMf;
  4840. return B;
  4841. };
  4842. },{"../math/vec2":30,"./Equation":22}],26:[function(require,module,exports){
  4843. /**
  4844. * Base class for objects that dispatches events.
  4845. * @class EventEmitter
  4846. * @constructor
  4847. */
  4848. var EventEmitter = function () {}
  4849. module.exports = EventEmitter;
  4850. EventEmitter.prototype = {
  4851. constructor: EventEmitter,
  4852. /**
  4853. * Add an event listener
  4854. * @method on
  4855. * @param {String} type
  4856. * @param {Function} listener
  4857. * @return {EventEmitter} The self object, for chainability.
  4858. */
  4859. on: function ( type, listener, context ) {
  4860. listener.context = context || this;
  4861. if ( this._listeners === undefined ) this._listeners = {};
  4862. var listeners = this._listeners;
  4863. if ( listeners[ type ] === undefined ) {
  4864. listeners[ type ] = [];
  4865. }
  4866. if ( listeners[ type ].indexOf( listener ) === - 1 ) {
  4867. listeners[ type ].push( listener );
  4868. }
  4869. return this;
  4870. },
  4871. /**
  4872. * Check if an event listener is added
  4873. * @method has
  4874. * @param {String} type
  4875. * @param {Function} listener
  4876. * @return {Boolean}
  4877. */
  4878. has: function ( type, listener ) {
  4879. if ( this._listeners === undefined ) return false;
  4880. var listeners = this._listeners;
  4881. if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {
  4882. return true;
  4883. }
  4884. return false;
  4885. },
  4886. /**
  4887. * Remove an event listener
  4888. * @method off
  4889. * @param {String} type
  4890. * @param {Function} listener
  4891. * @return {EventEmitter} The self object, for chainability.
  4892. */
  4893. off: function ( type, listener ) {
  4894. if ( this._listeners === undefined ) return this;
  4895. var listeners = this._listeners;
  4896. var index = listeners[ type ].indexOf( listener );
  4897. if ( index !== - 1 ) {
  4898. listeners[ type ].splice( index, 1 );
  4899. }
  4900. return this;
  4901. },
  4902. /**
  4903. * Emit an event.
  4904. * @method emit
  4905. * @param {Object} event
  4906. * @param {String} event.type
  4907. * @return {EventEmitter} The self object, for chainability.
  4908. */
  4909. emit: function ( event ) {
  4910. if ( this._listeners === undefined ) return this;
  4911. var listeners = this._listeners;
  4912. var listenerArray = listeners[ event.type ];
  4913. if ( listenerArray !== undefined ) {
  4914. event.target = this;
  4915. for ( var i = 0, l = listenerArray.length; i < l; i ++ ) {
  4916. var listener = listenerArray[ i ];
  4917. listener.call( listener.context, event );
  4918. }
  4919. }
  4920. return this;
  4921. }
  4922. };
  4923. },{}],27:[function(require,module,exports){
  4924. var Material = require('./Material');
  4925. var Equation = require('../equations/Equation');
  4926. module.exports = ContactMaterial;
  4927. /**
  4928. * Defines what happens when two materials meet, such as what friction coefficient to use. You can also set other things such as restitution, surface velocity and constraint parameters.
  4929. * @class ContactMaterial
  4930. * @constructor
  4931. * @param {Material} materialA
  4932. * @param {Material} materialB
  4933. * @param {Object} [options]
  4934. * @param {Number} [options.friction=0.3] Friction coefficient.
  4935. * @param {Number} [options.restitution=0] Restitution coefficient aka "bounciness".
  4936. * @param {Number} [options.stiffness] ContactEquation stiffness.
  4937. * @param {Number} [options.relaxation] ContactEquation relaxation.
  4938. * @param {Number} [options.frictionStiffness] FrictionEquation stiffness.
  4939. * @param {Number} [options.frictionRelaxation] FrictionEquation relaxation.
  4940. * @param {Number} [options.surfaceVelocity=0] Surface velocity.
  4941. * @author schteppe
  4942. */
  4943. function ContactMaterial(materialA, materialB, options){
  4944. options = options || {};
  4945. if(!(materialA instanceof Material) || !(materialB instanceof Material))
  4946. throw new Error("First two arguments must be Material instances.");
  4947. /**
  4948. * The contact material identifier
  4949. * @property id
  4950. * @type {Number}
  4951. */
  4952. this.id = ContactMaterial.idCounter++;
  4953. /**
  4954. * First material participating in the contact material
  4955. * @property materialA
  4956. * @type {Material}
  4957. */
  4958. this.materialA = materialA;
  4959. /**
  4960. * Second material participating in the contact material
  4961. * @property materialB
  4962. * @type {Material}
  4963. */
  4964. this.materialB = materialB;
  4965. /**
  4966. * Friction to use in the contact of these two materials
  4967. * @property friction
  4968. * @type {Number}
  4969. */
  4970. this.friction = typeof(options.friction) !== "undefined" ? Number(options.friction) : 0.3;
  4971. /**
  4972. * Restitution to use in the contact of these two materials
  4973. * @property restitution
  4974. * @type {Number}
  4975. */
  4976. this.restitution = typeof(options.restitution) !== "undefined" ? Number(options.restitution) : 0.0;
  4977. /**
  4978. * Stiffness of the resulting ContactEquation that this ContactMaterial generate
  4979. * @property stiffness
  4980. * @type {Number}
  4981. */
  4982. this.stiffness = typeof(options.stiffness) !== "undefined" ? Number(options.stiffness) : Equation.DEFAULT_STIFFNESS;
  4983. /**
  4984. * Relaxation of the resulting ContactEquation that this ContactMaterial generate
  4985. * @property relaxation
  4986. * @type {Number}
  4987. */
  4988. this.relaxation = typeof(options.relaxation) !== "undefined" ? Number(options.relaxation) : Equation.DEFAULT_RELAXATION;
  4989. /**
  4990. * Stiffness of the resulting FrictionEquation that this ContactMaterial generate
  4991. * @property frictionStiffness
  4992. * @type {Number}
  4993. */
  4994. this.frictionStiffness = typeof(options.frictionStiffness) !== "undefined" ? Number(options.frictionStiffness) : Equation.DEFAULT_STIFFNESS;
  4995. /**
  4996. * Relaxation of the resulting FrictionEquation that this ContactMaterial generate
  4997. * @property frictionRelaxation
  4998. * @type {Number}
  4999. */
  5000. this.frictionRelaxation = typeof(options.frictionRelaxation) !== "undefined" ? Number(options.frictionRelaxation) : Equation.DEFAULT_RELAXATION;
  5001. /**
  5002. * Will add surface velocity to this material. If bodyA rests on top if bodyB, and the surface velocity is positive, bodyA will slide to the right.
  5003. * @property {Number} surfaceVelocity
  5004. */
  5005. this.surfaceVelocity = typeof(options.surfaceVelocity) !== "undefined" ? Number(options.surfaceVelocity) : 0;
  5006. }
  5007. ContactMaterial.idCounter = 0;
  5008. },{"../equations/Equation":22,"./Material":28}],28:[function(require,module,exports){
  5009. module.exports = Material;
  5010. /**
  5011. * Defines a physics material.
  5012. * @class Material
  5013. * @constructor
  5014. * @param string name
  5015. * @author schteppe
  5016. */
  5017. function Material(){
  5018. /**
  5019. * The material identifier
  5020. * @property id
  5021. * @type {Number}
  5022. */
  5023. this.id = Material.idCounter++;
  5024. };
  5025. Material.idCounter = 0;
  5026. },{}],29:[function(require,module,exports){
  5027. /*
  5028. PolyK library
  5029. url: http://polyk.ivank.net
  5030. Released under MIT licence.
  5031. Copyright (c) 2012 Ivan Kuckir
  5032. Permission is hereby granted, free of charge, to any person
  5033. obtaining a copy of this software and associated documentation
  5034. files (the "Software"), to deal in the Software without
  5035. restriction, including without limitation the rights to use,
  5036. copy, modify, merge, publish, distribute, sublicense, and/or sell
  5037. copies of the Software, and to permit persons to whom the
  5038. Software is furnished to do so, subject to the following
  5039. conditions:
  5040. The above copyright notice and this permission notice shall be
  5041. included in all copies or substantial portions of the Software.
  5042. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  5043. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  5044. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  5045. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  5046. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  5047. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  5048. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  5049. OTHER DEALINGS IN THE SOFTWARE.
  5050. */
  5051. var PolyK = {};
  5052. /*
  5053. Is Polygon self-intersecting?
  5054. O(n^2)
  5055. */
  5056. /*
  5057. PolyK.IsSimple = function(p)
  5058. {
  5059. var n = p.length>>1;
  5060. if(n<4) return true;
  5061. var a1 = new PolyK._P(), a2 = new PolyK._P();
  5062. var b1 = new PolyK._P(), b2 = new PolyK._P();
  5063. var c = new PolyK._P();
  5064. for(var i=0; i<n; i++)
  5065. {
  5066. a1.x = p[2*i ];
  5067. a1.y = p[2*i+1];
  5068. if(i==n-1) { a2.x = p[0 ]; a2.y = p[1 ]; }
  5069. else { a2.x = p[2*i+2]; a2.y = p[2*i+3]; }
  5070. for(var j=0; j<n; j++)
  5071. {
  5072. if(Math.abs(i-j) < 2) continue;
  5073. if(j==n-1 && i==0) continue;
  5074. if(i==n-1 && j==0) continue;
  5075. b1.x = p[2*j ];
  5076. b1.y = p[2*j+1];
  5077. if(j==n-1) { b2.x = p[0 ]; b2.y = p[1 ]; }
  5078. else { b2.x = p[2*j+2]; b2.y = p[2*j+3]; }
  5079. if(PolyK._GetLineIntersection(a1,a2,b1,b2,c) != null) return false;
  5080. }
  5081. }
  5082. return true;
  5083. }
  5084. PolyK.IsConvex = function(p)
  5085. {
  5086. if(p.length<6) return true;
  5087. var l = p.length - 4;
  5088. for(var i=0; i<l; i+=2)
  5089. if(!PolyK._convex(p[i], p[i+1], p[i+2], p[i+3], p[i+4], p[i+5])) return false;
  5090. if(!PolyK._convex(p[l ], p[l+1], p[l+2], p[l+3], p[0], p[1])) return false;
  5091. if(!PolyK._convex(p[l+2], p[l+3], p[0 ], p[1 ], p[2], p[3])) return false;
  5092. return true;
  5093. }
  5094. */
  5095. PolyK.GetArea = function(p)
  5096. {
  5097. if(p.length <6) return 0;
  5098. var l = p.length - 2;
  5099. var sum = 0;
  5100. for(var i=0; i<l; i+=2)
  5101. sum += (p[i+2]-p[i]) * (p[i+1]+p[i+3]);
  5102. sum += (p[0]-p[l]) * (p[l+1]+p[1]);
  5103. return - sum * 0.5;
  5104. }
  5105. /*
  5106. PolyK.GetAABB = function(p)
  5107. {
  5108. var minx = Infinity;
  5109. var miny = Infinity;
  5110. var maxx = -minx;
  5111. var maxy = -miny;
  5112. for(var i=0; i<p.length; i+=2)
  5113. {
  5114. minx = Math.min(minx, p[i ]);
  5115. maxx = Math.max(maxx, p[i ]);
  5116. miny = Math.min(miny, p[i+1]);
  5117. maxy = Math.max(maxy, p[i+1]);
  5118. }
  5119. return {x:minx, y:miny, width:maxx-minx, height:maxy-miny};
  5120. }
  5121. */
  5122. PolyK.Triangulate = function(p)
  5123. {
  5124. var n = p.length>>1;
  5125. if(n<3) return [];
  5126. var tgs = [];
  5127. var avl = [];
  5128. for(var i=0; i<n; i++) avl.push(i);
  5129. var i = 0;
  5130. var al = n;
  5131. while(al > 3)
  5132. {
  5133. var i0 = avl[(i+0)%al];
  5134. var i1 = avl[(i+1)%al];
  5135. var i2 = avl[(i+2)%al];
  5136. var ax = p[2*i0], ay = p[2*i0+1];
  5137. var bx = p[2*i1], by = p[2*i1+1];
  5138. var cx = p[2*i2], cy = p[2*i2+1];
  5139. var earFound = false;
  5140. if(PolyK._convex(ax, ay, bx, by, cx, cy))
  5141. {
  5142. earFound = true;
  5143. for(var j=0; j<al; j++)
  5144. {
  5145. var vi = avl[j];
  5146. if(vi==i0 || vi==i1 || vi==i2) continue;
  5147. if(PolyK._PointInTriangle(p[2*vi], p[2*vi+1], ax, ay, bx, by, cx, cy)) {earFound = false; break;}
  5148. }
  5149. }
  5150. if(earFound)
  5151. {
  5152. tgs.push(i0, i1, i2);
  5153. avl.splice((i+1)%al, 1);
  5154. al--;
  5155. i= 0;
  5156. }
  5157. else if(i++ > 3*al) break; // no convex angles :(
  5158. }
  5159. tgs.push(avl[0], avl[1], avl[2]);
  5160. return tgs;
  5161. }
  5162. /*
  5163. PolyK.ContainsPoint = function(p, px, py)
  5164. {
  5165. var n = p.length>>1;
  5166. var ax, ay, bx = p[2*n-2]-px, by = p[2*n-1]-py;
  5167. var depth = 0;
  5168. for(var i=0; i<n; i++)
  5169. {
  5170. ax = bx; ay = by;
  5171. bx = p[2*i ] - px;
  5172. by = p[2*i+1] - py;
  5173. if(ay< 0 && by< 0) continue; // both "up" or both "donw"
  5174. if(ay>=0 && by>=0) continue; // both "up" or both "donw"
  5175. if(ax< 0 && bx< 0) continue;
  5176. var lx = ax + (bx-ax)*(-ay)/(by-ay);
  5177. if(lx>0) depth++;
  5178. }
  5179. return (depth & 1) == 1;
  5180. }
  5181. PolyK.Slice = function(p, ax, ay, bx, by)
  5182. {
  5183. if(PolyK.ContainsPoint(p, ax, ay) || PolyK.ContainsPoint(p, bx, by)) return [p.slice(0)];
  5184. var a = new PolyK._P(ax, ay);
  5185. var b = new PolyK._P(bx, by);
  5186. var iscs = []; // intersections
  5187. var ps = []; // points
  5188. for(var i=0; i<p.length; i+=2) ps.push(new PolyK._P(p[i], p[i+1]));
  5189. for(var i=0; i<ps.length; i++)
  5190. {
  5191. var isc = new PolyK._P(0,0);
  5192. isc = PolyK._GetLineIntersection(a, b, ps[i], ps[(i+1)%ps.length], isc);
  5193. if(isc)
  5194. {
  5195. isc.flag = true;
  5196. iscs.push(isc);
  5197. ps.splice(i+1,0,isc);
  5198. i++;
  5199. }
  5200. }
  5201. if(iscs.length == 0) return [p.slice(0)];
  5202. var comp = function(u,v) {return PolyK._P.dist(a,u) - PolyK._P.dist(a,v); }
  5203. iscs.sort(comp);
  5204. var pgs = [];
  5205. var dir = 0;
  5206. while(iscs.length > 0)
  5207. {
  5208. var n = ps.length;
  5209. var i0 = iscs[0];
  5210. var i1 = iscs[1];
  5211. var ind0 = ps.indexOf(i0);
  5212. var ind1 = ps.indexOf(i1);
  5213. var solved = false;
  5214. if(PolyK._firstWithFlag(ps, ind0) == ind1) solved = true;
  5215. else
  5216. {
  5217. i0 = iscs[1];
  5218. i1 = iscs[0];
  5219. ind0 = ps.indexOf(i0);
  5220. ind1 = ps.indexOf(i1);
  5221. if(PolyK._firstWithFlag(ps, ind0) == ind1) solved = true;
  5222. }
  5223. if(solved)
  5224. {
  5225. dir--;
  5226. var pgn = PolyK._getPoints(ps, ind0, ind1);
  5227. pgs.push(pgn);
  5228. ps = PolyK._getPoints(ps, ind1, ind0);
  5229. i0.flag = i1.flag = false;
  5230. iscs.splice(0,2);
  5231. if(iscs.length == 0) pgs.push(ps);
  5232. }
  5233. else { dir++; iscs.reverse(); }
  5234. if(dir>1) break;
  5235. }
  5236. var result = [];
  5237. for(var i=0; i<pgs.length; i++)
  5238. {
  5239. var pg = pgs[i];
  5240. var npg = [];
  5241. for(var j=0; j<pg.length; j++) npg.push(pg[j].x, pg[j].y);
  5242. result.push(npg);
  5243. }
  5244. return result;
  5245. }
  5246. PolyK.Raycast = function(p, x, y, dx, dy, isc)
  5247. {
  5248. var l = p.length - 2;
  5249. var tp = PolyK._tp;
  5250. var a1 = tp[0], a2 = tp[1],
  5251. b1 = tp[2], b2 = tp[3], c = tp[4];
  5252. a1.x = x; a1.y = y;
  5253. a2.x = x+dx; a2.y = y+dy;
  5254. if(isc==null) isc = {dist:0, edge:0, norm:{x:0, y:0}, refl:{x:0, y:0}};
  5255. isc.dist = Infinity;
  5256. for(var i=0; i<l; i+=2)
  5257. {
  5258. b1.x = p[i ]; b1.y = p[i+1];
  5259. b2.x = p[i+2]; b2.y = p[i+3];
  5260. var nisc = PolyK._RayLineIntersection(a1, a2, b1, b2, c);
  5261. if(nisc) PolyK._updateISC(dx, dy, a1, b1, b2, c, i/2, isc);
  5262. }
  5263. b1.x = b2.x; b1.y = b2.y;
  5264. b2.x = p[0]; b2.y = p[1];
  5265. var nisc = PolyK._RayLineIntersection(a1, a2, b1, b2, c);
  5266. if(nisc) PolyK._updateISC(dx, dy, a1, b1, b2, c, p.length/2, isc);
  5267. return (isc.dist != Infinity) ? isc : null;
  5268. }
  5269. PolyK.ClosestEdge = function(p, x, y, isc)
  5270. {
  5271. var l = p.length - 2;
  5272. var tp = PolyK._tp;
  5273. var a1 = tp[0],
  5274. b1 = tp[2], b2 = tp[3], c = tp[4];
  5275. a1.x = x; a1.y = y;
  5276. if(isc==null) isc = {dist:0, edge:0, point:{x:0, y:0}, norm:{x:0, y:0}};
  5277. isc.dist = Infinity;
  5278. for(var i=0; i<l; i+=2)
  5279. {
  5280. b1.x = p[i ]; b1.y = p[i+1];
  5281. b2.x = p[i+2]; b2.y = p[i+3];
  5282. PolyK._pointLineDist(a1, b1, b2, i>>1, isc);
  5283. }
  5284. b1.x = b2.x; b1.y = b2.y;
  5285. b2.x = p[0]; b2.y = p[1];
  5286. PolyK._pointLineDist(a1, b1, b2, l>>1, isc);
  5287. var idst = 1/isc.dist;
  5288. isc.norm.x = (x-isc.point.x)*idst;
  5289. isc.norm.y = (y-isc.point.y)*idst;
  5290. return isc;
  5291. }
  5292. PolyK._pointLineDist = function(p, a, b, edge, isc)
  5293. {
  5294. var x = p.x, y = p.y, x1 = a.x, y1 = a.y, x2 = b.x, y2 = b.y;
  5295. var A = x - x1;
  5296. var B = y - y1;
  5297. var C = x2 - x1;
  5298. var D = y2 - y1;
  5299. var dot = A * C + B * D;
  5300. var len_sq = C * C + D * D;
  5301. var param = dot / len_sq;
  5302. var xx, yy;
  5303. if (param < 0 || (x1 == x2 && y1 == y2)) {
  5304. xx = x1;
  5305. yy = y1;
  5306. }
  5307. else if (param > 1) {
  5308. xx = x2;
  5309. yy = y2;
  5310. }
  5311. else {
  5312. xx = x1 + param * C;
  5313. yy = y1 + param * D;
  5314. }
  5315. var dx = x - xx;
  5316. var dy = y - yy;
  5317. var dst = Math.sqrt(dx * dx + dy * dy);
  5318. if(dst<isc.dist)
  5319. {
  5320. isc.dist = dst;
  5321. isc.edge = edge;
  5322. isc.point.x = xx;
  5323. isc.point.y = yy;
  5324. }
  5325. }
  5326. PolyK._updateISC = function(dx, dy, a1, b1, b2, c, edge, isc)
  5327. {
  5328. var nrl = PolyK._P.dist(a1, c);
  5329. if(nrl<isc.dist)
  5330. {
  5331. var ibl = 1/PolyK._P.dist(b1, b2);
  5332. var nx = -(b2.y-b1.y)*ibl;
  5333. var ny = (b2.x-b1.x)*ibl;
  5334. var ddot = 2*(dx*nx+dy*ny);
  5335. isc.dist = nrl;
  5336. isc.norm.x = nx;
  5337. isc.norm.y = ny;
  5338. isc.refl.x = -ddot*nx+dx;
  5339. isc.refl.y = -ddot*ny+dy;
  5340. isc.edge = edge;
  5341. }
  5342. }
  5343. PolyK._getPoints = function(ps, ind0, ind1)
  5344. {
  5345. var n = ps.length;
  5346. var nps = [];
  5347. if(ind1<ind0) ind1 += n;
  5348. for(var i=ind0; i<= ind1; i++) nps.push(ps[i%n]);
  5349. return nps;
  5350. }
  5351. PolyK._firstWithFlag = function(ps, ind)
  5352. {
  5353. var n = ps.length;
  5354. while(true)
  5355. {
  5356. ind = (ind+1)%n;
  5357. if(ps[ind].flag) return ind;
  5358. }
  5359. }
  5360. */
  5361. PolyK._PointInTriangle = function(px, py, ax, ay, bx, by, cx, cy)
  5362. {
  5363. var v0x = cx-ax;
  5364. var v0y = cy-ay;
  5365. var v1x = bx-ax;
  5366. var v1y = by-ay;
  5367. var v2x = px-ax;
  5368. var v2y = py-ay;
  5369. var dot00 = v0x*v0x+v0y*v0y;
  5370. var dot01 = v0x*v1x+v0y*v1y;
  5371. var dot02 = v0x*v2x+v0y*v2y;
  5372. var dot11 = v1x*v1x+v1y*v1y;
  5373. var dot12 = v1x*v2x+v1y*v2y;
  5374. var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
  5375. var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  5376. var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  5377. // Check if point is in triangle
  5378. return (u >= 0) && (v >= 0) && (u + v < 1);
  5379. }
  5380. /*
  5381. PolyK._RayLineIntersection = function(a1, a2, b1, b2, c)
  5382. {
  5383. var dax = (a1.x-a2.x), dbx = (b1.x-b2.x);
  5384. var day = (a1.y-a2.y), dby = (b1.y-b2.y);
  5385. var Den = dax*dby - day*dbx;
  5386. if (Den == 0) return null; // parallel
  5387. var A = (a1.x * a2.y - a1.y * a2.x);
  5388. var B = (b1.x * b2.y - b1.y * b2.x);
  5389. var I = c;
  5390. var iDen = 1/Den;
  5391. I.x = ( A*dbx - dax*B ) * iDen;
  5392. I.y = ( A*dby - day*B ) * iDen;
  5393. if(!PolyK._InRect(I, b1, b2)) return null;
  5394. if((day>0 && I.y>a1.y) || (day<0 && I.y<a1.y)) return null;
  5395. if((dax>0 && I.x>a1.x) || (dax<0 && I.x<a1.x)) return null;
  5396. return I;
  5397. }
  5398. PolyK._GetLineIntersection = function(a1, a2, b1, b2, c)
  5399. {
  5400. var dax = (a1.x-a2.x), dbx = (b1.x-b2.x);
  5401. var day = (a1.y-a2.y), dby = (b1.y-b2.y);
  5402. var Den = dax*dby - day*dbx;
  5403. if (Den == 0) return null; // parallel
  5404. var A = (a1.x * a2.y - a1.y * a2.x);
  5405. var B = (b1.x * b2.y - b1.y * b2.x);
  5406. var I = c;
  5407. I.x = ( A*dbx - dax*B ) / Den;
  5408. I.y = ( A*dby - day*B ) / Den;
  5409. if(PolyK._InRect(I, a1, a2) && PolyK._InRect(I, b1, b2)) return I;
  5410. return null;
  5411. }
  5412. PolyK._InRect = function(a, b, c)
  5413. {
  5414. if (b.x == c.x) return (a.y>=Math.min(b.y, c.y) && a.y<=Math.max(b.y, c.y));
  5415. if (b.y == c.y) return (a.x>=Math.min(b.x, c.x) && a.x<=Math.max(b.x, c.x));
  5416. if(a.x >= Math.min(b.x, c.x) && a.x <= Math.max(b.x, c.x)
  5417. && a.y >= Math.min(b.y, c.y) && a.y <= Math.max(b.y, c.y))
  5418. return true;
  5419. return false;
  5420. }
  5421. */
  5422. PolyK._convex = function(ax, ay, bx, by, cx, cy)
  5423. {
  5424. return (ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0;
  5425. }
  5426. /*
  5427. PolyK._P = function(x,y)
  5428. {
  5429. this.x = x;
  5430. this.y = y;
  5431. this.flag = false;
  5432. }
  5433. PolyK._P.prototype.toString = function()
  5434. {
  5435. return "Point ["+this.x+", "+this.y+"]";
  5436. }
  5437. PolyK._P.dist = function(a,b)
  5438. {
  5439. var dx = b.x-a.x;
  5440. var dy = b.y-a.y;
  5441. return Math.sqrt(dx*dx + dy*dy);
  5442. }
  5443. PolyK._tp = [];
  5444. for(var i=0; i<10; i++) PolyK._tp.push(new PolyK._P(0,0));
  5445. */
  5446. module.exports = PolyK;
  5447. },{}],30:[function(require,module,exports){
  5448. /**
  5449. * The vec2 object from glMatrix, with some extensions and some removed methods. See http://glmatrix.net for full doc.
  5450. * @class vec2
  5451. */
  5452. var vec2 = require('../../build/vec2').vec2;
  5453. /**
  5454. * Make a cross product and only return the z component
  5455. * @method crossLength
  5456. * @static
  5457. * @param {Float32Array} a
  5458. * @param {Float32Array} b
  5459. * @return {Number}
  5460. */
  5461. vec2.crossLength = function(a,b){
  5462. return a[0] * b[1] - a[1] * b[0];
  5463. };
  5464. /**
  5465. * Cross product between a vector and the Z component of a vector
  5466. * @method crossVZ
  5467. * @static
  5468. * @param {Float32Array} out
  5469. * @param {Float32Array} vec
  5470. * @param {Number} zcomp
  5471. * @return {Number}
  5472. */
  5473. vec2.crossVZ = function(out, vec, zcomp){
  5474. vec2.rotate(out,vec,-Math.PI/2);// Rotate according to the right hand rule
  5475. vec2.scale(out,out,zcomp); // Scale with z
  5476. return out;
  5477. };
  5478. /**
  5479. * Cross product between a vector and the Z component of a vector
  5480. * @method crossZV
  5481. * @static
  5482. * @param {Float32Array} out
  5483. * @param {Number} zcomp
  5484. * @param {Float32Array} vec
  5485. * @return {Number}
  5486. */
  5487. vec2.crossZV = function(out, zcomp, vec){
  5488. vec2.rotate(out,vec,Math.PI/2); // Rotate according to the right hand rule
  5489. vec2.scale(out,out,zcomp); // Scale with z
  5490. return out;
  5491. };
  5492. /**
  5493. * Rotate a vector by an angle
  5494. * @method rotate
  5495. * @static
  5496. * @param {Float32Array} out
  5497. * @param {Float32Array} a
  5498. * @param {Number} angle
  5499. */
  5500. vec2.rotate = function(out,a,angle){
  5501. var c = Math.cos(angle),
  5502. s = Math.sin(angle),
  5503. x = a[0],
  5504. y = a[1];
  5505. out[0] = c*x -s*y;
  5506. out[1] = s*x +c*y;
  5507. };
  5508. /**
  5509. * Transform a point position to local frame.
  5510. * @method toLocalFrame
  5511. * @param {Array} out
  5512. * @param {Array} worldPoint
  5513. * @param {Array} framePosition
  5514. * @param {Number} frameAngle
  5515. */
  5516. vec2.toLocalFrame = function(out, worldPoint, framePosition, frameAngle){
  5517. vec2.copy(out, worldPoint);
  5518. vec2.sub(out, out, framePosition);
  5519. vec2.rotate(out, out, -frameAngle);
  5520. };
  5521. /**
  5522. * Transform a point position to global frame.
  5523. * @method toGlobalFrame
  5524. * @param {Array} out
  5525. * @param {Array} localPoint
  5526. * @param {Array} framePosition
  5527. * @param {Number} frameAngle
  5528. */
  5529. vec2.toGlobalFrame = function(out, localPoint, framePosition, frameAngle){
  5530. vec2.copy(out, localPoint);
  5531. vec2.rotate(out, out, frameAngle);
  5532. vec2.add(out, out, framePosition);
  5533. };
  5534. /**
  5535. * Compute centroid of a triangle spanned by vectors a,b,c. See http://easycalculation.com/analytical/learn-centroid.php
  5536. * @method centroid
  5537. * @static
  5538. * @param {Float32Array} out
  5539. * @param {Float32Array} a
  5540. * @param {Float32Array} b
  5541. * @param {Float32Array} c
  5542. * @return {Float32Array} The out object
  5543. */
  5544. vec2.centroid = function(out, a, b, c){
  5545. vec2.add(out, a, b);
  5546. vec2.add(out, out, c);
  5547. vec2.scale(out, out, 1/3);
  5548. return out;
  5549. };
  5550. // Export everything
  5551. module.exports = vec2;
  5552. },{"../../build/vec2":1}],31:[function(require,module,exports){
  5553. var vec2 = require('../math/vec2')
  5554. , decomp = require('poly-decomp')
  5555. , Convex = require('../shapes/Convex')
  5556. , AABB = require('../collision/AABB')
  5557. , EventEmitter = require('../events/EventEmitter')
  5558. module.exports = Body;
  5559. /**
  5560. * A rigid body. Has got a center of mass, position, velocity and a number of
  5561. * shapes that are used for collisions.
  5562. *
  5563. * @class Body
  5564. * @constructor
  5565. * @extends EventEmitter
  5566. * @param {Object} [options]
  5567. * @param {Number} [options.mass=0] A number >= 0. If zero, the .motionState will be set to Body.STATIC.
  5568. * @param {Array} [options.position]
  5569. * @param {Array} [options.velocity]
  5570. * @param {Number} [options.angle=0]
  5571. * @param {Number} [options.angularVelocity=0]
  5572. * @param {Array} [options.force]
  5573. * @param {Number} [options.angularForce=0]
  5574. * @param {Number} [options.fixedRotation=false]
  5575. */
  5576. function Body(options){
  5577. options = options || {};
  5578. EventEmitter.call(this);
  5579. /**
  5580. * The body identifyer
  5581. * @property id
  5582. * @type {Number}
  5583. */
  5584. this.id = ++Body._idCounter;
  5585. /**
  5586. * The world that this body is added to. This property is set to NULL if the body is not added to any world.
  5587. * @property world
  5588. * @type {World}
  5589. */
  5590. this.world = null;
  5591. /**
  5592. * The shapes of the body. The local transform of the shape in .shapes[i] is
  5593. * defined by .shapeOffsets[i] and .shapeAngles[i].
  5594. *
  5595. * @property shapes
  5596. * @type {Array}
  5597. */
  5598. this.shapes = [];
  5599. /**
  5600. * The local shape offsets, relative to the body center of mass. This is an
  5601. * array of Array.
  5602. * @property shapeOffsets
  5603. * @type {Array}
  5604. */
  5605. this.shapeOffsets = [];
  5606. /**
  5607. * The body-local shape angle transforms. This is an array of numbers (angles).
  5608. * @property shapeAngles
  5609. * @type {Array}
  5610. */
  5611. this.shapeAngles = [];
  5612. /**
  5613. * The mass of the body.
  5614. * @property mass
  5615. * @type {number}
  5616. */
  5617. this.mass = options.mass || 0;
  5618. /**
  5619. * The inverse mass of the body.
  5620. * @property invMass
  5621. * @type {number}
  5622. */
  5623. this.invMass = 0;
  5624. /**
  5625. * The inertia of the body around the Z axis.
  5626. * @property inertia
  5627. * @type {number}
  5628. */
  5629. this.inertia = 0;
  5630. /**
  5631. * The inverse inertia of the body.
  5632. * @property invInertia
  5633. * @type {number}
  5634. */
  5635. this.invInertia = 0;
  5636. /**
  5637. * Set to true if you want to fix the rotation of the body.
  5638. * @property fixedRotation
  5639. * @type {Boolean}
  5640. */
  5641. this.fixedRotation = !!options.fixedRotation || false;
  5642. /**
  5643. * The position of the body
  5644. * @property position
  5645. * @type {Array}
  5646. */
  5647. this.position = vec2.fromValues(0,0);
  5648. if(options.position){
  5649. vec2.copy(this.position, options.position);
  5650. }
  5651. /**
  5652. * The interpolated position of the body.
  5653. * @property interpolatedPosition
  5654. * @type {Array}
  5655. */
  5656. this.interpolatedPosition = vec2.fromValues(0,0);
  5657. /**
  5658. * The interpolated angle of the body.
  5659. * @property interpolatedAngle
  5660. * @type {Number}
  5661. */
  5662. this.interpolatedAngle = 0;
  5663. /**
  5664. * The previous position of the body.
  5665. * @property previousPosition
  5666. * @type {Array}
  5667. */
  5668. this.previousPosition = vec2.fromValues(0,0);
  5669. /**
  5670. * The previous angle of the body.
  5671. * @property previousAngle
  5672. * @type {Number}
  5673. */
  5674. this.previousAngle = 0;
  5675. /**
  5676. * The velocity of the body
  5677. * @property velocity
  5678. * @type {Array}
  5679. */
  5680. this.velocity = vec2.fromValues(0,0);
  5681. if(options.velocity){
  5682. vec2.copy(this.velocity, options.velocity);
  5683. }
  5684. /**
  5685. * Constraint velocity that was added to the body during the last step.
  5686. * @property vlambda
  5687. * @type {Array}
  5688. */
  5689. this.vlambda = vec2.fromValues(0,0);
  5690. /**
  5691. * Angular constraint velocity that was added to the body during last step.
  5692. * @property wlambda
  5693. * @type {Array}
  5694. */
  5695. this.wlambda = 0;
  5696. /**
  5697. * The angle of the body, in radians.
  5698. * @property angle
  5699. * @type {number}
  5700. * @example
  5701. * // The angle property is not normalized to the interval 0 to 2*pi, it can be any value.
  5702. * // If you need a value between 0 and 2*pi, use the following function to normalize it.
  5703. * function normalizeAngle(angle){
  5704. * angle = angle % (2*Math.PI);
  5705. * if(angle < 0){
  5706. * angle += (2*Math.PI);
  5707. * }
  5708. * return angle;
  5709. * }
  5710. */
  5711. this.angle = options.angle || 0;
  5712. /**
  5713. * The angular velocity of the body, in radians per second.
  5714. * @property angularVelocity
  5715. * @type {number}
  5716. */
  5717. this.angularVelocity = options.angularVelocity || 0;
  5718. /**
  5719. * The force acting on the body. Since the body force (and {{#crossLink "Body/angularForce:property"}}{{/crossLink}}) will be zeroed after each step, so you need to set the force before each step.
  5720. * @property force
  5721. * @type {Array}
  5722. *
  5723. * @example
  5724. * // This produces a forcefield of 1 Newton in the positive x direction.
  5725. * for(var i=0; i<numSteps; i++){
  5726. * body.force[0] = 1;
  5727. * world.step(1/60);
  5728. * }
  5729. *
  5730. * @example
  5731. * // This will apply a rotational force on the body
  5732. * for(var i=0; i<numSteps; i++){
  5733. * body.angularForce = -3;
  5734. * world.step(1/60);
  5735. * }
  5736. */
  5737. this.force = vec2.create();
  5738. if(options.force) vec2.copy(this.force, options.force);
  5739. /**
  5740. * The angular force acting on the body. See {{#crossLink "Body/force:property"}}{{/crossLink}}.
  5741. * @property angularForce
  5742. * @type {number}
  5743. */
  5744. this.angularForce = options.angularForce || 0;
  5745. /**
  5746. * The linear damping acting on the body in the velocity direction. Should be a value between 0 and 1.
  5747. * @property damping
  5748. * @type {Number}
  5749. * @default 0.1
  5750. */
  5751. this.damping = typeof(options.damping)=="number" ? options.damping : 0.1;
  5752. /**
  5753. * The angular force acting on the body. Should be a value between 0 and 1.
  5754. * @property angularDamping
  5755. * @type {Number}
  5756. * @default 0.1
  5757. */
  5758. this.angularDamping = typeof(options.angularDamping)=="number" ? options.angularDamping : 0.1;
  5759. /**
  5760. * The type of motion this body has. Should be one of: {{#crossLink "Body/STATIC:property"}}Body.STATIC{{/crossLink}}, {{#crossLink "Body/DYNAMIC:property"}}Body.DYNAMIC{{/crossLink}} and {{#crossLink "Body/KINEMATIC:property"}}Body.KINEMATIC{{/crossLink}}.
  5761. *
  5762. * * Static bodies do not move, and they do not respond to forces or collision.
  5763. * * Dynamic bodies body can move and respond to collisions and forces.
  5764. * * Kinematic bodies only moves according to its .velocity, and does not respond to collisions or force.
  5765. *
  5766. * @property motionState
  5767. * @type {number}
  5768. *
  5769. * @example
  5770. * // This body will move and interact with other bodies
  5771. * var dynamicBody = new Body({
  5772. * mass : 1 // If mass is nonzero, the body becomes dynamic automatically
  5773. * });
  5774. * dynamicBody.motionState == Body.DYNAMIC // true
  5775. *
  5776. * @example
  5777. * // This body will not move at all
  5778. * var staticBody = new Body({
  5779. * mass : 0 // Will make the body static
  5780. * });
  5781. * staticBody.motionState == Body.STATIC // true
  5782. *
  5783. * @example
  5784. * // This body will only move if you change its velocity
  5785. * var kinematicBody = new Body();
  5786. * kinematicBody.motionState = Body.KINEMATIC;
  5787. */
  5788. this.motionState = this.mass === 0 ? Body.STATIC : Body.DYNAMIC;
  5789. /**
  5790. * Bounding circle radius.
  5791. * @property boundingRadius
  5792. * @type {Number}
  5793. */
  5794. this.boundingRadius = 0;
  5795. /**
  5796. * Bounding box of this body.
  5797. * @property aabb
  5798. * @type {AABB}
  5799. */
  5800. this.aabb = new AABB();
  5801. /**
  5802. * Indicates if the AABB needs update. Update it with {{#crossLink "Body/updateAABB:method"}}.updateAABB(){{/crossLink}}.
  5803. * @property aabbNeedsUpdate
  5804. * @type {Boolean}
  5805. * @see updateAABB
  5806. *
  5807. * @example
  5808. * // Force update the AABB
  5809. * body.aabbNeedsUpdate = true;
  5810. * body.updateAABB();
  5811. * console.log(body.aabbNeedsUpdate); // false
  5812. */
  5813. this.aabbNeedsUpdate = true;
  5814. /**
  5815. * If true, the body will automatically fall to sleep. Note that you need to enable sleeping in the {{#crossLink "World"}}{{/crossLink}} before anything will happen.
  5816. * @property allowSleep
  5817. * @type {Boolean}
  5818. * @default true
  5819. */
  5820. this.allowSleep = true;
  5821. this.wantsToSleep = false;
  5822. /**
  5823. * One of {{#crossLink "Body/AWAKE:property"}}Body.AWAKE{{/crossLink}}, {{#crossLink "Body/SLEEPY:property"}}Body.SLEEPY{{/crossLink}} and {{#crossLink "Body/SLEEPING:property"}}Body.SLEEPING{{/crossLink}}.
  5824. *
  5825. * The body is initially Body.AWAKE. If its velocity norm is below .sleepSpeedLimit, the sleepState will become Body.SLEEPY. If the body continues to be Body.SLEEPY for .sleepTimeLimit seconds, it will fall asleep (Body.SLEEPY).
  5826. *
  5827. * @property sleepState
  5828. * @type {Number}
  5829. * @default Body.AWAKE
  5830. */
  5831. this.sleepState = Body.AWAKE;
  5832. /**
  5833. * If the speed (the norm of the velocity) is smaller than this value, the body is considered sleepy.
  5834. * @property sleepSpeedLimit
  5835. * @type {Number}
  5836. * @default 0.2
  5837. */
  5838. this.sleepSpeedLimit = 0.2;
  5839. /**
  5840. * If the body has been sleepy for this sleepTimeLimit seconds, it is considered sleeping.
  5841. * @property sleepTimeLimit
  5842. * @type {Number}
  5843. * @default 1
  5844. */
  5845. this.sleepTimeLimit = 1;
  5846. /**
  5847. * Gravity scaling factor. If you want the body to ignore gravity, set this to zero. If you want to reverse gravity, set it to -1.
  5848. * @property {Number} gravityScale
  5849. * @default 1
  5850. */
  5851. this.gravityScale = 1;
  5852. /**
  5853. * The last time when the body went to SLEEPY state.
  5854. * @property {Number} timeLastSleepy
  5855. * @private
  5856. */
  5857. this.timeLastSleepy = 0;
  5858. this.concavePath = null;
  5859. this.lastDampingScale = 1;
  5860. this.lastAngularDampingScale = 1;
  5861. this.lastDampingTimeStep = -1;
  5862. this.updateMassProperties();
  5863. }
  5864. Body.prototype = new EventEmitter();
  5865. Body._idCounter = 0;
  5866. /**
  5867. * Set the total density of the body
  5868. * @method setDensity
  5869. */
  5870. Body.prototype.setDensity = function(density) {
  5871. var totalArea = this.getArea();
  5872. this.mass = totalArea * density;
  5873. this.updateMassProperties();
  5874. };
  5875. /**
  5876. * Get the total area of all shapes in the body
  5877. * @method getArea
  5878. * @return {Number}
  5879. */
  5880. Body.prototype.getArea = function() {
  5881. var totalArea = 0;
  5882. for(var i=0; i<this.shapes.length; i++){
  5883. totalArea += this.shapes[i].area;
  5884. }
  5885. return totalArea;
  5886. };
  5887. var shapeAABB = new AABB(),
  5888. tmp = vec2.create();
  5889. /**
  5890. * Updates the AABB of the Body
  5891. * @method updateAABB
  5892. */
  5893. Body.prototype.updateAABB = function() {
  5894. var shapes = this.shapes,
  5895. shapeOffsets = this.shapeOffsets,
  5896. shapeAngles = this.shapeAngles,
  5897. N = shapes.length;
  5898. for(var i=0; i!==N; i++){
  5899. var shape = shapes[i],
  5900. offset = tmp,
  5901. angle = shapeAngles[i] + this.angle;
  5902. // Get shape world offset
  5903. vec2.rotate(offset,shapeOffsets[i],this.angle);
  5904. vec2.add(offset,offset,this.position);
  5905. // Get shape AABB
  5906. shape.computeAABB(shapeAABB,offset,angle);
  5907. if(i===0)
  5908. this.aabb.copy(shapeAABB);
  5909. else
  5910. this.aabb.extend(shapeAABB);
  5911. }
  5912. this.aabbNeedsUpdate = false;
  5913. };
  5914. /**
  5915. * Update the bounding radius of the body. Should be done if any of the shapes
  5916. * are changed.
  5917. * @method updateBoundingRadius
  5918. */
  5919. Body.prototype.updateBoundingRadius = function(){
  5920. var shapes = this.shapes,
  5921. shapeOffsets = this.shapeOffsets,
  5922. N = shapes.length,
  5923. radius = 0;
  5924. for(var i=0; i!==N; i++){
  5925. var shape = shapes[i],
  5926. offset = vec2.length(shapeOffsets[i]),
  5927. r = shape.boundingRadius;
  5928. if(offset + r > radius){
  5929. radius = offset + r;
  5930. }
  5931. }
  5932. this.boundingRadius = radius;
  5933. };
  5934. /**
  5935. * Add a shape to the body. You can pass a local transform when adding a shape,
  5936. * so that the shape gets an offset and angle relative to the body center of mass.
  5937. * Will automatically update the mass properties and bounding radius.
  5938. *
  5939. * @method addShape
  5940. * @param {Shape} shape
  5941. * @param {Array} [offset] Local body offset of the shape.
  5942. * @param {Number} [angle] Local body angle.
  5943. *
  5944. * @example
  5945. * var body = new Body(),
  5946. * shape = new Circle();
  5947. *
  5948. * // Add the shape to the body, positioned in the center
  5949. * body.addShape(shape);
  5950. *
  5951. * // Add another shape to the body, positioned 1 unit length from the body center of mass along the local x-axis.
  5952. * body.addShape(shape,[1,0]);
  5953. *
  5954. * // Add another shape to the body, positioned 1 unit length from the body center of mass along the local y-axis, and rotated 90 degrees CCW.
  5955. * body.addShape(shape,[0,1],Math.PI/2);
  5956. */
  5957. Body.prototype.addShape = function(shape,offset,angle){
  5958. angle = angle || 0.0;
  5959. // Copy the offset vector
  5960. if(offset){
  5961. offset = vec2.fromValues(offset[0],offset[1]);
  5962. } else {
  5963. offset = vec2.fromValues(0,0);
  5964. }
  5965. this.shapes .push(shape);
  5966. this.shapeOffsets.push(offset);
  5967. this.shapeAngles .push(angle);
  5968. this.updateMassProperties();
  5969. this.updateBoundingRadius();
  5970. this.aabbNeedsUpdate = true;
  5971. };
  5972. /**
  5973. * Remove a shape
  5974. * @method removeShape
  5975. * @param {Shape} shape
  5976. * @return {Boolean} True if the shape was found and removed, else false.
  5977. */
  5978. Body.prototype.removeShape = function(shape){
  5979. var idx = this.shapes.indexOf(shape);
  5980. if(idx !== -1){
  5981. this.shapes.splice(idx,1);
  5982. this.shapeOffsets.splice(idx,1);
  5983. this.shapeAngles.splice(idx,1);
  5984. this.aabbNeedsUpdate = true;
  5985. return true;
  5986. } else {
  5987. return false;
  5988. }
  5989. };
  5990. /**
  5991. * Updates .inertia, .invMass, .invInertia for this Body. Should be called when
  5992. * changing the structure or mass of the Body.
  5993. *
  5994. * @method updateMassProperties
  5995. *
  5996. * @example
  5997. * body.mass += 1;
  5998. * body.updateMassProperties();
  5999. */
  6000. Body.prototype.updateMassProperties = function(){
  6001. if(this.motionState === Body.STATIC || this.motionState === Body.KINEMATIC){
  6002. this.mass = Number.MAX_VALUE;
  6003. this.invMass = 0;
  6004. this.inertia = Number.MAX_VALUE;
  6005. this.invInertia = 0;
  6006. } else {
  6007. var shapes = this.shapes,
  6008. N = shapes.length,
  6009. m = this.mass / N,
  6010. I = 0;
  6011. if(!this.fixedRotation){
  6012. for(var i=0; i<N; i++){
  6013. var shape = shapes[i],
  6014. r2 = vec2.squaredLength(this.shapeOffsets[i]),
  6015. Icm = shape.computeMomentOfInertia(m);
  6016. I += Icm + m*r2;
  6017. }
  6018. this.inertia = I;
  6019. this.invInertia = I>0 ? 1/I : 0;
  6020. } else {
  6021. this.inertia = Number.MAX_VALUE;
  6022. this.invInertia = 0;
  6023. }
  6024. // Inverse mass properties are easy
  6025. this.invMass = 1/this.mass;// > 0 ? 1/this.mass : 0;
  6026. }
  6027. };
  6028. var Body_applyForce_r = vec2.create();
  6029. /**
  6030. * Apply force to a world point. This could for example be a point on the RigidBody surface. Applying force this way will add to Body.force and Body.angularForce.
  6031. * @method applyForce
  6032. * @param {Array} force The force to add.
  6033. * @param {Array} worldPoint A world point to apply the force on.
  6034. */
  6035. Body.prototype.applyForce = function(force,worldPoint){
  6036. // Compute point position relative to the body center
  6037. var r = Body_applyForce_r;
  6038. vec2.sub(r,worldPoint,this.position);
  6039. // Add linear force
  6040. vec2.add(this.force,this.force,force);
  6041. // Compute produced rotational force
  6042. var rotForce = vec2.crossLength(r,force);
  6043. // Add rotational force
  6044. this.angularForce += rotForce;
  6045. };
  6046. /**
  6047. * Transform a world point to local body frame.
  6048. * @method toLocalFrame
  6049. * @param {Array} out The vector to store the result in
  6050. * @param {Array} worldPoint The input world vector
  6051. */
  6052. Body.prototype.toLocalFrame = function(out, worldPoint){
  6053. vec2.toLocalFrame(out, worldPoint, this.position, this.angle);
  6054. };
  6055. /**
  6056. * Transform a local point to world frame.
  6057. * @method toWorldFrame
  6058. * @param {Array} out The vector to store the result in
  6059. * @param {Array} localPoint The input local vector
  6060. */
  6061. Body.prototype.toWorldFrame = function(out, localPoint){
  6062. vec2.toGlobalFrame(out, localPoint, this.position, this.angle);
  6063. };
  6064. /**
  6065. * Reads a polygon shape path, and assembles convex shapes from that and puts them at proper offset points.
  6066. * @method fromPolygon
  6067. * @param {Array} path An array of 2d vectors, e.g. [[0,0],[0,1],...] that resembles a concave or convex polygon. The shape must be simple and without holes.
  6068. * @param {Object} [options]
  6069. * @param {Boolean} [options.optimalDecomp=false] Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  6070. * @param {Boolean} [options.skipSimpleCheck=false] Set to true if you already know that the path is not intersecting itself.
  6071. * @param {Boolean|Number} [options.removeCollinearPoints=false] Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  6072. * @return {Boolean} True on success, else false.
  6073. */
  6074. Body.prototype.fromPolygon = function(path,options){
  6075. options = options || {};
  6076. // Remove all shapes
  6077. for(var i=this.shapes.length; i>=0; --i)
  6078. this.removeShape(this.shapes[i]);
  6079. var p = new decomp.Polygon();
  6080. p.vertices = path;
  6081. // Make it counter-clockwise
  6082. p.makeCCW();
  6083. if(typeof(options.removeCollinearPoints)=="number"){
  6084. p.removeCollinearPoints(options.removeCollinearPoints);
  6085. }
  6086. // Check if any line segment intersects the path itself
  6087. if(typeof(options.skipSimpleCheck) == "undefined"){
  6088. if(!p.isSimple()) return false;
  6089. }
  6090. // Save this path for later
  6091. this.concavePath = p.vertices.slice(0);
  6092. for(var i=0; i<this.concavePath.length; i++){
  6093. var v = [0,0];
  6094. vec2.copy(v,this.concavePath[i]);
  6095. this.concavePath[i] = v;
  6096. }
  6097. // Slow or fast decomp?
  6098. var convexes;
  6099. if(options.optimalDecomp) convexes = p.decomp();
  6100. else convexes = p.quickDecomp();
  6101. var cm = vec2.create();
  6102. // Add convexes
  6103. for(var i=0; i!==convexes.length; i++){
  6104. // Create convex
  6105. var c = new Convex(convexes[i].vertices);
  6106. // Move all vertices so its center of mass is in the local center of the convex
  6107. for(var j=0; j!==c.vertices.length; j++){
  6108. var v = c.vertices[j];
  6109. vec2.sub(v,v,c.centerOfMass);
  6110. }
  6111. vec2.scale(cm,c.centerOfMass,1);
  6112. c.updateTriangles();
  6113. c.updateCenterOfMass();
  6114. c.updateBoundingRadius();
  6115. // Add the shape
  6116. this.addShape(c,cm);
  6117. }
  6118. this.adjustCenterOfMass();
  6119. this.aabbNeedsUpdate = true;
  6120. return true;
  6121. };
  6122. var adjustCenterOfMass_tmp1 = vec2.fromValues(0,0),
  6123. adjustCenterOfMass_tmp2 = vec2.fromValues(0,0),
  6124. adjustCenterOfMass_tmp3 = vec2.fromValues(0,0),
  6125. adjustCenterOfMass_tmp4 = vec2.fromValues(0,0);
  6126. /**
  6127. * Moves the shape offsets so their center of mass becomes the body center of mass.
  6128. * @method adjustCenterOfMass
  6129. */
  6130. Body.prototype.adjustCenterOfMass = function(){
  6131. var offset_times_area = adjustCenterOfMass_tmp2,
  6132. sum = adjustCenterOfMass_tmp3,
  6133. cm = adjustCenterOfMass_tmp4,
  6134. totalArea = 0;
  6135. vec2.set(sum,0,0);
  6136. for(var i=0; i!==this.shapes.length; i++){
  6137. var s = this.shapes[i],
  6138. offset = this.shapeOffsets[i];
  6139. vec2.scale(offset_times_area,offset,s.area);
  6140. vec2.add(sum,sum,offset_times_area);
  6141. totalArea += s.area;
  6142. }
  6143. vec2.scale(cm,sum,1/totalArea);
  6144. // Now move all shapes
  6145. for(var i=0; i!==this.shapes.length; i++){
  6146. var s = this.shapes[i],
  6147. offset = this.shapeOffsets[i];
  6148. // Offset may be undefined. Fix that.
  6149. if(!offset){
  6150. offset = this.shapeOffsets[i] = vec2.create();
  6151. }
  6152. vec2.sub(offset,offset,cm);
  6153. }
  6154. // Move the body position too
  6155. vec2.add(this.position,this.position,cm);
  6156. // And concave path
  6157. for(var i=0; this.concavePath && i<this.concavePath.length; i++){
  6158. vec2.sub(this.concavePath[i], this.concavePath[i], cm);
  6159. }
  6160. this.updateMassProperties();
  6161. this.updateBoundingRadius();
  6162. };
  6163. /**
  6164. * Sets the force on the body to zero.
  6165. * @method setZeroForce
  6166. */
  6167. Body.prototype.setZeroForce = function(){
  6168. vec2.set(this.force,0.0,0.0);
  6169. this.angularForce = 0.0;
  6170. };
  6171. Body.prototype.resetConstraintVelocity = function(){
  6172. var b = this,
  6173. vlambda = b.vlambda;
  6174. vec2.set(vlambda,0,0);
  6175. b.wlambda = 0;
  6176. };
  6177. Body.prototype.addConstraintVelocity = function(){
  6178. var b = this,
  6179. v = b.velocity;
  6180. vec2.add( v, v, b.vlambda);
  6181. b.angularVelocity += b.wlambda;
  6182. };
  6183. /**
  6184. * Apply damping, see <a href="http://code.google.com/p/bullet/issues/detail?id=74">this</a> for details.
  6185. * @method applyDamping
  6186. * @param {number} dt Current time step
  6187. */
  6188. Body.prototype.applyDamping = function(dt){
  6189. if(this.motionState === Body.DYNAMIC){ // Only for dynamic bodies
  6190. // Since Math.pow generates garbage we check if we can reuse the scaling coefficient from last step
  6191. if(dt !== this.lastDampingTimeStep){
  6192. this.lastDampingScale = Math.pow(1.0 - this.damping,dt);
  6193. this.lastAngularDampingScale = Math.pow(1.0 - this.angularDamping,dt);
  6194. this.lastDampingTimeStep = dt;
  6195. }
  6196. var v = this.velocity;
  6197. vec2.scale(v,v,this.lastDampingScale);
  6198. this.angularVelocity *= this.lastAngularDampingScale;
  6199. }
  6200. };
  6201. /**
  6202. * Wake the body up. Normally you should not need this, as the body is automatically awoken at events such as collisions.
  6203. * Sets the sleepState to {{#crossLink "Body/AWAKE:property"}}Body.AWAKE{{/crossLink}} and emits the wakeUp event if the body wasn't awake before.
  6204. * @method wakeUp
  6205. */
  6206. Body.prototype.wakeUp = function(){
  6207. var s = this.sleepState;
  6208. this.sleepState = Body.AWAKE;
  6209. this.idleTime = 0;
  6210. if(s !== Body.AWAKE){
  6211. this.emit(Body.wakeUpEvent);
  6212. }
  6213. };
  6214. /**
  6215. * Force body sleep
  6216. * @method sleep
  6217. */
  6218. Body.prototype.sleep = function(){
  6219. this.sleepState = Body.SLEEPING;
  6220. this.angularVelocity = 0;
  6221. this.angularForce = 0;
  6222. vec2.set(this.velocity,0,0);
  6223. vec2.set(this.force,0,0);
  6224. this.emit(Body.sleepEvent);
  6225. };
  6226. //var velo2 = vec2.create();
  6227. /**
  6228. * @method sleepTick
  6229. * @param float time The world time in seconds
  6230. * @brief Called every timestep to update internal sleep timer and change sleep state if needed.
  6231. */
  6232. Body.prototype.sleepTick = function(time, dontSleep, dt){
  6233. if(!this.allowSleep || this.motionState === Body.SLEEPING){
  6234. return;
  6235. }
  6236. this.wantsToSleep = false;
  6237. var sleepState = this.sleepState,
  6238. speedSquared = vec2.squaredLength(this.velocity) + Math.pow(this.angularVelocity,2),
  6239. speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
  6240. // Add to idle time
  6241. if(speedSquared >= speedLimitSquared){
  6242. this.idleTime = 0;
  6243. this.sleepState = Body.AWAKE;
  6244. } else {
  6245. this.idleTime += dt;
  6246. this.sleepState = Body.SLEEPY;
  6247. }
  6248. if(this.idleTime > this.sleepTimeLimit){
  6249. if(!dontSleep){
  6250. this.sleep();
  6251. } else {
  6252. this.wantsToSleep = true;
  6253. }
  6254. }
  6255. /*
  6256. if(sleepState===Body.AWAKE && speedSquared < speedLimitSquared){
  6257. this.sleepState = Body.SLEEPY; // Sleepy
  6258. this.timeLastSleepy = time;
  6259. this.emit(Body.sleepyEvent);
  6260. } else if(sleepState===Body.SLEEPY && speedSquared >= speedLimitSquared){
  6261. this.wakeUp(); // Wake up
  6262. } else if(sleepState===Body.SLEEPY && (time - this.timeLastSleepy ) > this.sleepTimeLimit){
  6263. this.wantsToSleep = true;
  6264. if(!dontSleep){
  6265. this.sleep();
  6266. }
  6267. }
  6268. */
  6269. };
  6270. Body.prototype.getVelocityFromPosition = function(store, timeStep){
  6271. store = store || vec2.create();
  6272. vec2.sub(store, this.position, this.previousPosition);
  6273. vec2.scale(store, store, 1/timeStep);
  6274. return store;
  6275. };
  6276. Body.prototype.getAngularVelocityFromPosition = function(timeStep){
  6277. return (this.angle - this.previousAngle) / timeStep;
  6278. };
  6279. /**
  6280. * @event sleepy
  6281. */
  6282. Body.sleepyEvent = {
  6283. type: "sleepy"
  6284. };
  6285. /**
  6286. * @event sleep
  6287. */
  6288. Body.sleepEvent = {
  6289. type: "sleep"
  6290. };
  6291. /**
  6292. * @event wakeup
  6293. */
  6294. Body.wakeUpEvent = {
  6295. type: "wakeup"
  6296. };
  6297. /**
  6298. * Dynamic body.
  6299. * @property DYNAMIC
  6300. * @type {Number}
  6301. * @static
  6302. */
  6303. Body.DYNAMIC = 1;
  6304. /**
  6305. * Static body.
  6306. * @property STATIC
  6307. * @type {Number}
  6308. * @static
  6309. */
  6310. Body.STATIC = 2;
  6311. /**
  6312. * Kinematic body.
  6313. * @property KINEMATIC
  6314. * @type {Number}
  6315. * @static
  6316. */
  6317. Body.KINEMATIC = 4;
  6318. /**
  6319. * @property AWAKE
  6320. * @type {Number}
  6321. * @static
  6322. */
  6323. Body.AWAKE = 0;
  6324. /**
  6325. * @property SLEEPY
  6326. * @type {Number}
  6327. * @static
  6328. */
  6329. Body.SLEEPY = 1;
  6330. /**
  6331. * @property SLEEPING
  6332. * @type {Number}
  6333. * @static
  6334. */
  6335. Body.SLEEPING = 2;
  6336. },{"../collision/AABB":8,"../events/EventEmitter":26,"../math/vec2":30,"../shapes/Convex":36,"poly-decomp":6}],32:[function(require,module,exports){
  6337. var vec2 = require('../math/vec2');
  6338. module.exports = Spring;
  6339. /**
  6340. * A spring, connecting two bodies. The Spring explicitly adds force and angularForce to the bodies and does therefore not put load on the solver.
  6341. *
  6342. * @class Spring
  6343. * @constructor
  6344. * @param {Body} bodyA
  6345. * @param {Body} bodyB
  6346. * @param {Object} [options]
  6347. * @param {number} [options.restLength=1] A number > 0. Default: 1
  6348. * @param {number} [options.stiffness=100] Spring constant (see Hookes Law). A number >= 0.
  6349. * @param {number} [options.damping=1] A number >= 0. Default: 1
  6350. * @param {Array} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates. Overrides the option "localAnchorA" if given.
  6351. * @param {Array} [options.worldAnchorB]
  6352. * @param {Array} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates. Defaults to the body center.
  6353. * @param {Array} [options.localAnchorB]
  6354. */
  6355. function Spring(bodyA,bodyB,options){
  6356. options = options || {};
  6357. /**
  6358. * Rest length of the spring.
  6359. * @property restLength
  6360. * @type {number}
  6361. */
  6362. this.restLength = typeof(options.restLength)=="number" ? options.restLength : 1;
  6363. /**
  6364. * Stiffness of the spring.
  6365. * @property stiffness
  6366. * @type {number}
  6367. */
  6368. this.stiffness = options.stiffness || 100;
  6369. /**
  6370. * Damping of the spring.
  6371. * @property damping
  6372. * @type {number}
  6373. */
  6374. this.damping = options.damping || 1;
  6375. /**
  6376. * First connected body.
  6377. * @property bodyA
  6378. * @type {Body}
  6379. */
  6380. this.bodyA = bodyA;
  6381. /**
  6382. * Second connected body.
  6383. * @property bodyB
  6384. * @type {Body}
  6385. */
  6386. this.bodyB = bodyB;
  6387. /**
  6388. * Anchor for bodyA in local bodyA coordinates.
  6389. * @property localAnchorA
  6390. * @type {Array}
  6391. */
  6392. this.localAnchorA = vec2.fromValues(0,0);
  6393. /**
  6394. * Anchor for bodyB in local bodyB coordinates.
  6395. * @property localAnchorB
  6396. * @type {Array}
  6397. */
  6398. this.localAnchorB = vec2.fromValues(0,0);
  6399. if(options.localAnchorA) vec2.copy(this.localAnchorA, options.localAnchorA);
  6400. if(options.localAnchorB) vec2.copy(this.localAnchorB, options.localAnchorB);
  6401. if(options.worldAnchorA) this.setWorldAnchorA(options.worldAnchorA);
  6402. if(options.worldAnchorB) this.setWorldAnchorB(options.worldAnchorB);
  6403. };
  6404. /**
  6405. * Set the anchor point on body A, using world coordinates.
  6406. * @method setWorldAnchorA
  6407. * @param {Array} worldAnchorA
  6408. */
  6409. Spring.prototype.setWorldAnchorA = function(worldAnchorA){
  6410. this.bodyA.toLocalFrame(this.localAnchorA, worldAnchorA);
  6411. };
  6412. /**
  6413. * Set the anchor point on body B, using world coordinates.
  6414. * @method setWorldAnchorB
  6415. * @param {Array} worldAnchorB
  6416. */
  6417. Spring.prototype.setWorldAnchorB = function(worldAnchorB){
  6418. this.bodyB.toLocalFrame(this.localAnchorB, worldAnchorB);
  6419. };
  6420. /**
  6421. * Get the anchor point on body A, in world coordinates.
  6422. * @method getWorldAnchorA
  6423. * @param {Array} result The vector to store the result in.
  6424. */
  6425. Spring.prototype.getWorldAnchorA = function(result){
  6426. this.bodyA.toWorldFrame(result, this.localAnchorA);
  6427. };
  6428. /**
  6429. * Get the anchor point on body B, in world coordinates.
  6430. * @method getWorldAnchorB
  6431. * @param {Array} result The vector to store the result in.
  6432. */
  6433. Spring.prototype.getWorldAnchorB = function(result){
  6434. this.bodyB.toWorldFrame(result, this.localAnchorB);
  6435. };
  6436. var applyForce_r = vec2.create(),
  6437. applyForce_r_unit = vec2.create(),
  6438. applyForce_u = vec2.create(),
  6439. applyForce_f = vec2.create(),
  6440. applyForce_worldAnchorA = vec2.create(),
  6441. applyForce_worldAnchorB = vec2.create(),
  6442. applyForce_ri = vec2.create(),
  6443. applyForce_rj = vec2.create(),
  6444. applyForce_tmp = vec2.create();
  6445. /**
  6446. * Apply the spring force to the connected bodies.
  6447. * @method applyForce
  6448. */
  6449. Spring.prototype.applyForce = function(){
  6450. var k = this.stiffness,
  6451. d = this.damping,
  6452. l = this.restLength,
  6453. bodyA = this.bodyA,
  6454. bodyB = this.bodyB,
  6455. r = applyForce_r,
  6456. r_unit = applyForce_r_unit,
  6457. u = applyForce_u,
  6458. f = applyForce_f,
  6459. tmp = applyForce_tmp;
  6460. var worldAnchorA = applyForce_worldAnchorA,
  6461. worldAnchorB = applyForce_worldAnchorB,
  6462. ri = applyForce_ri,
  6463. rj = applyForce_rj;
  6464. // Get world anchors
  6465. this.getWorldAnchorA(worldAnchorA);
  6466. this.getWorldAnchorB(worldAnchorB);
  6467. // Get offset points
  6468. vec2.sub(ri, worldAnchorA, bodyA.position);
  6469. vec2.sub(rj, worldAnchorB, bodyB.position);
  6470. // Compute distance vector between world anchor points
  6471. vec2.sub(r, worldAnchorB, worldAnchorA);
  6472. var rlen = vec2.len(r);
  6473. vec2.normalize(r_unit,r);
  6474. //console.log(rlen)
  6475. //console.log("A",vec2.str(worldAnchorA),"B",vec2.str(worldAnchorB))
  6476. // Compute relative velocity of the anchor points, u
  6477. vec2.sub(u, bodyB.velocity, bodyA.velocity);
  6478. vec2.crossZV(tmp, bodyB.angularVelocity, rj);
  6479. vec2.add(u, u, tmp);
  6480. vec2.crossZV(tmp, bodyA.angularVelocity, ri);
  6481. vec2.sub(u, u, tmp);
  6482. // F = - k * ( x - L ) - D * ( u )
  6483. vec2.scale(f, r_unit, -k*(rlen-l) - d*vec2.dot(u,r_unit));
  6484. // Add forces to bodies
  6485. vec2.sub( bodyA.force, bodyA.force, f);
  6486. vec2.add( bodyB.force, bodyB.force, f);
  6487. // Angular force
  6488. var ri_x_f = vec2.crossLength(ri, f);
  6489. var rj_x_f = vec2.crossLength(rj, f);
  6490. bodyA.angularForce -= ri_x_f;
  6491. bodyB.angularForce += rj_x_f;
  6492. };
  6493. },{"../math/vec2":30}],33:[function(require,module,exports){
  6494. // Export p2 classes
  6495. module.exports = {
  6496. AABB : require('./collision/AABB'),
  6497. AngleLockEquation : require('./equations/AngleLockEquation'),
  6498. Body : require('./objects/Body'),
  6499. Broadphase : require('./collision/Broadphase'),
  6500. Capsule : require('./shapes/Capsule'),
  6501. Circle : require('./shapes/Circle'),
  6502. Constraint : require('./constraints/Constraint'),
  6503. ContactEquation : require('./equations/ContactEquation'),
  6504. ContactMaterial : require('./material/ContactMaterial'),
  6505. Convex : require('./shapes/Convex'),
  6506. DistanceConstraint : require('./constraints/DistanceConstraint'),
  6507. Equation : require('./equations/Equation'),
  6508. EventEmitter : require('./events/EventEmitter'),
  6509. FrictionEquation : require('./equations/FrictionEquation'),
  6510. GearConstraint : require('./constraints/GearConstraint'),
  6511. GridBroadphase : require('./collision/GridBroadphase'),
  6512. GSSolver : require('./solver/GSSolver'),
  6513. Heightfield : require('./shapes/Heightfield'),
  6514. Line : require('./shapes/Line'),
  6515. LockConstraint : require('./constraints/LockConstraint'),
  6516. Material : require('./material/Material'),
  6517. Narrowphase : require('./collision/Narrowphase'),
  6518. NaiveBroadphase : require('./collision/NaiveBroadphase'),
  6519. Particle : require('./shapes/Particle'),
  6520. Plane : require('./shapes/Plane'),
  6521. RevoluteConstraint : require('./constraints/RevoluteConstraint'),
  6522. PrismaticConstraint : require('./constraints/PrismaticConstraint'),
  6523. Rectangle : require('./shapes/Rectangle'),
  6524. RotationalVelocityEquation : require('./equations/RotationalVelocityEquation'),
  6525. SAPBroadphase : require('./collision/SAPBroadphase'),
  6526. Shape : require('./shapes/Shape'),
  6527. Solver : require('./solver/Solver'),
  6528. Spring : require('./objects/Spring'),
  6529. Utils : require('./utils/Utils'),
  6530. World : require('./world/World'),
  6531. vec2 : require('./math/vec2'),
  6532. version : require('../package.json').version,
  6533. };
  6534. },{"../package.json":7,"./collision/AABB":8,"./collision/Broadphase":9,"./collision/GridBroadphase":10,"./collision/NaiveBroadphase":11,"./collision/Narrowphase":12,"./collision/SAPBroadphase":13,"./constraints/Constraint":14,"./constraints/DistanceConstraint":15,"./constraints/GearConstraint":16,"./constraints/LockConstraint":17,"./constraints/PrismaticConstraint":18,"./constraints/RevoluteConstraint":19,"./equations/AngleLockEquation":20,"./equations/ContactEquation":21,"./equations/Equation":22,"./equations/FrictionEquation":23,"./equations/RotationalVelocityEquation":25,"./events/EventEmitter":26,"./material/ContactMaterial":27,"./material/Material":28,"./math/vec2":30,"./objects/Body":31,"./objects/Spring":32,"./shapes/Capsule":34,"./shapes/Circle":35,"./shapes/Convex":36,"./shapes/Heightfield":37,"./shapes/Line":38,"./shapes/Particle":39,"./shapes/Plane":40,"./shapes/Rectangle":41,"./shapes/Shape":42,"./solver/GSSolver":43,"./solver/Solver":44,"./utils/Utils":45,"./world/World":49}],34:[function(require,module,exports){
  6535. var Shape = require('./Shape')
  6536. , vec2 = require('../math/vec2');
  6537. module.exports = Capsule;
  6538. /**
  6539. * Capsule shape class.
  6540. * @class Capsule
  6541. * @constructor
  6542. * @extends Shape
  6543. * @param {Number} [length] The distance between the end points
  6544. * @param {Number} [radius] Radius of the capsule
  6545. */
  6546. function Capsule(length,radius){
  6547. /**
  6548. * The distance between the end points.
  6549. * @property {Number} length
  6550. */
  6551. this.length = length || 1;
  6552. /**
  6553. * The radius of the capsule.
  6554. * @property {Number} radius
  6555. */
  6556. this.radius = radius || 1;
  6557. Shape.call(this,Shape.CAPSULE);
  6558. }
  6559. Capsule.prototype = new Shape();
  6560. /**
  6561. * Compute the mass moment of inertia of the Capsule.
  6562. * @method conputeMomentOfInertia
  6563. * @param {Number} mass
  6564. * @return {Number}
  6565. * @todo
  6566. */
  6567. Capsule.prototype.computeMomentOfInertia = function(mass){
  6568. // Approximate with rectangle
  6569. var r = this.radius,
  6570. w = this.length + r, // 2*r is too much, 0 is too little
  6571. h = r*2;
  6572. return mass * (h*h + w*w) / 12;
  6573. };
  6574. /**
  6575. * @method updateBoundingRadius
  6576. */
  6577. Capsule.prototype.updateBoundingRadius = function(){
  6578. this.boundingRadius = this.radius + this.length/2;
  6579. };
  6580. /**
  6581. * @method updateArea
  6582. */
  6583. Capsule.prototype.updateArea = function(){
  6584. this.area = Math.PI * this.radius * this.radius + this.radius * 2 * this.length;
  6585. };
  6586. var r = vec2.create();
  6587. /**
  6588. * @method computeAABB
  6589. * @param {AABB} out The resulting AABB.
  6590. * @param {Array} position
  6591. * @param {Number} angle
  6592. */
  6593. Capsule.prototype.computeAABB = function(out, position, angle){
  6594. var radius = this.radius;
  6595. // Compute center position of one of the the circles, world oriented, but with local offset
  6596. vec2.set(r,this.length,0);
  6597. vec2.rotate(r,r,angle);
  6598. // Get bounds
  6599. vec2.set(out.upperBound, Math.max(r[0]+radius, -r[0]+radius),
  6600. Math.max(r[1]+radius, -r[1]+radius));
  6601. vec2.set(out.lowerBound, Math.min(r[0]-radius, -r[0]-radius),
  6602. Math.min(r[1]-radius, -r[1]-radius));
  6603. // Add offset
  6604. vec2.add(out.lowerBound, out.lowerBound, position);
  6605. vec2.add(out.upperBound, out.upperBound, position);
  6606. };
  6607. },{"../math/vec2":30,"./Shape":42}],35:[function(require,module,exports){
  6608. var Shape = require('./Shape')
  6609. , vec2 = require('../math/vec2')
  6610. module.exports = Circle;
  6611. /**
  6612. * Circle shape class.
  6613. * @class Circle
  6614. * @extends Shape
  6615. * @constructor
  6616. * @param {number} [radius=1] The radius of this circle
  6617. */
  6618. function Circle(radius){
  6619. /**
  6620. * The radius of the circle.
  6621. * @property radius
  6622. * @type {number}
  6623. */
  6624. this.radius = radius || 1;
  6625. Shape.call(this,Shape.CIRCLE);
  6626. };
  6627. Circle.prototype = new Shape();
  6628. /**
  6629. * @method computeMomentOfInertia
  6630. * @param {Number} mass
  6631. * @return {Number}
  6632. */
  6633. Circle.prototype.computeMomentOfInertia = function(mass){
  6634. var r = this.radius;
  6635. return mass * r * r / 2;
  6636. };
  6637. /**
  6638. * @method updateBoundingRadius
  6639. * @return {Number}
  6640. */
  6641. Circle.prototype.updateBoundingRadius = function(){
  6642. this.boundingRadius = this.radius;
  6643. };
  6644. /**
  6645. * @method updateArea
  6646. * @return {Number}
  6647. */
  6648. Circle.prototype.updateArea = function(){
  6649. this.area = Math.PI * this.radius * this.radius;
  6650. };
  6651. /**
  6652. * @method computeAABB
  6653. * @param {AABB} out The resulting AABB.
  6654. * @param {Array} position
  6655. * @param {Number} angle
  6656. */
  6657. Circle.prototype.computeAABB = function(out, position, angle){
  6658. var r = this.radius;
  6659. vec2.set(out.upperBound, r, r);
  6660. vec2.set(out.lowerBound, -r, -r);
  6661. if(position){
  6662. vec2.add(out.lowerBound, out.lowerBound, position);
  6663. vec2.add(out.upperBound, out.upperBound, position);
  6664. }
  6665. };
  6666. },{"../math/vec2":30,"./Shape":42}],36:[function(require,module,exports){
  6667. var Shape = require('./Shape')
  6668. , vec2 = require('../math/vec2')
  6669. , polyk = require('../math/polyk')
  6670. , decomp = require('poly-decomp')
  6671. module.exports = Convex;
  6672. /**
  6673. * Convex shape class.
  6674. * @class Convex
  6675. * @constructor
  6676. * @extends Shape
  6677. * @param {Array} vertices An array of Float32Array vertices that span this shape. Vertices are given in counter-clockwise (CCW) direction.
  6678. */
  6679. function Convex(vertices){
  6680. /**
  6681. * Vertices defined in the local frame.
  6682. * @property vertices
  6683. * @type {Array}
  6684. */
  6685. this.vertices = [];
  6686. // Copy the verts
  6687. for(var i=0; i<vertices.length; i++){
  6688. var v = vec2.create();
  6689. vec2.copy(v,vertices[i]);
  6690. this.vertices.push(v);
  6691. }
  6692. /**
  6693. * The center of mass of the Convex
  6694. * @property centerOfMass
  6695. * @type {Float32Array}
  6696. */
  6697. this.centerOfMass = vec2.fromValues(0,0);
  6698. /**
  6699. * Triangulated version of this convex. The structure is Array of 3-Arrays, and each subarray contains 3 integers, referencing the vertices.
  6700. * @property triangles
  6701. * @type {Array}
  6702. */
  6703. this.triangles = [];
  6704. if(this.vertices.length){
  6705. this.updateTriangles();
  6706. this.updateCenterOfMass();
  6707. }
  6708. /**
  6709. * The bounding radius of the convex
  6710. * @property boundingRadius
  6711. * @type {Number}
  6712. */
  6713. this.boundingRadius = 0;
  6714. Shape.call(this,Shape.CONVEX);
  6715. this.updateBoundingRadius();
  6716. this.updateArea();
  6717. if(this.area < 0)
  6718. throw new Error("Convex vertices must be given in conter-clockwise winding.");
  6719. };
  6720. Convex.prototype = new Shape();
  6721. /**
  6722. * Update the .triangles property
  6723. * @method updateTriangles
  6724. */
  6725. Convex.prototype.updateTriangles = function(){
  6726. this.triangles.length = 0;
  6727. // Rewrite on polyk notation, array of numbers
  6728. var polykVerts = [];
  6729. for(var i=0; i<this.vertices.length; i++){
  6730. var v = this.vertices[i];
  6731. polykVerts.push(v[0],v[1]);
  6732. }
  6733. // Triangulate
  6734. var triangles = polyk.Triangulate(polykVerts);
  6735. // Loop over all triangles, add their inertia contributions to I
  6736. for(var i=0; i<triangles.length; i+=3){
  6737. var id1 = triangles[i],
  6738. id2 = triangles[i+1],
  6739. id3 = triangles[i+2];
  6740. // Add to triangles
  6741. this.triangles.push([id1,id2,id3]);
  6742. }
  6743. };
  6744. var updateCenterOfMass_centroid = vec2.create(),
  6745. updateCenterOfMass_centroid_times_mass = vec2.create(),
  6746. updateCenterOfMass_a = vec2.create(),
  6747. updateCenterOfMass_b = vec2.create(),
  6748. updateCenterOfMass_c = vec2.create(),
  6749. updateCenterOfMass_ac = vec2.create(),
  6750. updateCenterOfMass_ca = vec2.create(),
  6751. updateCenterOfMass_cb = vec2.create(),
  6752. updateCenterOfMass_n = vec2.create();
  6753. /**
  6754. * Update the .centerOfMass property.
  6755. * @method updateCenterOfMass
  6756. */
  6757. Convex.prototype.updateCenterOfMass = function(){
  6758. var triangles = this.triangles,
  6759. verts = this.vertices,
  6760. cm = this.centerOfMass,
  6761. centroid = updateCenterOfMass_centroid,
  6762. n = updateCenterOfMass_n,
  6763. a = updateCenterOfMass_a,
  6764. b = updateCenterOfMass_b,
  6765. c = updateCenterOfMass_c,
  6766. ac = updateCenterOfMass_ac,
  6767. ca = updateCenterOfMass_ca,
  6768. cb = updateCenterOfMass_cb,
  6769. centroid_times_mass = updateCenterOfMass_centroid_times_mass;
  6770. vec2.set(cm,0,0);
  6771. var totalArea = 0;
  6772. for(var i=0; i!==triangles.length; i++){
  6773. var t = triangles[i],
  6774. a = verts[t[0]],
  6775. b = verts[t[1]],
  6776. c = verts[t[2]];
  6777. vec2.centroid(centroid,a,b,c);
  6778. // Get mass for the triangle (density=1 in this case)
  6779. // http://math.stackexchange.com/questions/80198/area-of-triangle-via-vectors
  6780. var m = Convex.triangleArea(a,b,c)
  6781. totalArea += m;
  6782. // Add to center of mass
  6783. vec2.scale(centroid_times_mass, centroid, m);
  6784. vec2.add(cm, cm, centroid_times_mass);
  6785. }
  6786. vec2.scale(cm,cm,1/totalArea);
  6787. };
  6788. /**
  6789. * Compute the mass moment of inertia of the Convex.
  6790. * @method computeMomentOfInertia
  6791. * @param {Number} mass
  6792. * @return {Number}
  6793. * @see http://www.gamedev.net/topic/342822-moment-of-inertia-of-a-polygon-2d/
  6794. */
  6795. Convex.prototype.computeMomentOfInertia = function(mass){
  6796. var denom = 0.0,
  6797. numer = 0.0,
  6798. N = this.vertices.length;
  6799. for(var j = N-1, i = 0; i < N; j = i, i ++){
  6800. var p0 = this.vertices[j];
  6801. var p1 = this.vertices[i];
  6802. var a = Math.abs(vec2.crossLength(p0,p1));
  6803. var b = vec2.dot(p1,p1) + vec2.dot(p1,p0) + vec2.dot(p0,p0);
  6804. denom += a * b;
  6805. numer += a;
  6806. }
  6807. return (mass / 6.0) * (denom / numer);
  6808. };
  6809. /**
  6810. * Updates the .boundingRadius property
  6811. * @method updateBoundingRadius
  6812. */
  6813. Convex.prototype.updateBoundingRadius = function(){
  6814. var verts = this.vertices,
  6815. r2 = 0;
  6816. for(var i=0; i!==verts.length; i++){
  6817. var l2 = vec2.squaredLength(verts[i]);
  6818. if(l2 > r2) r2 = l2;
  6819. }
  6820. this.boundingRadius = Math.sqrt(r2);
  6821. };
  6822. /**
  6823. * Get the area of the triangle spanned by the three points a, b, c. The area is positive if the points are given in counter-clockwise order, otherwise negative.
  6824. * @static
  6825. * @method triangleArea
  6826. * @param {Array} a
  6827. * @param {Array} b
  6828. * @param {Array} c
  6829. * @return {Number}
  6830. */
  6831. Convex.triangleArea = function(a,b,c){
  6832. return (((b[0] - a[0])*(c[1] - a[1]))-((c[0] - a[0])*(b[1] - a[1]))) * 0.5;
  6833. }
  6834. /**
  6835. * Update the .area
  6836. * @method updateArea
  6837. */
  6838. Convex.prototype.updateArea = function(){
  6839. this.updateTriangles();
  6840. this.area = 0;
  6841. var triangles = this.triangles,
  6842. verts = this.vertices;
  6843. for(var i=0; i!==triangles.length; i++){
  6844. var t = triangles[i],
  6845. a = verts[t[0]],
  6846. b = verts[t[1]],
  6847. c = verts[t[2]];
  6848. // Get mass for the triangle (density=1 in this case)
  6849. var m = Convex.triangleArea(a,b,c);
  6850. this.area += m;
  6851. }
  6852. };
  6853. /**
  6854. * @method computeAABB
  6855. * @param {AABB} out
  6856. * @param {Array} position
  6857. * @param {Number} angle
  6858. */
  6859. Convex.prototype.computeAABB = function(out, position, angle){
  6860. out.setFromPoints(this.vertices,position,angle);
  6861. };
  6862. },{"../math/polyk":29,"../math/vec2":30,"./Shape":42,"poly-decomp":6}],37:[function(require,module,exports){
  6863. var Shape = require('./Shape')
  6864. , vec2 = require('../math/vec2');
  6865. module.exports = Heightfield;
  6866. /**
  6867. * Heightfield shape class. Height data is given as an array. These data points are spread out evenly with a distance "elementWidth".
  6868. * @class Heightfield
  6869. * @extends Shape
  6870. * @constructor
  6871. * @param {Array} data
  6872. * @param {Number} maxValue
  6873. * @param {Number} elementWidth
  6874. * @todo Should take maxValue as an option and also be able to compute it itself if not given.
  6875. * @todo Should be possible to use along all axes, not just y
  6876. */
  6877. function Heightfield(data,maxValue,elementWidth){
  6878. /**
  6879. * An array of numbers, or height values, that are spread out along the x axis.
  6880. * @property {array} data
  6881. */
  6882. this.data = data;
  6883. /**
  6884. * Max value of the data
  6885. * @property {number} maxValue
  6886. */
  6887. this.maxValue = maxValue;
  6888. /**
  6889. * The width of each element
  6890. * @property {number} elementWidth
  6891. */
  6892. this.elementWidth = elementWidth;
  6893. Shape.call(this,Shape.HEIGHTFIELD);
  6894. }
  6895. Heightfield.prototype = new Shape();
  6896. /**
  6897. * @method computeMomentOfInertia
  6898. * @param {Number} mass
  6899. * @return {Number}
  6900. */
  6901. Heightfield.prototype.computeMomentOfInertia = function(mass){
  6902. return Number.MAX_VALUE;
  6903. };
  6904. Heightfield.prototype.updateBoundingRadius = function(){
  6905. this.boundingRadius = Number.MAX_VALUE;
  6906. };
  6907. Heightfield.prototype.updateArea = function(){
  6908. var data = this.data,
  6909. area = 0;
  6910. for(var i=0; i<data.length-1; i++){
  6911. area += (data[i]+data[i+1]) / 2 * this.elementWidth;
  6912. }
  6913. this.area = area;
  6914. };
  6915. /**
  6916. * @method computeAABB
  6917. * @param {AABB} out The resulting AABB.
  6918. * @param {Array} position
  6919. * @param {Number} angle
  6920. */
  6921. Heightfield.prototype.computeAABB = function(out, position, angle){
  6922. // Use the max data rectangle
  6923. out.upperBound[0] = this.elementWidth * this.data.length + position[0];
  6924. out.upperBound[1] = this.maxValue + position[1];
  6925. out.lowerBound[0] = position[0];
  6926. out.lowerBound[1] = -Number.MAX_VALUE; // Infinity
  6927. };
  6928. },{"../math/vec2":30,"./Shape":42}],38:[function(require,module,exports){
  6929. var Shape = require('./Shape')
  6930. , vec2 = require('../math/vec2')
  6931. module.exports = Line;
  6932. /**
  6933. * Line shape class. The line shape is along the x direction, and stretches from [-length/2, 0] to [length/2,0].
  6934. * @class Line
  6935. * @param {Number} length The total length of the line
  6936. * @extends Shape
  6937. * @constructor
  6938. */
  6939. function Line(length){
  6940. /**
  6941. * Length of this line
  6942. * @property length
  6943. * @type {Number}
  6944. */
  6945. this.length = length;
  6946. Shape.call(this,Shape.LINE);
  6947. };
  6948. Line.prototype = new Shape();
  6949. Line.prototype.computeMomentOfInertia = function(mass){
  6950. return mass * Math.pow(this.length,2) / 12;
  6951. };
  6952. Line.prototype.updateBoundingRadius = function(){
  6953. this.boundingRadius = this.length/2;
  6954. };
  6955. var points = [vec2.create(),vec2.create()];
  6956. /**
  6957. * @method computeAABB
  6958. * @param {AABB} out The resulting AABB.
  6959. * @param {Array} position
  6960. * @param {Number} angle
  6961. */
  6962. Line.prototype.computeAABB = function(out, position, angle){
  6963. var l = this.length;
  6964. vec2.set(points[0], -l/2, 0);
  6965. vec2.set(points[1], l/2, 0);
  6966. out.setFromPoints(points,position,angle);
  6967. };
  6968. },{"../math/vec2":30,"./Shape":42}],39:[function(require,module,exports){
  6969. var Shape = require('./Shape')
  6970. , vec2 = require('../math/vec2')
  6971. module.exports = Particle;
  6972. /**
  6973. * Particle shape class.
  6974. * @class Particle
  6975. * @constructor
  6976. * @extends Shape
  6977. */
  6978. function Particle(){
  6979. Shape.call(this,Shape.PARTICLE);
  6980. };
  6981. Particle.prototype = new Shape();
  6982. Particle.prototype.computeMomentOfInertia = function(mass){
  6983. return 0; // Can't rotate a particle
  6984. };
  6985. Particle.prototype.updateBoundingRadius = function(){
  6986. this.boundingRadius = 0;
  6987. };
  6988. /**
  6989. * @method computeAABB
  6990. * @param {AABB} out
  6991. * @param {Array} position
  6992. * @param {Number} angle
  6993. */
  6994. Particle.prototype.computeAABB = function(out, position, angle){
  6995. var l = this.length;
  6996. vec2.copy(out.lowerBound, position);
  6997. vec2.copy(out.upperBound, position);
  6998. };
  6999. },{"../math/vec2":30,"./Shape":42}],40:[function(require,module,exports){
  7000. var Shape = require('./Shape')
  7001. , vec2 = require('../math/vec2')
  7002. , Utils = require('../utils/Utils')
  7003. module.exports = Plane;
  7004. /**
  7005. * Plane shape class. The plane is facing in the Y direction.
  7006. * @class Plane
  7007. * @extends Shape
  7008. * @constructor
  7009. */
  7010. function Plane(){
  7011. Shape.call(this,Shape.PLANE);
  7012. };
  7013. Plane.prototype = new Shape();
  7014. /**
  7015. * Compute moment of inertia
  7016. * @method computeMomentOfInertia
  7017. */
  7018. Plane.prototype.computeMomentOfInertia = function(mass){
  7019. return 0; // Plane is infinite. The inertia should therefore be infinty but by convention we set 0 here
  7020. };
  7021. /**
  7022. * Update the bounding radius
  7023. * @method updateBoundingRadius
  7024. */
  7025. Plane.prototype.updateBoundingRadius = function(){
  7026. this.boundingRadius = Number.MAX_VALUE;
  7027. };
  7028. /**
  7029. * @method computeAABB
  7030. * @param {AABB} out
  7031. * @param {Array} position
  7032. * @param {Number} angle
  7033. */
  7034. Plane.prototype.computeAABB = function(out, position, angle){
  7035. var a = 0,
  7036. set = vec2.set;
  7037. if(typeof(angle) == "number")
  7038. a = angle % (2*Math.PI);
  7039. if(a == 0){
  7040. // y goes from -inf to 0
  7041. set(out.lowerBound, -Number.MAX_VALUE, -Number.MAX_VALUE);
  7042. set(out.upperBound, Number.MAX_VALUE, 0);
  7043. } else if(a == Math.PI / 2){
  7044. // x goes from 0 to inf
  7045. set(out.lowerBound, 0, -Number.MAX_VALUE);
  7046. set(out.upperBound, Number.MAX_VALUE, Number.MAX_VALUE);
  7047. } else if(a == Math.PI){
  7048. // y goes from 0 to inf
  7049. set(out.lowerBound, -Number.MAX_VALUE, 0);
  7050. set(out.upperBound, Number.MAX_VALUE, Number.MAX_VALUE);
  7051. } else if(a == 3*Math.PI/2){
  7052. // x goes from -inf to 0
  7053. set(out.lowerBound, -Number.MAX_VALUE, -Number.MAX_VALUE);
  7054. set(out.upperBound, 0, Number.MAX_VALUE);
  7055. } else {
  7056. // Set max bounds
  7057. set(out.lowerBound, -Number.MAX_VALUE, -Number.MAX_VALUE);
  7058. set(out.upperBound, Number.MAX_VALUE, Number.MAX_VALUE);
  7059. }
  7060. vec2.add(out.lowerBound, out.lowerBound, position);
  7061. vec2.add(out.upperBound, out.upperBound, position);
  7062. };
  7063. Plane.prototype.updateArea = function(){
  7064. this.area = Number.MAX_VALUE;
  7065. };
  7066. },{"../math/vec2":30,"../utils/Utils":45,"./Shape":42}],41:[function(require,module,exports){
  7067. var vec2 = require('../math/vec2')
  7068. , Shape = require('./Shape')
  7069. , Convex = require('./Convex')
  7070. module.exports = Rectangle;
  7071. /**
  7072. * Rectangle shape class.
  7073. * @class Rectangle
  7074. * @constructor
  7075. * @param {Number} w Width
  7076. * @param {Number} h Height
  7077. * @extends Convex
  7078. */
  7079. function Rectangle(w,h){
  7080. var verts = [ vec2.fromValues(-w/2, -h/2),
  7081. vec2.fromValues( w/2, -h/2),
  7082. vec2.fromValues( w/2, h/2),
  7083. vec2.fromValues(-w/2, h/2)];
  7084. /**
  7085. * Total width of the rectangle
  7086. * @property width
  7087. * @type {Number}
  7088. */
  7089. this.width = w;
  7090. /**
  7091. * Total height of the rectangle
  7092. * @property height
  7093. * @type {Number}
  7094. */
  7095. this.height = h;
  7096. Convex.call(this,verts);
  7097. this.type = Shape.RECTANGLE;
  7098. };
  7099. Rectangle.prototype = new Convex([]);
  7100. /**
  7101. * Compute moment of inertia
  7102. * @method computeMomentOfInertia
  7103. * @param {Number} mass
  7104. * @return {Number}
  7105. */
  7106. Rectangle.prototype.computeMomentOfInertia = function(mass){
  7107. var w = this.width,
  7108. h = this.height;
  7109. return mass * (h*h + w*w) / 12;
  7110. };
  7111. /**
  7112. * Update the bounding radius
  7113. * @method updateBoundingRadius
  7114. */
  7115. Rectangle.prototype.updateBoundingRadius = function(){
  7116. var w = this.width,
  7117. h = this.height;
  7118. this.boundingRadius = Math.sqrt(w*w + h*h) / 2;
  7119. };
  7120. var corner1 = vec2.create(),
  7121. corner2 = vec2.create(),
  7122. corner3 = vec2.create(),
  7123. corner4 = vec2.create();
  7124. /**
  7125. * @method computeAABB
  7126. * @param {AABB} out The resulting AABB.
  7127. * @param {Array} position
  7128. * @param {Number} angle
  7129. */
  7130. Rectangle.prototype.computeAABB = function(out, position, angle){
  7131. out.setFromPoints(this.vertices,position,angle);
  7132. };
  7133. Rectangle.prototype.updateArea = function(){
  7134. this.area = this.width * this.height;
  7135. };
  7136. },{"../math/vec2":30,"./Convex":36,"./Shape":42}],42:[function(require,module,exports){
  7137. module.exports = Shape;
  7138. /**
  7139. * Base class for shapes.
  7140. * @class Shape
  7141. * @constructor
  7142. * @param {Number} type
  7143. */
  7144. function Shape(type){
  7145. /**
  7146. * The type of the shape. One of:
  7147. *
  7148. * * {{#crossLink "Shape/CIRCLE:property"}}Shape.CIRCLE{{/crossLink}}
  7149. * * {{#crossLink "Shape/PARTICLE:property"}}Shape.PARTICLE{{/crossLink}}
  7150. * * {{#crossLink "Shape/PLANE:property"}}Shape.PLANE{{/crossLink}}
  7151. * * {{#crossLink "Shape/CONVEX:property"}}Shape.CONVEX{{/crossLink}}
  7152. * * {{#crossLink "Shape/LINE:property"}}Shape.LINE{{/crossLink}}
  7153. * * {{#crossLink "Shape/RECTANGLE:property"}}Shape.RECTANGLE{{/crossLink}}
  7154. * * {{#crossLink "Shape/CAPSULE:property"}}Shape.CAPSULE{{/crossLink}}
  7155. * * {{#crossLink "Shape/HEIGHTFIELD:property"}}Shape.HEIGHTFIELD{{/crossLink}}
  7156. *
  7157. * @property {number} type
  7158. */
  7159. this.type = type;
  7160. /**
  7161. * Shape object identifier.
  7162. * @type {Number}
  7163. * @property id
  7164. */
  7165. this.id = Shape.idCounter++;
  7166. /**
  7167. * Bounding circle radius of this shape
  7168. * @property boundingRadius
  7169. * @type {Number}
  7170. */
  7171. this.boundingRadius = 0;
  7172. /**
  7173. * Collision group that this shape belongs to (bit mask). See <a href="http://www.aurelienribon.com/blog/2011/07/box2d-tutorial-collision-filtering/">this tutorial</a>.
  7174. * @property collisionGroup
  7175. * @type {Number}
  7176. * @example
  7177. * // Setup bits for each available group
  7178. * var PLAYER = Math.pow(2,0),
  7179. * ENEMY = Math.pow(2,1),
  7180. * GROUND = Math.pow(2,2)
  7181. *
  7182. * // Put shapes into their groups
  7183. * player1Shape.collisionGroup = PLAYER;
  7184. * player2Shape.collisionGroup = PLAYER;
  7185. * enemyShape .collisionGroup = ENEMY;
  7186. * groundShape .collisionGroup = GROUND;
  7187. *
  7188. * // Assign groups that each shape collide with.
  7189. * // Note that the players can collide with ground and enemies, but not with other players.
  7190. * player1Shape.collisionMask = ENEMY | GROUND;
  7191. * player2Shape.collisionMask = ENEMY | GROUND;
  7192. * enemyShape .collisionMask = PLAYER | GROUND;
  7193. * groundShape .collisionMask = PLAYER | ENEMY;
  7194. *
  7195. * @example
  7196. * // How collision check is done
  7197. * if(shapeA.collisionGroup & shapeB.collisionMask)!=0 && (shapeB.collisionGroup & shapeA.collisionMask)!=0){
  7198. * // The shapes will collide
  7199. * }
  7200. */
  7201. this.collisionGroup = 1;
  7202. /**
  7203. * Collision mask of this shape. See .collisionGroup.
  7204. * @property collisionMask
  7205. * @type {Number}
  7206. */
  7207. this.collisionMask = 1;
  7208. if(type) this.updateBoundingRadius();
  7209. /**
  7210. * Material to use in collisions for this Shape. If this is set to null, the world will use default material properties instead.
  7211. * @property material
  7212. * @type {Material}
  7213. */
  7214. this.material = null;
  7215. /**
  7216. * Area of this shape.
  7217. * @property area
  7218. * @type {Number}
  7219. */
  7220. this.area = 0;
  7221. /**
  7222. * Set to true if you want this shape to be a sensor. A sensor does not generate contacts, but it still reports contact events. This is good if you want to know if a shape is overlapping another shape, without them generating contacts.
  7223. * @property {Boolean} sensor
  7224. */
  7225. this.sensor = false;
  7226. this.updateArea();
  7227. };
  7228. Shape.idCounter = 0;
  7229. /**
  7230. * @static
  7231. * @property {Number} CIRCLE
  7232. */
  7233. Shape.CIRCLE = 1;
  7234. /**
  7235. * @static
  7236. * @property {Number} PARTICLE
  7237. */
  7238. Shape.PARTICLE = 2;
  7239. /**
  7240. * @static
  7241. * @property {Number} PLANE
  7242. */
  7243. Shape.PLANE = 4;
  7244. /**
  7245. * @static
  7246. * @property {Number} CONVEX
  7247. */
  7248. Shape.CONVEX = 8;
  7249. /**
  7250. * @static
  7251. * @property {Number} LINE
  7252. */
  7253. Shape.LINE = 16;
  7254. /**
  7255. * @static
  7256. * @property {Number} RECTANGLE
  7257. */
  7258. Shape.RECTANGLE = 32;
  7259. /**
  7260. * @static
  7261. * @property {Number} CAPSULE
  7262. */
  7263. Shape.CAPSULE = 64;
  7264. /**
  7265. * @static
  7266. * @property {Number} HEIGHTFIELD
  7267. */
  7268. Shape.HEIGHTFIELD = 128;
  7269. /**
  7270. * Should return the moment of inertia around the Z axis of the body given the total mass. See <a href="http://en.wikipedia.org/wiki/List_of_moments_of_inertia">Wikipedia's list of moments of inertia</a>.
  7271. * @method computeMomentOfInertia
  7272. * @param {Number} mass
  7273. * @return {Number} If the inertia is infinity or if the object simply isn't possible to rotate, return 0.
  7274. */
  7275. Shape.prototype.computeMomentOfInertia = function(mass){
  7276. throw new Error("Shape.computeMomentOfInertia is not implemented in this Shape...");
  7277. };
  7278. /**
  7279. * Returns the bounding circle radius of this shape.
  7280. * @method updateBoundingRadius
  7281. * @return {Number}
  7282. */
  7283. Shape.prototype.updateBoundingRadius = function(){
  7284. throw new Error("Shape.updateBoundingRadius is not implemented in this Shape...");
  7285. };
  7286. /**
  7287. * Update the .area property of the shape.
  7288. * @method updateArea
  7289. */
  7290. Shape.prototype.updateArea = function(){
  7291. // To be implemented in all subclasses
  7292. };
  7293. /**
  7294. * Compute the world axis-aligned bounding box (AABB) of this shape.
  7295. * @method computeAABB
  7296. * @param {AABB} out The resulting AABB.
  7297. * @param {Array} position
  7298. * @param {Number} angle
  7299. */
  7300. Shape.prototype.computeAABB = function(out, position, angle){
  7301. // To be implemented in each subclass
  7302. };
  7303. },{}],43:[function(require,module,exports){
  7304. var vec2 = require('../math/vec2')
  7305. , Solver = require('./Solver')
  7306. , Utils = require('../utils/Utils')
  7307. , FrictionEquation = require('../equations/FrictionEquation');
  7308. module.exports = GSSolver;
  7309. /**
  7310. * Iterative Gauss-Seidel constraint equation solver.
  7311. *
  7312. * @class GSSolver
  7313. * @constructor
  7314. * @extends Solver
  7315. * @param {Object} [options]
  7316. * @param {Number} [options.iterations=10]
  7317. * @param {Number} [options.tolerance=0]
  7318. */
  7319. function GSSolver(options){
  7320. Solver.call(this,options,Solver.GS);
  7321. options = options || {};
  7322. /**
  7323. * The number of iterations to do when solving. More gives better results, but is more expensive.
  7324. * @property iterations
  7325. * @type {Number}
  7326. */
  7327. this.iterations = options.iterations || 10;
  7328. /**
  7329. * The error tolerance, per constraint. If the total error is below this limit, the solver will stop iterating. Set to zero for as good solution as possible, but to something larger than zero to make computations faster.
  7330. * @property tolerance
  7331. * @type {Number}
  7332. */
  7333. this.tolerance = options.tolerance || 1e-10;
  7334. this.arrayStep = 30;
  7335. this.lambda = new Utils.ARRAY_TYPE(this.arrayStep);
  7336. this.Bs = new Utils.ARRAY_TYPE(this.arrayStep);
  7337. this.invCs = new Utils.ARRAY_TYPE(this.arrayStep);
  7338. /**
  7339. * Set to true to set all right hand side terms to zero when solving. Can be handy for a few applications.
  7340. * @property useZeroRHS
  7341. * @type {Boolean}
  7342. */
  7343. this.useZeroRHS = false;
  7344. /**
  7345. * Number of solver iterations that are done to approximate normal forces. When these iterations are done, friction force will be computed from the contact normal forces. These friction forces will override any other friction forces set from the World for example.
  7346. * The solver will use less iterations if the solution is below the .tolerance.
  7347. * @property frictionIterations
  7348. * @type {Number}
  7349. */
  7350. this.frictionIterations = 0;
  7351. /**
  7352. * The number of iterations that were made during the last solve. If .tolerance is zero, this value will always be equal to .iterations, but if .tolerance is larger than zero, and the solver can quit early, then this number will be somewhere between 1 and .iterations.
  7353. * @property {Number} usedIterations
  7354. */
  7355. this.usedIterations = 0;
  7356. }
  7357. GSSolver.prototype = new Solver();
  7358. function setArrayZero(array){
  7359. for(var i=0; i!==array.length; i++){
  7360. array[i] = 0.0;
  7361. }
  7362. }
  7363. /**
  7364. * Solve the system of equations
  7365. * @method solve
  7366. * @param {Number} h Time step
  7367. * @param {World} world World to solve
  7368. */
  7369. GSSolver.prototype.solve = function(h, world){
  7370. this.sortEquations();
  7371. var iter = 0,
  7372. maxIter = this.iterations,
  7373. maxFrictionIter = this.frictionIterations,
  7374. equations = this.equations,
  7375. Neq = equations.length,
  7376. tolSquared = Math.pow(this.tolerance*Neq, 2),
  7377. bodies = world.bodies,
  7378. Nbodies = world.bodies.length,
  7379. add = vec2.add,
  7380. set = vec2.set,
  7381. useZeroRHS = this.useZeroRHS,
  7382. lambda = this.lambda;
  7383. this.usedIterations = 0;
  7384. // Things that does not change during iteration can be computed once
  7385. if(lambda.length < Neq){
  7386. lambda = this.lambda = new Utils.ARRAY_TYPE(Neq + this.arrayStep);
  7387. this.Bs = new Utils.ARRAY_TYPE(Neq + this.arrayStep);
  7388. this.invCs = new Utils.ARRAY_TYPE(Neq + this.arrayStep);
  7389. }
  7390. setArrayZero(lambda);
  7391. var invCs = this.invCs,
  7392. Bs = this.Bs,
  7393. lambda = this.lambda;
  7394. for(var i=0; i!==equations.length; i++){
  7395. var c = equations[i];
  7396. if(c.timeStep !== h || c.needsUpdate){
  7397. c.timeStep = h;
  7398. c.update();
  7399. }
  7400. Bs[i] = c.computeB(c.a,c.b,h);
  7401. invCs[i] = c.computeInvC(c.epsilon);
  7402. }
  7403. var q, B, c, deltalambdaTot,i,j;
  7404. if(Neq !== 0){
  7405. // Reset vlambda
  7406. for(i=0; i!==Nbodies; i++){
  7407. bodies[i].resetConstraintVelocity();
  7408. }
  7409. if(maxFrictionIter){
  7410. // Iterate over contact equations to get normal forces
  7411. for(iter=0; iter!==maxFrictionIter; iter++){
  7412. // Accumulate the total error for each iteration.
  7413. deltalambdaTot = 0.0;
  7414. for(j=0; j!==Neq; j++){
  7415. c = equations[j];
  7416. if(c instanceof FrictionEquation){
  7417. //continue;
  7418. }
  7419. var deltalambda = GSSolver.iterateEquation(j,c,c.epsilon,Bs,invCs,lambda,useZeroRHS,h,iter);
  7420. deltalambdaTot += Math.abs(deltalambda);
  7421. }
  7422. this.usedIterations++;
  7423. // If the total error is small enough - stop iterate
  7424. if(deltalambdaTot*deltalambdaTot <= tolSquared){
  7425. break;
  7426. }
  7427. }
  7428. // Set computed friction force
  7429. for(j=0; j!==Neq; j++){
  7430. var eq = equations[j];
  7431. if(eq instanceof FrictionEquation){
  7432. var f = eq.contactEquation.multiplier * eq.frictionCoefficient;
  7433. eq.maxForce = f;
  7434. eq.minForce = -f;
  7435. }
  7436. }
  7437. }
  7438. // Iterate over all equations
  7439. for(iter=0; iter!==maxIter; iter++){
  7440. // Accumulate the total error for each iteration.
  7441. deltalambdaTot = 0.0;
  7442. for(j=0; j!==Neq; j++){
  7443. c = equations[j];
  7444. var deltalambda = GSSolver.iterateEquation(j,c,c.epsilon,Bs,invCs,lambda,useZeroRHS,h,iter);
  7445. deltalambdaTot += Math.abs(deltalambda);
  7446. }
  7447. this.usedIterations++;
  7448. // If the total error is small enough - stop iterate
  7449. if(deltalambdaTot*deltalambdaTot <= tolSquared){
  7450. break;
  7451. }
  7452. }
  7453. // Add result to velocity
  7454. for(i=0; i!==Nbodies; i++){
  7455. bodies[i].addConstraintVelocity();
  7456. }
  7457. }
  7458. };
  7459. GSSolver.iterateEquation = function(j,eq,eps,Bs,invCs,lambda,useZeroRHS,dt,iter){
  7460. // Compute iteration
  7461. var B = Bs[j],
  7462. invC = invCs[j],
  7463. lambdaj = lambda[j],
  7464. GWlambda = eq.computeGWlambda();
  7465. var maxForce = eq.maxForce,
  7466. minForce = eq.minForce;
  7467. if(useZeroRHS){
  7468. B = 0;
  7469. }
  7470. var deltalambda = invC * ( B - GWlambda - eps * lambdaj );
  7471. // Clamp if we are not within the min/max interval
  7472. var lambdaj_plus_deltalambda = lambdaj + deltalambda;
  7473. if(lambdaj_plus_deltalambda < minForce*dt){
  7474. deltalambda = minForce*dt - lambdaj;
  7475. } else if(lambdaj_plus_deltalambda > maxForce*dt){
  7476. deltalambda = maxForce*dt - lambdaj;
  7477. }
  7478. lambda[j] += deltalambda;
  7479. eq.multiplier = lambda[j] / dt;
  7480. eq.addToWlambda(deltalambda);
  7481. return deltalambda;
  7482. };
  7483. },{"../equations/FrictionEquation":23,"../math/vec2":30,"../utils/Utils":45,"./Solver":44}],44:[function(require,module,exports){
  7484. var Utils = require('../utils/Utils')
  7485. , EventEmitter = require('../events/EventEmitter')
  7486. module.exports = Solver;
  7487. /**
  7488. * Base class for constraint solvers.
  7489. * @class Solver
  7490. * @constructor
  7491. * @extends EventEmitter
  7492. */
  7493. function Solver(options,type){
  7494. options = options || {};
  7495. EventEmitter.call(this);
  7496. this.type = type;
  7497. /**
  7498. * Current equations in the solver.
  7499. *
  7500. * @property equations
  7501. * @type {Array}
  7502. */
  7503. this.equations = [];
  7504. /**
  7505. * Function that is used to sort all equations before each solve.
  7506. * @property equationSortFunction
  7507. * @type {function|boolean}
  7508. */
  7509. this.equationSortFunction = options.equationSortFunction || false;
  7510. }
  7511. Solver.prototype = new EventEmitter();
  7512. /**
  7513. * Method to be implemented in each subclass
  7514. * @method solve
  7515. * @param {Number} dt
  7516. * @param {World} world
  7517. */
  7518. Solver.prototype.solve = function(dt,world){
  7519. throw new Error("Solver.solve should be implemented by subclasses!");
  7520. };
  7521. var mockWorld = {bodies:[]};
  7522. /**
  7523. * Solves all constraints in an island.
  7524. * @method solveIsland
  7525. * @param {Number} dt
  7526. * @param {Island} island
  7527. */
  7528. Solver.prototype.solveIsland = function(dt,island){
  7529. this.removeAllEquations();
  7530. if(island.equations.length){
  7531. // Add equations to solver
  7532. this.addEquations(island.equations);
  7533. mockWorld.bodies.length = 0;
  7534. island.getBodies(mockWorld.bodies);
  7535. // Solve
  7536. if(mockWorld.bodies.length){
  7537. this.solve(dt,mockWorld);
  7538. }
  7539. }
  7540. };
  7541. /**
  7542. * Sort all equations using the .equationSortFunction. Should be called by subclasses before solving.
  7543. * @method sortEquations
  7544. */
  7545. Solver.prototype.sortEquations = function(){
  7546. if(this.equationSortFunction){
  7547. this.equations.sort(this.equationSortFunction);
  7548. }
  7549. };
  7550. /**
  7551. * Add an equation to be solved.
  7552. *
  7553. * @method addEquation
  7554. * @param {Equation} eq
  7555. */
  7556. Solver.prototype.addEquation = function(eq){
  7557. if(eq.enabled){
  7558. this.equations.push(eq);
  7559. }
  7560. };
  7561. /**
  7562. * Add equations. Same as .addEquation, but this time the argument is an array of Equations
  7563. *
  7564. * @method addEquations
  7565. * @param {Array} eqs
  7566. */
  7567. Solver.prototype.addEquations = function(eqs){
  7568. //Utils.appendArray(this.equations,eqs);
  7569. for(var i=0, N=eqs.length; i!==N; i++){
  7570. var eq = eqs[i];
  7571. if(eq.enabled){
  7572. this.equations.push(eq);
  7573. }
  7574. }
  7575. };
  7576. /**
  7577. * Remove an equation.
  7578. *
  7579. * @method removeEquation
  7580. * @param {Equation} eq
  7581. */
  7582. Solver.prototype.removeEquation = function(eq){
  7583. var i = this.equations.indexOf(eq);
  7584. if(i !== -1){
  7585. this.equations.splice(i,1);
  7586. }
  7587. };
  7588. /**
  7589. * Remove all currently added equations.
  7590. *
  7591. * @method removeAllEquations
  7592. */
  7593. Solver.prototype.removeAllEquations = function(){
  7594. this.equations.length=0;
  7595. };
  7596. Solver.GS = 1;
  7597. Solver.ISLAND = 2;
  7598. },{"../events/EventEmitter":26,"../utils/Utils":45}],45:[function(require,module,exports){
  7599. module.exports = Utils;
  7600. /**
  7601. * Misc utility functions
  7602. * @class Utils
  7603. * @constructor
  7604. */
  7605. function Utils(){};
  7606. /**
  7607. * Append the values in array b to the array a. See <a href="http://stackoverflow.com/questions/1374126/how-to-append-an-array-to-an-existing-javascript-array/1374131#1374131">this</a> for an explanation.
  7608. * @method appendArray
  7609. * @static
  7610. * @param {Array} a
  7611. * @param {Array} b
  7612. */
  7613. Utils.appendArray = function(a,b){
  7614. if (b.length < 150000) {
  7615. a.push.apply(a, b);
  7616. } else {
  7617. for (var i = 0, len = b.length; i !== len; ++i) {
  7618. a.push(b[i]);
  7619. }
  7620. }
  7621. };
  7622. /**
  7623. * Garbage free Array.splice(). Does not allocate a new array.
  7624. * @method splice
  7625. * @static
  7626. * @param {Array} array
  7627. * @param {Number} index
  7628. * @param {Number} howmany
  7629. */
  7630. Utils.splice = function(array,index,howmany){
  7631. howmany = howmany || 1;
  7632. for (var i=index, len=array.length-howmany; i < len; i++){
  7633. array[i] = array[i + howmany];
  7634. }
  7635. array.length = len;
  7636. };
  7637. /**
  7638. * The array type to use for internal numeric computations.
  7639. * @type {Array}
  7640. * @static
  7641. * @property ARRAY_TYPE
  7642. */
  7643. Utils.ARRAY_TYPE = Float32Array || Array;
  7644. /**
  7645. * Extend an object with the properties of another
  7646. * @static
  7647. * @method extend
  7648. * @param {object} a
  7649. * @param {object} b
  7650. */
  7651. Utils.extend = function(a,b){
  7652. for(var key in b){
  7653. a[key] = b[key];
  7654. }
  7655. };
  7656. },{}],46:[function(require,module,exports){
  7657. var Body = require('../objects/Body');
  7658. module.exports = Island;
  7659. /**
  7660. * An island of bodies connected with equations.
  7661. * @class Island
  7662. * @constructor
  7663. */
  7664. function Island(){
  7665. /**
  7666. * Current equations in this island.
  7667. * @property equations
  7668. * @type {Array}
  7669. */
  7670. this.equations = [];
  7671. /**
  7672. * Current bodies in this island.
  7673. * @property bodies
  7674. * @type {Array}
  7675. */
  7676. this.bodies = [];
  7677. }
  7678. /**
  7679. * Clean this island from bodies and equations.
  7680. * @method reset
  7681. */
  7682. Island.prototype.reset = function(){
  7683. this.equations.length = this.bodies.length = 0;
  7684. };
  7685. var bodyIds = [];
  7686. /**
  7687. * Get all unique bodies in this island.
  7688. * @method getBodies
  7689. * @return {Array} An array of Body
  7690. */
  7691. Island.prototype.getBodies = function(result){
  7692. var bodies = result || [],
  7693. eqs = this.equations;
  7694. bodyIds.length = 0;
  7695. for(var i=0; i!==eqs.length; i++){
  7696. var eq = eqs[i];
  7697. if(bodyIds.indexOf(eq.bodyA.id)===-1){
  7698. bodies.push(eq.bodyA);
  7699. bodyIds.push(eq.bodyA.id);
  7700. }
  7701. if(bodyIds.indexOf(eq.bodyB.id)===-1){
  7702. bodies.push(eq.bodyB);
  7703. bodyIds.push(eq.bodyB.id);
  7704. }
  7705. }
  7706. return bodies;
  7707. };
  7708. /**
  7709. * Check if the entire island wants to sleep.
  7710. * @method wantsToSleep
  7711. * @return {Boolean}
  7712. */
  7713. Island.prototype.wantsToSleep = function(){
  7714. for(var i=0; i<this.bodies.length; i++){
  7715. var b = this.bodies[i];
  7716. if(b.motionState === Body.DYNAMIC && !b.wantsToSleep){
  7717. return false;
  7718. }
  7719. }
  7720. return true;
  7721. };
  7722. /**
  7723. * Make all bodies in the island sleep.
  7724. * @method sleep
  7725. */
  7726. Island.prototype.sleep = function(){
  7727. for(var i=0; i<this.bodies.length; i++){
  7728. var b = this.bodies[i];
  7729. b.sleep();
  7730. }
  7731. return true;
  7732. };
  7733. },{"../objects/Body":31}],47:[function(require,module,exports){
  7734. var vec2 = require('../math/vec2')
  7735. , Island = require('./Island')
  7736. , IslandNode = require('./IslandNode')
  7737. , Body = require('../objects/Body')
  7738. module.exports = IslandManager;
  7739. /**
  7740. * Splits the system of bodies and equations into independent islands
  7741. *
  7742. * @class IslandManager
  7743. * @constructor
  7744. * @param {Object} [options]
  7745. * @extends Solver
  7746. */
  7747. function IslandManager(options){
  7748. // Pooling of node objects saves some GC load
  7749. this._nodePool = [];
  7750. this._islandPool = [];
  7751. /**
  7752. * The equations to split. Manually fill this array before running .split().
  7753. * @property {Array} equations
  7754. */
  7755. this.equations = [];
  7756. /**
  7757. * The resulting {{#crossLink "Island"}}{{/crossLink}}s.
  7758. * @property {Array} islands
  7759. */
  7760. this.islands = [];
  7761. /**
  7762. * The resulting graph nodes.
  7763. * @property {Array} nodes
  7764. */
  7765. this.nodes = [];
  7766. /**
  7767. * The node queue, used when traversing the graph of nodes.
  7768. * @private
  7769. * @property {Array} queue
  7770. */
  7771. this.queue = [];
  7772. }
  7773. /**
  7774. * Get an unvisited node from a list of nodes.
  7775. * @static
  7776. * @method getUnvisitedNode
  7777. * @param {Array} nodes
  7778. * @return {IslandNode|boolean} The node if found, else false.
  7779. */
  7780. IslandManager.getUnvisitedNode = function(nodes){
  7781. var Nnodes = nodes.length;
  7782. for(var i=0; i!==Nnodes; i++){
  7783. var node = nodes[i];
  7784. if(!node.visited && node.body.motionState === Body.DYNAMIC){
  7785. return node;
  7786. }
  7787. }
  7788. return false;
  7789. };
  7790. /**
  7791. * Visit a node.
  7792. * @method visit
  7793. * @param {IslandNode} node
  7794. * @param {Array} bds
  7795. * @param {Array} eqs
  7796. */
  7797. IslandManager.prototype.visit = function (node,bds,eqs){
  7798. bds.push(node.body);
  7799. var Neqs = node.equations.length;
  7800. for(var i=0; i!==Neqs; i++){
  7801. var eq = node.equations[i];
  7802. if(eqs.indexOf(eq) === -1){ // Already added?
  7803. eqs.push(eq);
  7804. }
  7805. }
  7806. };
  7807. /**
  7808. * Runs the search algorithm, starting at a root node. The resulting bodies and equations will be stored in the provided arrays.
  7809. * @method bfs
  7810. * @param {IslandNode} root The node to start from
  7811. * @param {Array} bds An array to append resulting Bodies to.
  7812. * @param {Array} eqs An array to append resulting Equations to.
  7813. */
  7814. IslandManager.prototype.bfs = function(root,bds,eqs){
  7815. // Reset the visit queue
  7816. var queue = this.queue;
  7817. queue.length = 0;
  7818. // Add root node to queue
  7819. queue.push(root);
  7820. root.visited = true;
  7821. this.visit(root,bds,eqs);
  7822. // Process all queued nodes
  7823. while(queue.length) {
  7824. // Get next node in the queue
  7825. var node = queue.pop();
  7826. // Visit unvisited neighboring nodes
  7827. var child;
  7828. while((child = IslandManager.getUnvisitedNode(node.neighbors))) {
  7829. child.visited = true;
  7830. this.visit(child,bds,eqs);
  7831. // Only visit the children of this node if it's dynamic
  7832. if(child.body.motionState === Body.DYNAMIC){
  7833. queue.push(child);
  7834. }
  7835. }
  7836. }
  7837. };
  7838. /**
  7839. * Split the world into independent islands. The result is stored in .islands.
  7840. * @method split
  7841. * @param {World} world
  7842. * @return {Array} The generated islands
  7843. */
  7844. IslandManager.prototype.split = function(world){
  7845. var bodies = world.bodies,
  7846. nodes = this.nodes,
  7847. equations = this.equations;
  7848. // Move old nodes to the node pool
  7849. while(nodes.length){
  7850. this._nodePool.push(nodes.pop());
  7851. }
  7852. // Create needed nodes, reuse if possible
  7853. for(var i=0; i!==bodies.length; i++){
  7854. if(this._nodePool.length){
  7855. var node = this._nodePool.pop();
  7856. node.reset();
  7857. node.body = bodies[i];
  7858. nodes.push(node);
  7859. } else {
  7860. nodes.push(new IslandNode(bodies[i]));
  7861. }
  7862. }
  7863. // Add connectivity data. Each equation connects 2 bodies.
  7864. for(var k=0; k!==equations.length; k++){
  7865. var eq=equations[k],
  7866. i=bodies.indexOf(eq.bodyA),
  7867. j=bodies.indexOf(eq.bodyB),
  7868. ni=nodes[i],
  7869. nj=nodes[j];
  7870. ni.neighbors.push(nj);
  7871. nj.neighbors.push(ni);
  7872. ni.equations.push(eq);
  7873. nj.equations.push(eq);
  7874. }
  7875. // Move old islands to the island pool
  7876. var islands = this.islands;
  7877. while(islands.length){
  7878. var island = islands.pop();
  7879. island.reset();
  7880. this._islandPool.push(island);
  7881. }
  7882. // Get islands
  7883. var child;
  7884. while((child = IslandManager.getUnvisitedNode(nodes))){
  7885. // Create new island
  7886. var island = this._islandPool.length ? this._islandPool.pop() : new Island();
  7887. // Get all equations and bodies in this island
  7888. this.bfs(child, island.bodies, island.equations);
  7889. islands.push(island);
  7890. }
  7891. return islands;
  7892. };
  7893. },{"../math/vec2":30,"../objects/Body":31,"./Island":46,"./IslandNode":48}],48:[function(require,module,exports){
  7894. module.exports = IslandNode;
  7895. /**
  7896. * Holds a body and keeps track of some additional properties needed for graph traversal.
  7897. * @class IslandNode
  7898. * @constructor
  7899. * @param {Body} body
  7900. */
  7901. function IslandNode(body){
  7902. /**
  7903. * The body that is contained in this node.
  7904. * @property {Body}
  7905. */
  7906. this.body = body;
  7907. /**
  7908. * Neighboring IslandNodes
  7909. * @property {Array} neighbors
  7910. */
  7911. this.neighbors = [];
  7912. /**
  7913. * Equations connected to this node.
  7914. * @property {Array} equations
  7915. */
  7916. this.equations = [];
  7917. /**
  7918. * If this node was visiting during the graph traversal.
  7919. * @property visited
  7920. * @type {Boolean}
  7921. */
  7922. this.visited = false;
  7923. }
  7924. /**
  7925. * Clean this node from bodies and equations.
  7926. * @method reset
  7927. */
  7928. IslandNode.prototype.reset = function(){
  7929. this.equations.length = 0;
  7930. this.neighbors.length = 0;
  7931. this.visited = false;
  7932. this.body = null;
  7933. };
  7934. },{}],49:[function(require,module,exports){
  7935. var GSSolver = require('../solver/GSSolver')
  7936. , Solver = require('../solver/Solver')
  7937. , NaiveBroadphase = require('../collision/NaiveBroadphase')
  7938. , vec2 = require('../math/vec2')
  7939. , Circle = require('../shapes/Circle')
  7940. , Rectangle = require('../shapes/Rectangle')
  7941. , Convex = require('../shapes/Convex')
  7942. , Line = require('../shapes/Line')
  7943. , Plane = require('../shapes/Plane')
  7944. , Capsule = require('../shapes/Capsule')
  7945. , Particle = require('../shapes/Particle')
  7946. , EventEmitter = require('../events/EventEmitter')
  7947. , Body = require('../objects/Body')
  7948. , Shape = require('../shapes/Shape')
  7949. , Spring = require('../objects/Spring')
  7950. , Material = require('../material/Material')
  7951. , ContactMaterial = require('../material/ContactMaterial')
  7952. , DistanceConstraint = require('../constraints/DistanceConstraint')
  7953. , Constraint = require('../constraints/Constraint')
  7954. , LockConstraint = require('../constraints/LockConstraint')
  7955. , RevoluteConstraint = require('../constraints/RevoluteConstraint')
  7956. , PrismaticConstraint = require('../constraints/PrismaticConstraint')
  7957. , GearConstraint = require('../constraints/GearConstraint')
  7958. , pkg = require('../../package.json')
  7959. , Broadphase = require('../collision/Broadphase')
  7960. , SAPBroadphase = require('../collision/SAPBroadphase')
  7961. , Narrowphase = require('../collision/Narrowphase')
  7962. , Utils = require('../utils/Utils')
  7963. , IslandManager = require('./IslandManager')
  7964. module.exports = World;
  7965. if(typeof performance === 'undefined'){
  7966. performance = {};
  7967. }
  7968. if(!performance.now){
  7969. var nowOffset = Date.now();
  7970. if (performance.timing && performance.timing.navigationStart){
  7971. nowOffset = performance.timing.navigationStart;
  7972. }
  7973. performance.now = function(){
  7974. return Date.now() - nowOffset;
  7975. };
  7976. }
  7977. /**
  7978. * The dynamics world, where all bodies and constraints lives.
  7979. *
  7980. * @class World
  7981. * @constructor
  7982. * @param {Object} [options]
  7983. * @param {Solver} options.solver Defaults to GSSolver.
  7984. * @param {Array} options.gravity Defaults to [0,-9.78]
  7985. * @param {Broadphase} options.broadphase Defaults to NaiveBroadphase
  7986. * @param {Boolean} options.islandSplit
  7987. * @param {Boolean} options.doProfiling
  7988. * @extends EventEmitter
  7989. */
  7990. function World(options){
  7991. EventEmitter.apply(this);
  7992. options = options || {};
  7993. /**
  7994. * All springs in the world. To add a spring to the world, use {{#crossLink "World/addSpring:method"}}{{/crossLink}}.
  7995. *
  7996. * @property springs
  7997. * @type {Array}
  7998. */
  7999. this.springs = [];
  8000. /**
  8001. * All bodies in the world. To add a body to the world, use {{#crossLink "World/addBody:method"}}{{/crossLink}}.
  8002. * @property {Array} bodies
  8003. */
  8004. this.bodies = [];
  8005. /**
  8006. * Disabled body collision pairs. See {{#crossLink "World/disableBodyCollision:method"}}.
  8007. * @private
  8008. * @property {Array} disabledBodyCollisionPairs
  8009. */
  8010. this.disabledBodyCollisionPairs = [];
  8011. /**
  8012. * The solver used to satisfy constraints and contacts. Default is {{#crossLink "GSSolver"}}{{/crossLink}}.
  8013. * @property {Solver} solver
  8014. */
  8015. this.solver = options.solver || new GSSolver();
  8016. /**
  8017. * The narrowphase to use to generate contacts.
  8018. *
  8019. * @property narrowphase
  8020. * @type {Narrowphase}
  8021. */
  8022. this.narrowphase = new Narrowphase(this);
  8023. /**
  8024. * The island manager of this world.
  8025. * @property {IslandManager} islandManager
  8026. */
  8027. this.islandManager = new IslandManager();
  8028. /**
  8029. * Gravity in the world. This is applied on all bodies in the beginning of each step().
  8030. *
  8031. * @property gravity
  8032. * @type {Array}
  8033. */
  8034. this.gravity = options.gravity || vec2.fromValues(0, -9.78);
  8035. /**
  8036. * Gravity to use when approximating the friction max force (mu*mass*gravity).
  8037. * @property {Number} frictionGravity
  8038. */
  8039. this.frictionGravity = vec2.length(this.gravity) || 10;
  8040. /**
  8041. * Set to true if you want .frictionGravity to be automatically set to the length of .gravity.
  8042. * @property {Boolean} useWorldGravityAsFrictionGravity
  8043. */
  8044. this.useWorldGravityAsFrictionGravity = true;
  8045. /**
  8046. * If the length of .gravity is zero, and .useWorldGravityAsFrictionGravity=true, then switch to using .frictionGravity for friction instead. This fallback is useful for gravityless games.
  8047. * @property {Boolean} useFrictionGravityOnZeroGravity
  8048. */
  8049. this.useFrictionGravityOnZeroGravity = true;
  8050. /**
  8051. * Whether to do timing measurements during the step() or not.
  8052. *
  8053. * @property doPofiling
  8054. * @type {Boolean}
  8055. */
  8056. this.doProfiling = options.doProfiling || false;
  8057. /**
  8058. * How many millisecconds the last step() took. This is updated each step if .doProfiling is set to true.
  8059. *
  8060. * @property lastStepTime
  8061. * @type {Number}
  8062. */
  8063. this.lastStepTime = 0.0;
  8064. /**
  8065. * The broadphase algorithm to use.
  8066. *
  8067. * @property broadphase
  8068. * @type {Broadphase}
  8069. */
  8070. this.broadphase = options.broadphase || new NaiveBroadphase();
  8071. this.broadphase.setWorld(this);
  8072. /**
  8073. * User-added constraints.
  8074. *
  8075. * @property constraints
  8076. * @type {Array}
  8077. */
  8078. this.constraints = [];
  8079. /**
  8080. * Dummy default material in the world, used in .defaultContactMaterial
  8081. * @property {Material} defaultMaterial
  8082. */
  8083. this.defaultMaterial = new Material();
  8084. /**
  8085. * The default contact material to use, if no contact material was set for the colliding materials.
  8086. * @property {ContactMaterial} defaultContactMaterial
  8087. */
  8088. this.defaultContactMaterial = new ContactMaterial(this.defaultMaterial,this.defaultMaterial);
  8089. /**
  8090. * For keeping track of what time step size we used last step
  8091. * @property lastTimeStep
  8092. * @type {Number}
  8093. */
  8094. this.lastTimeStep = 1/60;
  8095. /**
  8096. * Enable to automatically apply spring forces each step.
  8097. * @property applySpringForces
  8098. * @type {Boolean}
  8099. */
  8100. this.applySpringForces = true;
  8101. /**
  8102. * Enable to automatically apply body damping each step.
  8103. * @property applyDamping
  8104. * @type {Boolean}
  8105. */
  8106. this.applyDamping = true;
  8107. /**
  8108. * Enable to automatically apply gravity each step.
  8109. * @property applyGravity
  8110. * @type {Boolean}
  8111. */
  8112. this.applyGravity = true;
  8113. /**
  8114. * Enable/disable constraint solving in each step.
  8115. * @property solveConstraints
  8116. * @type {Boolean}
  8117. */
  8118. this.solveConstraints = true;
  8119. /**
  8120. * The ContactMaterials added to the World.
  8121. * @property contactMaterials
  8122. * @type {Array}
  8123. */
  8124. this.contactMaterials = [];
  8125. /**
  8126. * World time.
  8127. * @property time
  8128. * @type {Number}
  8129. */
  8130. this.time = 0.0;
  8131. /**
  8132. * Is true during the step().
  8133. * @property {Boolean} stepping
  8134. */
  8135. this.stepping = false;
  8136. /**
  8137. * Bodies that are scheduled to be removed at the end of the step.
  8138. * @property {Array} bodiesToBeRemoved
  8139. * @private
  8140. */
  8141. this.bodiesToBeRemoved = [];
  8142. this.fixedStepTime = 0.0;
  8143. /**
  8144. * Whether to enable island splitting. Island splitting can be an advantage for many things, including solver performance. See {{#crossLink "IslandManager"}}{{/crossLink}}.
  8145. * @property {Boolean} islandSplit
  8146. */
  8147. this.islandSplit = typeof(options.islandSplit)!=="undefined" ? !!options.islandSplit : false;
  8148. /**
  8149. * Set to true if you want to the world to emit the "impact" event. Turning this off could improve performance.
  8150. * @property emitImpactEvent
  8151. * @type {Boolean}
  8152. */
  8153. this.emitImpactEvent = true;
  8154. // Id counters
  8155. this._constraintIdCounter = 0;
  8156. this._bodyIdCounter = 0;
  8157. /**
  8158. * Fired after the step().
  8159. * @event postStep
  8160. */
  8161. this.postStepEvent = {
  8162. type : "postStep",
  8163. };
  8164. /**
  8165. * Fired when a body is added to the world.
  8166. * @event addBody
  8167. * @param {Body} body
  8168. */
  8169. this.addBodyEvent = {
  8170. type : "addBody",
  8171. body : null
  8172. };
  8173. /**
  8174. * Fired when a body is removed from the world.
  8175. * @event removeBody
  8176. * @param {Body} body
  8177. */
  8178. this.removeBodyEvent = {
  8179. type : "removeBody",
  8180. body : null
  8181. };
  8182. /**
  8183. * Fired when a spring is added to the world.
  8184. * @event addSpring
  8185. * @param {Spring} spring
  8186. */
  8187. this.addSpringEvent = {
  8188. type : "addSpring",
  8189. spring : null,
  8190. };
  8191. /**
  8192. * Fired when a first contact is created between two bodies. This event is fired after the step has been done.
  8193. * @event impact
  8194. * @param {Body} bodyA
  8195. * @param {Body} bodyB
  8196. */
  8197. this.impactEvent = {
  8198. type: "impact",
  8199. bodyA : null,
  8200. bodyB : null,
  8201. shapeA : null,
  8202. shapeB : null,
  8203. contactEquation : null,
  8204. };
  8205. /**
  8206. * Fired after the Broadphase has collected collision pairs in the world.
  8207. * Inside the event handler, you can modify the pairs array as you like, to
  8208. * prevent collisions between objects that you don't want.
  8209. * @event postBroadphase
  8210. * @param {Array} pairs An array of collision pairs. If this array is [body1,body2,body3,body4], then the body pairs 1,2 and 3,4 would advance to narrowphase.
  8211. */
  8212. this.postBroadphaseEvent = {
  8213. type:"postBroadphase",
  8214. pairs:null,
  8215. };
  8216. /**
  8217. * Enable / disable automatic body sleeping. Sleeping can improve performance. You might need to {{#crossLink "Body/wakeUp:method"}}wake up{{/crossLink}} the bodies if they fall asleep when they shouldn't. If you want to enable sleeping in the world, but want to disable it for a particular body, see {{#crossLink "Body/allowSleep:property"}}Body.allowSleep{{/crossLink}}.
  8218. * @property allowSleep
  8219. * @type {Boolean}
  8220. */
  8221. this.enableBodySleeping = false;
  8222. /**
  8223. * Enable or disable island sleeping. Note that you must enable {{#crossLink "World/islandSplit:property"}}.islandSplit{{/crossLink}} for this to work.
  8224. * @property {Boolean} enableIslandSleeping
  8225. */
  8226. this.enableIslandSleeping = false;
  8227. /**
  8228. * Fired when two shapes starts start to overlap. Fired in the narrowphase, during step.
  8229. * @event beginContact
  8230. * @param {Shape} shapeA
  8231. * @param {Shape} shapeB
  8232. * @param {Body} bodyA
  8233. * @param {Body} bodyB
  8234. * @param {Array} contactEquations
  8235. */
  8236. this.beginContactEvent = {
  8237. type:"beginContact",
  8238. shapeA : null,
  8239. shapeB : null,
  8240. bodyA : null,
  8241. bodyB : null,
  8242. contactEquations : [],
  8243. };
  8244. /**
  8245. * Fired when two shapes stop overlapping, after the narrowphase (during step).
  8246. * @event endContact
  8247. * @param {Shape} shapeA
  8248. * @param {Shape} shapeB
  8249. * @param {Body} bodyA
  8250. * @param {Body} bodyB
  8251. * @param {Array} contactEquations
  8252. */
  8253. this.endContactEvent = {
  8254. type:"endContact",
  8255. shapeA : null,
  8256. shapeB : null,
  8257. bodyA : null,
  8258. bodyB : null,
  8259. };
  8260. /**
  8261. * Fired just before equations are added to the solver to be solved. Can be used to control what equations goes into the solver.
  8262. * @event preSolve
  8263. * @param {Array} contactEquations An array of contacts to be solved.
  8264. * @param {Array} frictionEquations An array of friction equations to be solved.
  8265. */
  8266. this.preSolveEvent = {
  8267. type:"preSolve",
  8268. contactEquations:null,
  8269. frictionEquations:null,
  8270. };
  8271. // For keeping track of overlapping shapes
  8272. this.overlappingShapesLastState = { keys:[] };
  8273. this.overlappingShapesCurrentState = { keys:[] };
  8274. this.overlappingShapeLookup = { keys:[] };
  8275. }
  8276. World.prototype = new Object(EventEmitter.prototype);
  8277. /**
  8278. * Add a constraint to the simulation.
  8279. *
  8280. * @method addConstraint
  8281. * @param {Constraint} c
  8282. */
  8283. World.prototype.addConstraint = function(c){
  8284. this.constraints.push(c);
  8285. };
  8286. /**
  8287. * Add a ContactMaterial to the simulation.
  8288. * @method addContactMaterial
  8289. * @param {ContactMaterial} contactMaterial
  8290. */
  8291. World.prototype.addContactMaterial = function(contactMaterial){
  8292. this.contactMaterials.push(contactMaterial);
  8293. };
  8294. /**
  8295. * Removes a contact material
  8296. *
  8297. * @method removeContactMaterial
  8298. * @param {ContactMaterial} cm
  8299. */
  8300. World.prototype.removeContactMaterial = function(cm){
  8301. var idx = this.contactMaterials.indexOf(cm);
  8302. if(idx!==-1){
  8303. Utils.splice(this.contactMaterials,idx,1);
  8304. }
  8305. };
  8306. /**
  8307. * Get a contact material given two materials
  8308. * @method getContactMaterial
  8309. * @param {Material} materialA
  8310. * @param {Material} materialB
  8311. * @return {ContactMaterial} The matching ContactMaterial, or false on fail.
  8312. * @todo Use faster hash map to lookup from material id's
  8313. */
  8314. World.prototype.getContactMaterial = function(materialA,materialB){
  8315. var cmats = this.contactMaterials;
  8316. for(var i=0, N=cmats.length; i!==N; i++){
  8317. var cm = cmats[i];
  8318. if( (cm.materialA === materialA) && (cm.materialB === materialB) ||
  8319. (cm.materialA === materialB) && (cm.materialB === materialA) ){
  8320. return cm;
  8321. }
  8322. }
  8323. return false;
  8324. };
  8325. /**
  8326. * Removes a constraint
  8327. *
  8328. * @method removeConstraint
  8329. * @param {Constraint} c
  8330. */
  8331. World.prototype.removeConstraint = function(c){
  8332. var idx = this.constraints.indexOf(c);
  8333. if(idx!==-1){
  8334. Utils.splice(this.constraints,idx,1);
  8335. }
  8336. };
  8337. var step_r = vec2.create(),
  8338. step_runit = vec2.create(),
  8339. step_u = vec2.create(),
  8340. step_f = vec2.create(),
  8341. step_fhMinv = vec2.create(),
  8342. step_velodt = vec2.create(),
  8343. step_mg = vec2.create(),
  8344. xiw = vec2.fromValues(0,0),
  8345. xjw = vec2.fromValues(0,0),
  8346. zero = vec2.fromValues(0,0),
  8347. interpvelo = vec2.fromValues(0,0);
  8348. /**
  8349. * Step the physics world forward in time.
  8350. *
  8351. * There are two modes. The simple mode is fixed timestepping without interpolation. In this case you only use the first argument. The second case uses interpolation. In that you also provide the time since the function was last used, as well as the maximum fixed timesteps to take.
  8352. *
  8353. * @method step
  8354. * @param {Number} dt The fixed time step size to use.
  8355. * @param {Number} [timeSinceLastCalled=0] The time elapsed since the function was last called.
  8356. * @param {Number} [maxSubSteps=10] Maximum number of fixed steps to take per function call.
  8357. *
  8358. * @example
  8359. * // fixed timestepping without interpolation
  8360. * var world = new World();
  8361. * world.step(0.01);
  8362. *
  8363. * @see http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
  8364. */
  8365. World.prototype.step = function(dt,timeSinceLastCalled,maxSubSteps){
  8366. maxSubSteps = maxSubSteps || 10;
  8367. timeSinceLastCalled = timeSinceLastCalled || 0;
  8368. if(timeSinceLastCalled === 0){ // Fixed, simple stepping
  8369. this.internalStep(dt);
  8370. // Increment time
  8371. this.time += dt;
  8372. } else {
  8373. // Compute the number of fixed steps we should have taken since the last step
  8374. var internalSteps = Math.floor( (this.time+timeSinceLastCalled) / dt) - Math.floor(this.time / dt);
  8375. internalSteps = Math.min(internalSteps,maxSubSteps);
  8376. // Do some fixed steps to catch up
  8377. for(var i=0; i<internalSteps; i++){
  8378. this.internalStep(dt);
  8379. }
  8380. // Increment internal clock
  8381. this.time += timeSinceLastCalled;
  8382. // Compute "Left over" time step
  8383. var h = this.time % dt;
  8384. for(var j=0; j!==this.bodies.length; j++){
  8385. var b = this.bodies[j];
  8386. if(b.motionState !== Body.STATIC && b.sleepState !== Body.SLEEPING){
  8387. // Interpolate
  8388. vec2.sub(interpvelo, b.position, b.previousPosition);
  8389. vec2.scale(interpvelo, interpvelo, h/dt);
  8390. vec2.add(b.interpolatedPosition, b.position, interpvelo);
  8391. b.interpolatedAngle = b.angle + (b.angle - b.previousAngle) * h/dt;
  8392. } else {
  8393. // For static bodies, just copy. Who else will do it?
  8394. vec2.copy(b.interpolatedPosition, b.position);
  8395. b.interpolatedAngle = b.angle;
  8396. }
  8397. }
  8398. }
  8399. };
  8400. /**
  8401. * Make a fixed step.
  8402. * @method internalStep
  8403. * @param {number} dt
  8404. * @private
  8405. */
  8406. World.prototype.internalStep = function(dt){
  8407. this.stepping = true;
  8408. var that = this,
  8409. doProfiling = this.doProfiling,
  8410. Nsprings = this.springs.length,
  8411. springs = this.springs,
  8412. bodies = this.bodies,
  8413. g = this.gravity,
  8414. solver = this.solver,
  8415. Nbodies = this.bodies.length,
  8416. broadphase = this.broadphase,
  8417. np = this.narrowphase,
  8418. constraints = this.constraints,
  8419. t0, t1,
  8420. fhMinv = step_fhMinv,
  8421. velodt = step_velodt,
  8422. mg = step_mg,
  8423. scale = vec2.scale,
  8424. add = vec2.add,
  8425. rotate = vec2.rotate,
  8426. islandManager = this.islandManager;
  8427. this.lastTimeStep = dt;
  8428. if(doProfiling){
  8429. t0 = performance.now();
  8430. }
  8431. // Update approximate friction gravity.
  8432. if(this.useWorldGravityAsFrictionGravity){
  8433. var gravityLen = vec2.length(this.gravity);
  8434. if(gravityLen === 0 && this.useFrictionGravityOnZeroGravity){
  8435. // Leave friction gravity as it is.
  8436. } else {
  8437. // Nonzero gravity. Use it.
  8438. this.frictionGravity = gravityLen;
  8439. }
  8440. }
  8441. // Add gravity to bodies
  8442. if(this.applyGravity){
  8443. for(var i=0; i!==Nbodies; i++){
  8444. var b = bodies[i],
  8445. fi = b.force;
  8446. if(b.motionState !== Body.DYNAMIC || b.sleepState === Body.SLEEPING){
  8447. continue;
  8448. }
  8449. vec2.scale(mg,g,b.mass*b.gravityScale); // F=m*g
  8450. add(fi,fi,mg);
  8451. }
  8452. }
  8453. // Add spring forces
  8454. if(this.applySpringForces){
  8455. for(var i=0; i!==Nsprings; i++){
  8456. var s = springs[i];
  8457. s.applyForce();
  8458. }
  8459. }
  8460. if(this.applyDamping){
  8461. for(var i=0; i!==Nbodies; i++){
  8462. var b = bodies[i];
  8463. if(b.motionState === Body.DYNAMIC){
  8464. b.applyDamping(dt);
  8465. }
  8466. }
  8467. }
  8468. // Broadphase
  8469. var result = broadphase.getCollisionPairs(this);
  8470. // Remove ignored collision pairs
  8471. var ignoredPairs = this.disabledBodyCollisionPairs;
  8472. for(var i=ignoredPairs.length-2; i>=0; i-=2){
  8473. for(var j=result.length-2; j>=0; j-=2){
  8474. if( (ignoredPairs[i] === result[j] && ignoredPairs[i+1] === result[j+1]) ||
  8475. (ignoredPairs[i+1] === result[j] && ignoredPairs[i] === result[j+1])){
  8476. result.splice(j,2);
  8477. }
  8478. }
  8479. }
  8480. // Remove constrained pairs with collideConnected == false
  8481. var Nconstraints = constraints.length;
  8482. for(i=0; i!==Nconstraints; i++){
  8483. var c = constraints[i];
  8484. if(!c.collideConnected){
  8485. for(var j=result.length-2; j>=0; j-=2){
  8486. if( (c.bodyA === result[j] && c.bodyB === result[j+1]) ||
  8487. (c.bodyB === result[j] && c.bodyA === result[j+1])){
  8488. result.splice(j,2);
  8489. }
  8490. }
  8491. }
  8492. }
  8493. // postBroadphase event
  8494. this.postBroadphaseEvent.pairs = result;
  8495. this.emit(this.postBroadphaseEvent);
  8496. // Narrowphase
  8497. np.reset(this);
  8498. for(var i=0, Nresults=result.length; i!==Nresults; i+=2){
  8499. var bi = result[i],
  8500. bj = result[i+1];
  8501. // Loop over all shapes of body i
  8502. for(var k=0, Nshapesi=bi.shapes.length; k!==Nshapesi; k++){
  8503. var si = bi.shapes[k],
  8504. xi = bi.shapeOffsets[k],
  8505. ai = bi.shapeAngles[k];
  8506. // All shapes of body j
  8507. for(var l=0, Nshapesj=bj.shapes.length; l!==Nshapesj; l++){
  8508. var sj = bj.shapes[l],
  8509. xj = bj.shapeOffsets[l],
  8510. aj = bj.shapeAngles[l];
  8511. var cm = this.defaultContactMaterial;
  8512. if(si.material && sj.material){
  8513. var tmp = this.getContactMaterial(si.material,sj.material);
  8514. if(tmp){
  8515. cm = tmp;
  8516. }
  8517. }
  8518. this.runNarrowphase(np,bi,si,xi,ai,bj,sj,xj,aj,cm,this.frictionGravity);
  8519. }
  8520. }
  8521. }
  8522. // Emit shape end overlap events
  8523. var last = this.overlappingShapesLastState;
  8524. for(var i=0; i!==last.keys.length; i++){
  8525. var key = last.keys[i];
  8526. if(last[key]!==true){
  8527. continue;
  8528. }
  8529. if(!this.overlappingShapesCurrentState[key]){
  8530. // Not overlapping in current state, but in last state. Emit event!
  8531. var e = this.endContactEvent;
  8532. // Add shapes to the event object
  8533. e.shapeA = last[key+"_shapeA"];
  8534. e.shapeB = last[key+"_shapeB"];
  8535. e.bodyA = last[key+"_bodyA"];
  8536. e.bodyB = last[key+"_bodyB"];
  8537. this.emit(e);
  8538. }
  8539. }
  8540. // Clear last object
  8541. for(var i=0; i!==last.keys.length; i++){
  8542. delete last[last.keys[i]];
  8543. }
  8544. last.keys.length = 0;
  8545. // Transfer from new object to old
  8546. var current = this.overlappingShapesCurrentState;
  8547. for(var i=0; i!==current.keys.length; i++){
  8548. last[current.keys[i]] = current[current.keys[i]];
  8549. last.keys.push(current.keys[i]);
  8550. }
  8551. // Clear current object
  8552. for(var i=0; i!==current.keys.length; i++){
  8553. delete current[current.keys[i]];
  8554. }
  8555. current.keys.length = 0;
  8556. var preSolveEvent = this.preSolveEvent;
  8557. preSolveEvent.contactEquations = np.contactEquations;
  8558. preSolveEvent.frictionEquations = np.frictionEquations;
  8559. this.emit(preSolveEvent);
  8560. // update constraint equations
  8561. var Nconstraints = constraints.length;
  8562. for(i=0; i!==Nconstraints; i++){
  8563. constraints[i].update();
  8564. }
  8565. if(np.contactEquations.length || np.frictionEquations.length || constraints.length){
  8566. if(this.islandSplit){
  8567. // Split into islands
  8568. islandManager.equations.length = 0;
  8569. Utils.appendArray(islandManager.equations, np.contactEquations);
  8570. Utils.appendArray(islandManager.equations, np.frictionEquations);
  8571. for(i=0; i!==Nconstraints; i++){
  8572. Utils.appendArray(islandManager.equations, constraints[i].equations);
  8573. }
  8574. islandManager.split(this);
  8575. for(var i=0; i!==islandManager.islands.length; i++){
  8576. var island = islandManager.islands[i];
  8577. if(island.equations.length){
  8578. solver.solveIsland(dt,island);
  8579. }
  8580. }
  8581. } else {
  8582. // Add contact equations to solver
  8583. solver.addEquations(np.contactEquations);
  8584. solver.addEquations(np.frictionEquations);
  8585. // Add user-defined constraint equations
  8586. for(i=0; i!==Nconstraints; i++){
  8587. solver.addEquations(constraints[i].equations);
  8588. }
  8589. if(this.solveConstraints){
  8590. solver.solve(dt,this);
  8591. }
  8592. solver.removeAllEquations();
  8593. }
  8594. }
  8595. // Step forward
  8596. for(var i=0; i!==Nbodies; i++){
  8597. var body = bodies[i];
  8598. if(body.sleepState !== Body.SLEEPING && body.motionState !== Body.STATIC){
  8599. World.integrateBody(body,dt);
  8600. }
  8601. }
  8602. // Reset force
  8603. for(var i=0; i!==Nbodies; i++){
  8604. bodies[i].setZeroForce();
  8605. }
  8606. if(doProfiling){
  8607. t1 = performance.now();
  8608. that.lastStepTime = t1-t0;
  8609. }
  8610. // Emit impact event
  8611. if(this.emitImpactEvent){
  8612. var ev = this.impactEvent;
  8613. for(var i=0; i!==np.contactEquations.length; i++){
  8614. var eq = np.contactEquations[i];
  8615. if(eq.firstImpact){
  8616. ev.bodyA = eq.bodyA;
  8617. ev.bodyB = eq.bodyB;
  8618. ev.shapeA = eq.shapeA;
  8619. ev.shapeB = eq.shapeB;
  8620. ev.contactEquation = eq;
  8621. this.emit(ev);
  8622. }
  8623. }
  8624. }
  8625. // Sleeping update
  8626. if(this.enableBodySleeping){
  8627. for(i=0; i!==Nbodies; i++){
  8628. bodies[i].sleepTick(this.time, false, dt);
  8629. }
  8630. } else if(this.enableIslandSleeping && this.islandSplit){
  8631. // Tell all bodies to sleep tick but dont sleep yet
  8632. for(i=0; i!==Nbodies; i++){
  8633. bodies[i].sleepTick(this.time, true, dt);
  8634. }
  8635. // Sleep islands
  8636. for(var i=0; i<this.islandManager.islands.length; i++){
  8637. var island = this.islandManager.islands[i];
  8638. if(island.wantsToSleep()){
  8639. island.sleep();
  8640. }
  8641. }
  8642. }
  8643. this.stepping = false;
  8644. // Remove bodies that are scheduled for removal
  8645. if(this.bodiesToBeRemoved.length){
  8646. for(var i=0; i!==this.bodiesToBeRemoved.length; i++){
  8647. this.removeBody(this.bodiesToBeRemoved[i]);
  8648. }
  8649. this.bodiesToBeRemoved.length = 0;
  8650. }
  8651. this.emit(this.postStepEvent);
  8652. };
  8653. var ib_fhMinv = vec2.create();
  8654. var ib_velodt = vec2.create();
  8655. /**
  8656. * Move a body forward in time.
  8657. * @static
  8658. * @method integrateBody
  8659. * @param {Body} body
  8660. * @param {Number} dt
  8661. * @todo Move to Body.prototype?
  8662. */
  8663. World.integrateBody = function(body,dt){
  8664. var minv = body.invMass,
  8665. f = body.force,
  8666. pos = body.position,
  8667. velo = body.velocity;
  8668. // Save old position
  8669. vec2.copy(body.previousPosition, body.position);
  8670. body.previousAngle = body.angle;
  8671. // Angular step
  8672. if(!body.fixedRotation){
  8673. body.angularVelocity += body.angularForce * body.invInertia * dt;
  8674. body.angle += body.angularVelocity * dt;
  8675. }
  8676. // Linear step
  8677. vec2.scale(ib_fhMinv,f,dt*minv);
  8678. vec2.add(velo,ib_fhMinv,velo);
  8679. vec2.scale(ib_velodt,velo,dt);
  8680. vec2.add(pos,pos,ib_velodt);
  8681. body.aabbNeedsUpdate = true;
  8682. };
  8683. /**
  8684. * Runs narrowphase for the shape pair i and j.
  8685. * @method runNarrowphase
  8686. * @param {Narrowphase} np
  8687. * @param {Body} bi
  8688. * @param {Shape} si
  8689. * @param {Array} xi
  8690. * @param {Number} ai
  8691. * @param {Body} bj
  8692. * @param {Shape} sj
  8693. * @param {Array} xj
  8694. * @param {Number} aj
  8695. * @param {Number} mu
  8696. */
  8697. World.prototype.runNarrowphase = function(np,bi,si,xi,ai,bj,sj,xj,aj,cm,glen){
  8698. // Check collision groups and masks
  8699. if(!((si.collisionGroup & sj.collisionMask) !== 0 && (sj.collisionGroup & si.collisionMask) !== 0)){
  8700. return;
  8701. }
  8702. // Get world position and angle of each shape
  8703. vec2.rotate(xiw, xi, bi.angle);
  8704. vec2.rotate(xjw, xj, bj.angle);
  8705. vec2.add(xiw, xiw, bi.position);
  8706. vec2.add(xjw, xjw, bj.position);
  8707. var aiw = ai + bi.angle;
  8708. var ajw = aj + bj.angle;
  8709. np.enableFriction = cm.friction > 0;
  8710. np.frictionCoefficient = cm.friction;
  8711. var reducedMass;
  8712. if(bi.motionState === Body.STATIC || bi.motionState === Body.KINEMATIC){
  8713. reducedMass = bj.mass;
  8714. } else if(bj.motionState === Body.STATIC || bj.motionState === Body.KINEMATIC){
  8715. reducedMass = bi.mass;
  8716. } else {
  8717. reducedMass = (bi.mass*bj.mass)/(bi.mass+bj.mass);
  8718. }
  8719. np.slipForce = cm.friction*glen*reducedMass;
  8720. np.restitution = cm.restitution;
  8721. np.surfaceVelocity = cm.surfaceVelocity;
  8722. np.frictionStiffness = cm.frictionStiffness;
  8723. np.frictionRelaxation = cm.frictionRelaxation;
  8724. np.stiffness = cm.stiffness;
  8725. np.relaxation = cm.relaxation;
  8726. var resolver = np[si.type | sj.type],
  8727. numContacts = 0;
  8728. if (resolver) {
  8729. var sensor = si.sensor || sj.sensor;
  8730. var numFrictionBefore = np.frictionEquations.length;
  8731. if (si.type < sj.type) {
  8732. numContacts = resolver.call(np, bi,si,xiw,aiw, bj,sj,xjw,ajw, sensor);
  8733. } else {
  8734. numContacts = resolver.call(np, bj,sj,xjw,ajw, bi,si,xiw,aiw, sensor);
  8735. }
  8736. var numFrictionEquations = np.frictionEquations.length - numFrictionBefore;
  8737. if(numContacts){
  8738. // Wake up bodies
  8739. var wakeUpA = false;
  8740. var wakeUpB = false;
  8741. var speedSquaredA = vec2.squaredLength(bi.velocity) + Math.pow(bi.angularVelocity,2);
  8742. var speedLimitSquaredA = Math.pow(bi.sleepSpeedLimit,2);
  8743. var speedSquaredB = vec2.squaredLength(bj.velocity) + Math.pow(bj.angularVelocity,2);
  8744. var speedLimitSquaredB = Math.pow(bj.sleepSpeedLimit,2);
  8745. if( bi.allowSleep &&
  8746. bi.motionState === Body.DYNAMIC &&
  8747. bi.sleepState === Body.SLEEPING &&
  8748. bj.sleepState === Body.AWAKE &&
  8749. bj.motionState !== Body.STATIC &&
  8750. speedSquaredB >= speedLimitSquaredB*2
  8751. ){
  8752. wakeUpA = true;
  8753. }
  8754. if( bj.allowSleep &&
  8755. bj.motionState === Body.DYNAMIC &&
  8756. bj.sleepState === Body.SLEEPING &&
  8757. bi.sleepState === Body.AWAKE &&
  8758. bi.motionState !== Body.STATIC &&
  8759. speedSquaredA >= speedLimitSquaredA*2
  8760. ){
  8761. wakeUpB = true;
  8762. }
  8763. if(wakeUpA){
  8764. bi.wakeUp();
  8765. }
  8766. if(wakeUpB){
  8767. bj.wakeUp();
  8768. }
  8769. var key = si.id < sj.id ? si.id+" "+ sj.id : sj.id+" "+ si.id;
  8770. if(!this.overlappingShapesLastState[key]){
  8771. // Report new shape overlap
  8772. var e = this.beginContactEvent;
  8773. e.shapeA = si;
  8774. e.shapeB = sj;
  8775. e.bodyA = bi;
  8776. e.bodyB = bj;
  8777. // Reset contact equations
  8778. e.contactEquations.length = 0;
  8779. if(typeof(numContacts)==="number"){
  8780. for(var i=np.contactEquations.length-numContacts; i<np.contactEquations.length; i++){
  8781. e.contactEquations.push(np.contactEquations[i]);
  8782. }
  8783. }
  8784. this.emit(e);
  8785. }
  8786. // Store current contact state
  8787. var current = this.overlappingShapesCurrentState;
  8788. if(!current[key]){
  8789. current[key] = true;
  8790. current.keys.push(key);
  8791. // Also store shape & body data
  8792. current[key+"_shapeA"] = si;
  8793. current.keys.push(key+"_shapeA");
  8794. current[key+"_shapeB"] = sj;
  8795. current.keys.push(key+"_shapeB");
  8796. current[key+"_bodyA"] = bi;
  8797. current.keys.push(key+"_bodyA");
  8798. current[key+"_bodyB"] = bj;
  8799. current.keys.push(key+"_bodyB");
  8800. }
  8801. // divide the max friction force by the number of contacts
  8802. if(typeof(numContacts)==="number" && numFrictionEquations > 1){ // Why divide by 1?
  8803. for(var i=np.frictionEquations.length-numFrictionEquations; i<np.frictionEquations.length; i++){
  8804. var f = np.frictionEquations[i];
  8805. f.setSlipForce(f.getSlipForce() / numFrictionEquations);
  8806. }
  8807. }
  8808. }
  8809. }
  8810. };
  8811. /**
  8812. * Add a spring to the simulation
  8813. *
  8814. * @method addSpring
  8815. * @param {Spring} s
  8816. */
  8817. World.prototype.addSpring = function(s){
  8818. this.springs.push(s);
  8819. this.addSpringEvent.spring = s;
  8820. this.emit(this.addSpringEvent);
  8821. };
  8822. /**
  8823. * Remove a spring
  8824. *
  8825. * @method removeSpring
  8826. * @param {Spring} s
  8827. */
  8828. World.prototype.removeSpring = function(s){
  8829. var idx = this.springs.indexOf(s);
  8830. if(idx===-1){
  8831. Utils.splice(this.springs,idx,1);
  8832. }
  8833. };
  8834. /**
  8835. * Add a body to the simulation
  8836. *
  8837. * @method addBody
  8838. * @param {Body} body
  8839. *
  8840. * @example
  8841. * var world = new World(),
  8842. * body = new Body();
  8843. * world.addBody(body);
  8844. * @todo What if this is done during step?
  8845. */
  8846. World.prototype.addBody = function(body){
  8847. if(this.bodies.indexOf(body) === -1){
  8848. this.bodies.push(body);
  8849. body.world = this;
  8850. this.addBodyEvent.body = body;
  8851. this.emit(this.addBodyEvent);
  8852. }
  8853. };
  8854. /**
  8855. * Remove a body from the simulation. If this method is called during step(), the body removal is scheduled to after the step.
  8856. *
  8857. * @method removeBody
  8858. * @param {Body} body
  8859. */
  8860. World.prototype.removeBody = function(body){
  8861. if(this.stepping){
  8862. this.bodiesToBeRemoved.push(body);
  8863. } else {
  8864. body.world = null;
  8865. var idx = this.bodies.indexOf(body);
  8866. if(idx!==-1){
  8867. Utils.splice(this.bodies,idx,1);
  8868. this.removeBodyEvent.body = body;
  8869. body.resetConstraintVelocity();
  8870. this.emit(this.removeBodyEvent);
  8871. }
  8872. }
  8873. };
  8874. /**
  8875. * Get a body by its id.
  8876. * @method getBodyById
  8877. * @return {Body|Boolean} The body, or false if it was not found.
  8878. */
  8879. World.prototype.getBodyById = function(id){
  8880. var bodies = this.bodies;
  8881. for(var i=0; i<bodies.length; i++){
  8882. var b = bodies[i];
  8883. if(b.id === id){
  8884. return b;
  8885. }
  8886. }
  8887. return false;
  8888. };
  8889. /**
  8890. * Disable collision between two bodies
  8891. * @method disableCollision
  8892. * @param {Body} bodyA
  8893. * @param {Body} bodyB
  8894. */
  8895. World.prototype.disableBodyCollision = function(bodyA,bodyB){
  8896. this.disabledBodyCollisionPairs.push(bodyA,bodyB);
  8897. };
  8898. /**
  8899. * Enable collisions between the given two bodies
  8900. * @method enableCollision
  8901. * @param {Body} bodyA
  8902. * @param {Body} bodyB
  8903. */
  8904. World.prototype.enableBodyCollision = function(bodyA,bodyB){
  8905. var pairs = this.disabledBodyCollisionPairs;
  8906. for(var i=0; i<pairs.length; i+=2){
  8907. if((pairs[i] === bodyA && pairs[i+1] === bodyB) || (pairs[i+1] === bodyA && pairs[i] === bodyB)){
  8908. pairs.splice(i,2);
  8909. return;
  8910. }
  8911. }
  8912. };
  8913. function v2a(v){
  8914. if(!v) return v;
  8915. return [v[0],v[1]];
  8916. }
  8917. function extend(a,b){
  8918. for(var key in b)
  8919. a[key] = b[key];
  8920. }
  8921. function contactMaterialToJSON(cm){
  8922. return {
  8923. id : cm.id,
  8924. materialA : cm.materialA.id,
  8925. materialB : cm.materialB.id,
  8926. friction : cm.friction,
  8927. restitution : cm.restitution,
  8928. stiffness : cm.stiffness,
  8929. relaxation : cm.relaxation,
  8930. frictionStiffness : cm.frictionStiffness,
  8931. frictionRelaxation : cm.frictionRelaxation,
  8932. };
  8933. }
  8934. /**
  8935. * Convert the world to a JSON-serializable Object.
  8936. *
  8937. * @method toJSON
  8938. * @return {Object}
  8939. * @deprecated Should use Serializer instead.
  8940. */
  8941. World.prototype.toJSON = function(){
  8942. var world = this;
  8943. var json = {
  8944. p2 : pkg.version,
  8945. bodies : [],
  8946. springs : [],
  8947. solver : {},
  8948. gravity : v2a(world.gravity),
  8949. broadphase : {},
  8950. distanceConstraints : [],
  8951. revoluteConstraints : [],
  8952. prismaticConstraints : [],
  8953. lockConstraints : [],
  8954. gearConstraints : [],
  8955. contactMaterials : [],
  8956. materials : [],
  8957. defaultContactMaterial : contactMaterialToJSON(world.defaultContactMaterial),
  8958. islandSplit : world.islandSplit,
  8959. enableIslandSleeping : world.enableIslandSleeping,
  8960. enableBodySleeping : world.enableBodySleeping,
  8961. };
  8962. // Solver
  8963. var js = json.solver,
  8964. s = world.solver;
  8965. if(s.type === Solver.GS){
  8966. js.type = "GSSolver";
  8967. js.iterations = s.iterations;
  8968. }
  8969. // Broadphase
  8970. var jb = json.broadphase,
  8971. wb = world.broadphase;
  8972. if(wb.type === Broadphase.NAIVE){
  8973. jb.type = "NaiveBroadphase";
  8974. } else if(wb.type === Broadphase.SAP) {
  8975. jb.type = "SAPBroadphase";
  8976. //jb.axisIndex = wb.axisIndex;
  8977. } else {
  8978. console.error("Broadphase not supported: "+wb.type);
  8979. }
  8980. // Serialize springs
  8981. for(var i=0; i!==world.springs.length; i++){
  8982. var s = world.springs[i];
  8983. json.springs.push({
  8984. bodyA : world.bodies.indexOf(s.bodyA),
  8985. bodyB : world.bodies.indexOf(s.bodyB),
  8986. stiffness : s.stiffness,
  8987. damping : s.damping,
  8988. restLength : s.restLength,
  8989. localAnchorA : v2a(s.localAnchorA),
  8990. localAnchorB : v2a(s.localAnchorB),
  8991. });
  8992. }
  8993. // Serialize constraints
  8994. for(var i=0; i<world.constraints.length; i++){
  8995. var c = world.constraints[i];
  8996. var jc = {
  8997. bodyA : world.bodies.indexOf(c.bodyA),
  8998. bodyB : world.bodies.indexOf(c.bodyB),
  8999. collideConnected : c.collideConnected
  9000. };
  9001. switch(c.type){
  9002. case Constraint.DISTANCE:
  9003. extend(jc,{
  9004. distance : c.distance,
  9005. maxForce : c.getMaxForce(),
  9006. });
  9007. json.distanceConstraints.push(jc);
  9008. break;
  9009. case Constraint.REVOLUTE:
  9010. extend(jc,{
  9011. pivotA : v2a(c.pivotA),
  9012. pivotB : v2a(c.pivotB),
  9013. maxForce : c.maxForce,
  9014. motorSpeed : c.getMotorSpeed() || 0,
  9015. motorEnabled : !!c.getMotorSpeed(),
  9016. lowerLimit : c.lowerLimit,
  9017. lowerLimitEnabled : c.lowerLimitEnabled,
  9018. upperLimit : c.upperLimit,
  9019. upperLimitEnabled : c.upperLimitEnabled,
  9020. });
  9021. json.revoluteConstraints.push(jc);
  9022. break;
  9023. case Constraint.PRISMATIC:
  9024. extend(jc,{
  9025. localAxisA : v2a(c.localAxisA),
  9026. localAnchorA : v2a(c.localAnchorA),
  9027. localAnchorB : v2a(c.localAnchorB),
  9028. maxForce : c.maxForce,
  9029. upperLimitEnabled : c.upperLimitEnabled,
  9030. lowerLimitEnabled : c.lowerLimitEnabled,
  9031. upperLimit : c.upperLimit,
  9032. lowerLimit : c.lowerLimit,
  9033. motorEnabled : c.motorEnabled,
  9034. motorSpeed : c.motorSpeed,
  9035. });
  9036. json.prismaticConstraints.push(jc);
  9037. break;
  9038. case Constraint.LOCK:
  9039. extend(jc,{
  9040. localOffsetB : v2a(c.localOffsetB),
  9041. localAngleB : c.localAngleB,
  9042. maxForce : c.getMaxForce(),
  9043. });
  9044. json.lockConstraints.push(jc);
  9045. break;
  9046. case Constraint.GEAR:
  9047. extend(jc,{
  9048. angle : c.angle,
  9049. ratio : c.ratio,
  9050. maxForce : c.maxForce || 1e6, // correct?
  9051. });
  9052. json.gearConstraints.push(jc);
  9053. break;
  9054. default:
  9055. console.error("Constraint not supported yet: ",c.type);
  9056. break;
  9057. }
  9058. }
  9059. // Serialize bodies
  9060. for(var i=0; i!==world.bodies.length; i++){
  9061. var b = world.bodies[i],
  9062. ss = b.shapes,
  9063. jsonBody = {
  9064. id : b.id,
  9065. mass : b.mass,
  9066. angle : b.angle,
  9067. position : v2a(b.position),
  9068. velocity : v2a(b.velocity),
  9069. angularVelocity : b.angularVelocity,
  9070. force : v2a(b.force),
  9071. motionState : b.motionState,
  9072. fixedRotation : b.fixedRotation,
  9073. circleShapes : [],
  9074. planeShapes : [],
  9075. particleShapes : [],
  9076. lineShapes : [],
  9077. rectangleShapes : [],
  9078. convexShapes : [],
  9079. capsuleShapes : [],
  9080. };
  9081. if(b.concavePath){
  9082. jsonBody.concavePath = b.concavePath;
  9083. }
  9084. for(var j=0; j<ss.length; j++){
  9085. var s = ss[j],
  9086. jsonShape = {};
  9087. jsonShape.offset = v2a(b.shapeOffsets[j]);
  9088. jsonShape.angle = b.shapeAngles[j];
  9089. jsonShape.collisionGroup = s.collisionGroup;
  9090. jsonShape.collisionMask = s.collisionMask;
  9091. jsonShape.material = s.material ? s.material.id : null;
  9092. // Check type
  9093. switch(s.type){
  9094. case Shape.CIRCLE:
  9095. extend(jsonShape,{ radius : s.radius, });
  9096. jsonBody.circleShapes.push(jsonShape);
  9097. break;
  9098. case Shape.PLANE:
  9099. jsonBody.planeShapes.push(jsonShape);
  9100. break;
  9101. case Shape.PARTICLE:
  9102. jsonBody.particleShapes.push(jsonShape);
  9103. break;
  9104. case Shape.LINE:
  9105. jsonShape.length = s.length;
  9106. jsonBody.lineShapes.push(jsonShape);
  9107. break;
  9108. case Shape.RECTANGLE:
  9109. extend(jsonShape,{ width : s.width,
  9110. height : s.height });
  9111. jsonBody.rectangleShapes.push(jsonShape);
  9112. break;
  9113. case Shape.CONVEX:
  9114. var verts = [];
  9115. for(var k=0; k<s.vertices.length; k++){
  9116. verts.push(v2a(s.vertices[k]));
  9117. }
  9118. extend(jsonShape,{ vertices : verts });
  9119. jsonBody.convexShapes.push(jsonShape);
  9120. break;
  9121. case Shape.CAPSULE:
  9122. extend(jsonShape,{ length : s.length, radius : s.radius });
  9123. jsonBody.capsuleShapes.push(jsonShape);
  9124. break;
  9125. default:
  9126. console.error("Shape type not supported yet!");
  9127. break;
  9128. }
  9129. }
  9130. json.bodies.push(jsonBody);
  9131. }
  9132. // Serialize contactmaterials
  9133. for(var i=0; i<world.contactMaterials.length; i++){
  9134. var cm = world.contactMaterials[i];
  9135. json.contactMaterials.push(contactMaterialToJSON(cm));
  9136. }
  9137. // Serialize materials
  9138. var mats = {};
  9139. // Get unique materials first
  9140. for(var i=0; i<world.contactMaterials.length; i++){
  9141. var cm = world.contactMaterials[i];
  9142. mats[cm.materialA.id+''] = cm.materialA;
  9143. mats[cm.materialB.id+''] = cm.materialB;
  9144. }
  9145. for(var matId in mats){
  9146. var m = mats[parseInt(matId)];
  9147. json.materials.push({
  9148. id : m.id,
  9149. });
  9150. }
  9151. return json;
  9152. };
  9153. /**
  9154. * Load a scene from a serialized state in JSON format.
  9155. *
  9156. * @method fromJSON
  9157. * @param {Object} json
  9158. * @return {Boolean} True on success, else false.
  9159. */
  9160. World.prototype.fromJSON = function(json){
  9161. this.clear();
  9162. if(!json.p2){
  9163. return false;
  9164. }
  9165. var w = this;
  9166. // Set gravity
  9167. vec2.copy(w.gravity, json.gravity);
  9168. w.islandSplit = json.islandSplit;
  9169. w.enableIslandSleeping = json.enableIslandSleeping;
  9170. w.enableBodySleeping = json.enableBodySleeping;
  9171. // Set solver
  9172. switch(json.solver.type){
  9173. case "GSSolver":
  9174. var js = json.solver,
  9175. s = new GSSolver();
  9176. w.solver = s;
  9177. s.iterations = js.iterations;
  9178. break;
  9179. default:
  9180. throw new Error("Solver type not recognized: "+json.solver.type);
  9181. }
  9182. // Broadphase
  9183. switch(json.broadphase.type){
  9184. case "NaiveBroadphase":
  9185. w.broadphase = new NaiveBroadphase();
  9186. break;
  9187. case "SAPBroadphase":
  9188. w.broadphase = new SAPBroadphase();
  9189. break;
  9190. }
  9191. w.broadphase.setWorld(w);
  9192. var bodies = w.bodies;
  9193. // Load materials
  9194. var id2material = {};
  9195. for(var i=0; i!==json.materials.length; i++){
  9196. var jm = json.materials[i];
  9197. var m = new Material();
  9198. id2material[jm.id+""] = m;
  9199. m.id = jm.id;
  9200. }
  9201. // Load default material
  9202. w.defaultMaterial.id = json.defaultContactMaterial.materialA;
  9203. // Load bodies
  9204. for(var i=0; i!==json.bodies.length; i++){
  9205. var jb = json.bodies[i];
  9206. // Create body
  9207. var b = new Body({
  9208. mass : jb.mass,
  9209. position : jb.position,
  9210. angle : jb.angle,
  9211. velocity : jb.velocity,
  9212. angularVelocity : jb.angularVelocity,
  9213. force : jb.force,
  9214. fixedRotation : jb.fixedRotation,
  9215. });
  9216. b.id = jb.id;
  9217. b.motionState = jb.motionState;
  9218. // Circle
  9219. for(var j=0; j<jb.circleShapes.length; j++){
  9220. var s = jb.circleShapes[j];
  9221. addShape(b, new Circle(s.radius), s);
  9222. }
  9223. // Plane
  9224. for(var j=0; j<jb.planeShapes.length; j++){
  9225. var s = jb.planeShapes[j];
  9226. addShape(b, new Plane(), s);
  9227. }
  9228. // Particle
  9229. for(var j=0; j<jb.particleShapes.length; j++){
  9230. var s = jb.particleShapes[j];
  9231. addShape(b, new Particle(), s);
  9232. }
  9233. // Line
  9234. for(var j=0; j<jb.lineShapes.length; j++){
  9235. var s = jb.lineShapes[j];
  9236. addShape(b, new Line(s.length), s);
  9237. }
  9238. // Rectangle
  9239. for(var j=0; j<jb.rectangleShapes.length; j++){
  9240. var s = jb.rectangleShapes[j];
  9241. addShape(b, new Rectangle(s.width,s.height), s);
  9242. }
  9243. // Convex
  9244. for(var j=0; j<jb.convexShapes.length; j++){
  9245. var s = jb.convexShapes[j];
  9246. addShape(b, new Convex(s.vertices), s);
  9247. }
  9248. // Capsule
  9249. for(var j=0; j<jb.capsuleShapes.length; j++){
  9250. var s = jb.capsuleShapes[j];
  9251. addShape(b, new Capsule(s.length, s.radius), s);
  9252. }
  9253. function addShape(body, shape, shapeJSON){
  9254. shape.collisionMask = shapeJSON.collisionMask;
  9255. shape.collisionGroup = shapeJSON.collisionGroup;
  9256. if(shapeJSON.material){
  9257. shape.material = id2material[shapeJSON.material+""];
  9258. }
  9259. body.addShape(shape, shapeJSON.offset, shapeJSON.angle);
  9260. }
  9261. if(jb.concavePath){
  9262. b.concavePath = jb.concavePath;
  9263. }
  9264. w.addBody(b);
  9265. }
  9266. // Load springs
  9267. for(var i=0; i<json.springs.length; i++){
  9268. var js = json.springs[i];
  9269. var bodyA = bodies[js.bodyA],
  9270. bodyB = bodies[js.bodyB];
  9271. if(!bodyA){
  9272. this.error = "instance.springs["+i+"] references instance.body["+js.bodyA+"], which does not exist.";
  9273. return false;
  9274. }
  9275. if(!bodyB){
  9276. this.error = "instance.springs["+i+"] references instance.body["+js.bodyB+"], which does not exist.";
  9277. return false;
  9278. }
  9279. var s = new Spring(bodyA, bodyB, {
  9280. stiffness : js.stiffness,
  9281. damping : js.damping,
  9282. restLength : js.restLength,
  9283. localAnchorA : js.localAnchorA,
  9284. localAnchorB : js.localAnchorB,
  9285. });
  9286. w.addSpring(s);
  9287. }
  9288. // Load contact materials
  9289. for(var i=0; i<json.contactMaterials.length; i++){
  9290. var jm = json.contactMaterials[i],
  9291. matA = id2material[jm.materialA+""],
  9292. matB = id2material[jm.materialB+""];
  9293. if(!matA){
  9294. this.error = "Reference to material id "+jm.materialA+": material not found";
  9295. return false;
  9296. }
  9297. if(!matB){
  9298. this.error = "Reference to material id "+jm.materialB+": material not found";
  9299. return false;
  9300. }
  9301. var cm = new ContactMaterial(matA, matB, {
  9302. friction : jm.friction,
  9303. restitution : jm.restitution,
  9304. stiffness : jm.stiffness,
  9305. relaxation : jm.relaxation,
  9306. frictionStiffness : jm.frictionStiffness,
  9307. frictionRelaxation : jm.frictionRelaxation,
  9308. });
  9309. cm.id = jm.id;
  9310. w.addContactMaterial(cm);
  9311. }
  9312. // Load default contact material
  9313. var jm = json.defaultContactMaterial,
  9314. matA = w.defaultMaterial,
  9315. matB = w.defaultMaterial;
  9316. var cm = new ContactMaterial(matA, matB, {
  9317. friction : jm.friction,
  9318. restitution : jm.restitution,
  9319. stiffness : jm.stiffness,
  9320. relaxation : jm.relaxation,
  9321. frictionStiffness : jm.frictionStiffness,
  9322. frictionRelaxation : jm.frictionRelaxation,
  9323. });
  9324. cm.id = jm.id;
  9325. w.defaultContactMaterial = cm;
  9326. // DistanceConstraint
  9327. for(var i=0; i<json.distanceConstraints.length; i++){
  9328. var c = json.distanceConstraints[i];
  9329. w.addConstraint(new DistanceConstraint( bodies[c.bodyA], bodies[c.bodyB], c.distance, {
  9330. maxForce:c.maxForce,
  9331. collideConnected:c.collideConnected
  9332. }));
  9333. }
  9334. // RevoluteConstraint
  9335. for(var i=0; i<json.revoluteConstraints.length; i++){
  9336. var c = json.revoluteConstraints[i];
  9337. var revolute = new RevoluteConstraint(bodies[c.bodyA], c.pivotA, bodies[c.bodyB], c.pivotB, {
  9338. maxForce: c.maxForce,
  9339. collideConnected: c.collideConnected
  9340. });
  9341. if(c.motorEnabled){
  9342. revolute.enableMotor();
  9343. }
  9344. revolute.setMotorSpeed(c.motorSpeed);
  9345. revolute.lowerLimit = c.lowerLimit;
  9346. revolute.upperLimit = c.upperLimit;
  9347. revolute.lowerLimitEnabled = c.lowerLimitEnabled;
  9348. revolute.upperLimitEnabled = c.upperLimitEnabled;
  9349. w.addConstraint(revolute);
  9350. }
  9351. // PrismaticConstraint
  9352. for(var i=0; i<json.prismaticConstraints.length; i++){
  9353. var c = json.prismaticConstraints[i],
  9354. p = new PrismaticConstraint(bodies[c.bodyA], bodies[c.bodyB], {
  9355. maxForce : c.maxForce,
  9356. localAxisA : c.localAxisA,
  9357. localAnchorA : c.localAnchorA,
  9358. localAnchorB : c.localAnchorB,
  9359. collideConnected: c.collideConnected
  9360. });
  9361. p.motorSpeed = c.motorSpeed;
  9362. w.addConstraint(p);
  9363. }
  9364. // LockConstraint
  9365. for(var i=0; i<json.lockConstraints.length; i++){
  9366. var c = json.lockConstraints[i];
  9367. w.addConstraint(new LockConstraint(bodies[c.bodyA], bodies[c.bodyB], {
  9368. maxForce : c.maxForce,
  9369. localOffsetB : c.localOffsetB,
  9370. localAngleB : c.localAngleB,
  9371. collideConnected: c.collideConnected
  9372. }));
  9373. }
  9374. // GearConstraint
  9375. for(var i=0; i<json.gearConstraints.length; i++){
  9376. var c = json.gearConstraints[i];
  9377. w.addConstraint(new GearConstraint(bodies[c.bodyA], bodies[c.bodyB], {
  9378. maxForce : c.maxForce,
  9379. angle : c.angle,
  9380. ratio : c.ratio,
  9381. collideConnected: c.collideConnected
  9382. }));
  9383. }
  9384. return true;
  9385. };
  9386. /**
  9387. * Resets the World, removes all bodies, constraints and springs.
  9388. *
  9389. * @method clear
  9390. */
  9391. World.prototype.clear = function(){
  9392. this.time = 0;
  9393. this.fixedStepTime = 0;
  9394. // Remove all solver equations
  9395. if(this.solver && this.solver.equations.length){
  9396. this.solver.removeAllEquations();
  9397. }
  9398. // Remove all constraints
  9399. var cs = this.constraints;
  9400. for(var i=cs.length-1; i>=0; i--){
  9401. this.removeConstraint(cs[i]);
  9402. }
  9403. // Remove all bodies
  9404. var bodies = this.bodies;
  9405. for(var i=bodies.length-1; i>=0; i--){
  9406. this.removeBody(bodies[i]);
  9407. }
  9408. // Remove all springs
  9409. var springs = this.springs;
  9410. for(var i=springs.length-1; i>=0; i--){
  9411. this.removeSpring(springs[i]);
  9412. }
  9413. // Remove all contact materials
  9414. var cms = this.contactMaterials;
  9415. for(var i=cms.length-1; i>=0; i--){
  9416. this.removeContactMaterial(cms[i]);
  9417. }
  9418. World.apply(this);
  9419. };
  9420. /**
  9421. * Get a copy of this World instance
  9422. * @method clone
  9423. * @return {World}
  9424. */
  9425. World.prototype.clone = function(){
  9426. var world = new World();
  9427. world.fromJSON(this.toJSON());
  9428. return world;
  9429. };
  9430. var hitTest_tmp1 = vec2.create(),
  9431. hitTest_zero = vec2.fromValues(0,0),
  9432. hitTest_tmp2 = vec2.fromValues(0,0);
  9433. /**
  9434. * Test if a world point overlaps bodies
  9435. * @method hitTest
  9436. * @param {Array} worldPoint Point to use for intersection tests
  9437. * @param {Array} bodies A list of objects to check for intersection
  9438. * @param {Number} precision Used for matching against particles and lines. Adds some margin to these infinitesimal objects.
  9439. * @return {Array} Array of bodies that overlap the point
  9440. */
  9441. World.prototype.hitTest = function(worldPoint,bodies,precision){
  9442. precision = precision || 0;
  9443. // Create a dummy particle body with a particle shape to test against the bodies
  9444. var pb = new Body({ position:worldPoint }),
  9445. ps = new Particle(),
  9446. px = worldPoint,
  9447. pa = 0,
  9448. x = hitTest_tmp1,
  9449. zero = hitTest_zero,
  9450. tmp = hitTest_tmp2;
  9451. pb.addShape(ps);
  9452. var n = this.narrowphase,
  9453. result = [];
  9454. // Check bodies
  9455. for(var i=0, N=bodies.length; i!==N; i++){
  9456. var b = bodies[i];
  9457. for(var j=0, NS=b.shapes.length; j!==NS; j++){
  9458. var s = b.shapes[j],
  9459. offset = b.shapeOffsets[j] || zero,
  9460. angle = b.shapeAngles[j] || 0.0;
  9461. // Get shape world position + angle
  9462. vec2.rotate(x, offset, b.angle);
  9463. vec2.add(x, x, b.position);
  9464. var a = angle + b.angle;
  9465. if( (s instanceof Circle && n.circleParticle (b,s,x,a, pb,ps,px,pa, true)) ||
  9466. (s instanceof Convex && n.particleConvex (pb,ps,px,pa, b,s,x,a, true)) ||
  9467. (s instanceof Plane && n.particlePlane (pb,ps,px,pa, b,s,x,a, true)) ||
  9468. (s instanceof Capsule && n.particleCapsule (pb,ps,px,pa, b,s,x,a, true)) ||
  9469. (s instanceof Particle && vec2.squaredLength(vec2.sub(tmp,x,worldPoint)) < precision*precision)
  9470. ){
  9471. result.push(b);
  9472. }
  9473. }
  9474. }
  9475. return result;
  9476. };
  9477. /**
  9478. * Sets the Equation parameters for all constraints and contact materials.
  9479. * @method setGlobalEquationParameters
  9480. * @param {object} [parameters]
  9481. * @param {Number} [parameters.relaxation]
  9482. * @param {Number} [parameters.stiffness]
  9483. */
  9484. World.prototype.setGlobalEquationParameters = function(parameters){
  9485. parameters = parameters || {};
  9486. // Set for all constraints
  9487. for(var i=0; i !== this.constraints.length; i++){
  9488. var c = this.constraints[i];
  9489. for(var j=0; j !== c.equations.length; j++){
  9490. var eq = c.equations[j];
  9491. if(typeof(parameters.stiffness) !== "undefined"){
  9492. eq.stiffness = parameters.stiffness;
  9493. }
  9494. if(typeof(parameters.relaxation) !== "undefined"){
  9495. eq.relaxation = parameters.relaxation;
  9496. }
  9497. eq.needsUpdate = true;
  9498. }
  9499. }
  9500. // Set for all contact materials
  9501. for(var i=0; i !== this.contactMaterials.length; i++){
  9502. var c = this.contactMaterials[i];
  9503. if(typeof(parameters.stiffness) !== "undefined"){
  9504. c.stiffness = parameters.stiffness;
  9505. c.frictionStiffness = parameters.stiffness;
  9506. }
  9507. if(typeof(parameters.relaxation) !== "undefined"){
  9508. c.relaxation = parameters.relaxation;
  9509. c.frictionRelaxation = parameters.relaxation;
  9510. }
  9511. }
  9512. // Set for default contact material
  9513. var c = this.defaultContactMaterial;
  9514. if(typeof(parameters.stiffness) !== "undefined"){
  9515. c.stiffness = parameters.stiffness;
  9516. c.frictionStiffness = parameters.stiffness;
  9517. }
  9518. if(typeof(parameters.relaxation) !== "undefined"){
  9519. c.relaxation = parameters.relaxation;
  9520. c.frictionRelaxation = parameters.relaxation;
  9521. }
  9522. };
  9523. /**
  9524. * Set the stiffness for all equations and contact materials.
  9525. * @method setGlobalStiffness
  9526. * @param {Number} stiffness
  9527. */
  9528. World.prototype.setGlobalStiffness = function(stiffness){
  9529. this.setGlobalEquationParameters({
  9530. stiffness: stiffness
  9531. });
  9532. };
  9533. /**
  9534. * Set the relaxation for all equations and contact materials.
  9535. * @method setGlobalRelaxation
  9536. * @param {Number} relaxation
  9537. */
  9538. World.prototype.setGlobalRelaxation = function(relaxation){
  9539. this.setGlobalEquationParameters({
  9540. relaxation: relaxation
  9541. });
  9542. };
  9543. },{"../../package.json":7,"../collision/Broadphase":9,"../collision/NaiveBroadphase":11,"../collision/Narrowphase":12,"../collision/SAPBroadphase":13,"../constraints/Constraint":14,"../constraints/DistanceConstraint":15,"../constraints/GearConstraint":16,"../constraints/LockConstraint":17,"../constraints/PrismaticConstraint":18,"../constraints/RevoluteConstraint":19,"../events/EventEmitter":26,"../material/ContactMaterial":27,"../material/Material":28,"../math/vec2":30,"../objects/Body":31,"../objects/Spring":32,"../shapes/Capsule":34,"../shapes/Circle":35,"../shapes/Convex":36,"../shapes/Line":38,"../shapes/Particle":39,"../shapes/Plane":40,"../shapes/Rectangle":41,"../shapes/Shape":42,"../solver/GSSolver":43,"../solver/Solver":44,"../utils/Utils":45,"./IslandManager":47}]},{},[33])
  9544. (33)
  9545. });
  9546. ;;
  9547. /**
  9548. * @author Richard Davey <rich@photonstorm.com>
  9549. * @copyright 2014 Photon Storm Ltd.
  9550. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  9551. */
  9552. // Add an extra properties to p2 that we need
  9553. p2.Body.prototype.parent = null;
  9554. p2.Spring.prototype.parent = null;
  9555. /**
  9556. * @class Phaser.Physics.P2
  9557. * @classdesc Physics World Constructor
  9558. * @constructor
  9559. * @param {Phaser.Game} game - Reference to the current game instance.
  9560. * @param {object} [config] - Physics configuration object passed in from the game constructor.
  9561. */
  9562. Phaser.Physics.P2 = function (game, config) {
  9563. /**
  9564. * @property {Phaser.Game} game - Local reference to game.
  9565. */
  9566. this.game = game;
  9567. if (typeof config === 'undefined' || !config.hasOwnProperty('gravity') || !config.hasOwnProperty('broadphase'))
  9568. {
  9569. config = { gravity: [0, 0], broadphase: new p2.SAPBroadphase() };
  9570. }
  9571. /**
  9572. * @property {p2.World} world - The p2 World in which the simulation is run.
  9573. * @protected
  9574. */
  9575. this.world = new p2.World(config);
  9576. /**
  9577. * @property {number} frameRate - The frame rate the world will be stepped at. Defaults to 1 / 60, but you can change here. Also see useElapsedTime property.
  9578. * @default
  9579. */
  9580. this.frameRate = 1 / 60;
  9581. /**
  9582. * @property {boolean} useElapsedTime - If true the frameRate value will be ignored and instead p2 will step with the value of Game.Time.physicsElapsed, which is a delta time value.
  9583. * @default
  9584. */
  9585. this.useElapsedTime = false;
  9586. /**
  9587. * @property {array<Phaser.Physics.P2.Material>} materials - A local array of all created Materials.
  9588. * @protected
  9589. */
  9590. this.materials = [];
  9591. /**
  9592. * @property {Phaser.Physics.P2.InversePointProxy} gravity - The gravity applied to all bodies each step.
  9593. */
  9594. this.gravity = new Phaser.Physics.P2.InversePointProxy(this, this.world.gravity);
  9595. /**
  9596. * @property {object} walls - An object containing the 4 wall bodies that bound the physics world.
  9597. */
  9598. this.walls = { left: null, right: null, top: null, bottom: null };
  9599. /**
  9600. * @property {Phaser.Signal} onBodyAdded - Dispatched when a new Body is added to the World.
  9601. */
  9602. this.onBodyAdded = new Phaser.Signal();
  9603. /**
  9604. * @property {Phaser.Signal} onBodyRemoved - Dispatched when a Body is removed from the World.
  9605. */
  9606. this.onBodyRemoved = new Phaser.Signal();
  9607. /**
  9608. * @property {Phaser.Signal} onSpringAdded - Dispatched when a new Spring is added to the World.
  9609. */
  9610. this.onSpringAdded = new Phaser.Signal();
  9611. /**
  9612. * @property {Phaser.Signal} onSpringRemoved - Dispatched when a Spring is removed from the World.
  9613. */
  9614. this.onSpringRemoved = new Phaser.Signal();
  9615. /**
  9616. * @property {Phaser.Signal} onConstraintAdded - Dispatched when a new Constraint is added to the World.
  9617. */
  9618. this.onConstraintAdded = new Phaser.Signal();
  9619. /**
  9620. * @property {Phaser.Signal} onConstraintRemoved - Dispatched when a Constraint is removed from the World.
  9621. */
  9622. this.onConstraintRemoved = new Phaser.Signal();
  9623. /**
  9624. * @property {Phaser.Signal} onContactMaterialAdded - Dispatched when a new ContactMaterial is added to the World.
  9625. */
  9626. this.onContactMaterialAdded = new Phaser.Signal();
  9627. /**
  9628. * @property {Phaser.Signal} onContactMaterialRemoved - Dispatched when a ContactMaterial is removed from the World.
  9629. */
  9630. this.onContactMaterialRemoved = new Phaser.Signal();
  9631. /**
  9632. * @property {function} postBroadphaseCallback - A postBroadphase callback.
  9633. */
  9634. this.postBroadphaseCallback = null;
  9635. /**
  9636. * @property {object} callbackContext - The context under which the callbacks are fired.
  9637. */
  9638. this.callbackContext = null;
  9639. /**
  9640. * @property {Phaser.Signal} onBeginContact - Dispatched when a first contact is created between two bodies. This event is fired before the step has been done.
  9641. */
  9642. this.onBeginContact = new Phaser.Signal();
  9643. /**
  9644. * @property {Phaser.Signal} onEndContact - Dispatched when final contact occurs between two bodies. This event is fired before the step has been done.
  9645. */
  9646. this.onEndContact = new Phaser.Signal();
  9647. // Pixel to meter function overrides
  9648. if (config.hasOwnProperty('mpx') && config.hasOwnProperty('pxm') && config.hasOwnProperty('mpxi') && config.hasOwnProperty('pxmi'))
  9649. {
  9650. this.mpx = config.mpx;
  9651. this.mpxi = config.mpxi;
  9652. this.pxm = config.pxm;
  9653. this.pxmi = config.pxmi;
  9654. }
  9655. // Hook into the World events
  9656. this.world.on("beginContact", this.beginContactHandler, this);
  9657. this.world.on("endContact", this.endContactHandler, this);
  9658. /**
  9659. * @property {array} collisionGroups - An array containing the collision groups that have been defined in the World.
  9660. */
  9661. this.collisionGroups = [];
  9662. /**
  9663. * @property {Phaser.Physics.P2.CollisionGroup} nothingCollisionGroup - A default collision group.
  9664. */
  9665. this.nothingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(1);
  9666. /**
  9667. * @property {Phaser.Physics.P2.CollisionGroup} boundsCollisionGroup - A default collision group.
  9668. */
  9669. this.boundsCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2);
  9670. /**
  9671. * @property {Phaser.Physics.P2.CollisionGroup} everythingCollisionGroup - A default collision group.
  9672. */
  9673. this.everythingCollisionGroup = new Phaser.Physics.P2.CollisionGroup(2147483648);
  9674. /**
  9675. * @property {array} boundsCollidesWith - An array of the bodies the world bounds collides with.
  9676. */
  9677. this.boundsCollidesWith = [];
  9678. /**
  9679. * @property {array} _toRemove - Internal var used to hold references to bodies to remove from the world on the next step.
  9680. * @private
  9681. */
  9682. this._toRemove = [];
  9683. /**
  9684. * @property {number} _collisionGroupID - Internal var.
  9685. * @private
  9686. */
  9687. this._collisionGroupID = 2;
  9688. // By default we want everything colliding with everything
  9689. this.setBoundsToWorld(true, true, true, true, false);
  9690. };
  9691. Phaser.Physics.P2.prototype = {
  9692. /**
  9693. * This will add a P2 Physics body into the removal list for the next step.
  9694. *
  9695. * @method Phaser.Physics.P2#removeBodyNextStep
  9696. * @param {Phaser.Physics.P2.Body} body - The body to remove at the start of the next step.
  9697. */
  9698. removeBodyNextStep: function (body) {
  9699. this._toRemove.push(body);
  9700. },
  9701. /**
  9702. * Called at the start of the core update loop. Purges flagged bodies from the world.
  9703. *
  9704. * @method Phaser.Physics.P2#preUpdate
  9705. */
  9706. preUpdate: function () {
  9707. var i = this._toRemove.length;
  9708. while (i--)
  9709. {
  9710. this.removeBody(this._toRemove[i]);
  9711. }
  9712. this._toRemove.length = 0;
  9713. },
  9714. /**
  9715. * This will create a P2 Physics body on the given game object or array of game objects.
  9716. * A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
  9717. *
  9718. * @method Phaser.Physics.P2#enable
  9719. * @param {object|array|Phaser.Group} object - The game object to create the physics body on. Can also be an array or Group of objects, a body will be created on every child that has a `body` property.
  9720. * @param {boolean} [debug=false] - Create a debug object to go with this body?
  9721. * @param {boolean} [children=true] - Should a body be created on all children of this object? If true it will recurse down the display list as far as it can go.
  9722. */
  9723. enable: function (object, debug, children) {
  9724. if (typeof debug === 'undefined') { debug = false; }
  9725. if (typeof children === 'undefined') { children = true; }
  9726. var i = 1;
  9727. if (Array.isArray(object))
  9728. {
  9729. i = object.length;
  9730. while (i--)
  9731. {
  9732. if (object[i] instanceof Phaser.Group)
  9733. {
  9734. // If it's a Group then we do it on the children regardless
  9735. this.enable(object[i].children, debug, children);
  9736. }
  9737. else
  9738. {
  9739. this.enableBody(object[i], debug);
  9740. if (children && object[i].hasOwnProperty('children') && object[i].children.length > 0)
  9741. {
  9742. this.enable(object[i], debug, true);
  9743. }
  9744. }
  9745. }
  9746. }
  9747. else
  9748. {
  9749. if (object instanceof Phaser.Group)
  9750. {
  9751. // If it's a Group then we do it on the children regardless
  9752. this.enable(object.children, debug, children);
  9753. }
  9754. else
  9755. {
  9756. this.enableBody(object, debug);
  9757. if (children && object.hasOwnProperty('children') && object.children.length > 0)
  9758. {
  9759. this.enable(object.children, debug, true);
  9760. }
  9761. }
  9762. }
  9763. },
  9764. /**
  9765. * Creates a P2 Physics body on the given game object.
  9766. * A game object can only have 1 physics body active at any one time, and it can't be changed until the body is nulled.
  9767. *
  9768. * @method Phaser.Physics.P2#enableBody
  9769. * @param {object} object - The game object to create the physics body on. A body will only be created if this object has a null `body` property.
  9770. * @param {boolean} debug - Create a debug object to go with this body?
  9771. */
  9772. enableBody: function (object, debug) {
  9773. if (object.hasOwnProperty('body') && object.body === null)
  9774. {
  9775. object.body = new Phaser.Physics.P2.Body(this.game, object, object.x, object.y, 1);
  9776. object.body.debug = debug;
  9777. object.anchor.set(0.5);
  9778. }
  9779. },
  9780. /**
  9781. * Impact event handling is disabled by default. Enable it before any impact events will be dispatched.
  9782. * In a busy world hundreds of impact events can be generated every step, so only enable this if you cannot do what you need via beginContact or collision masks.
  9783. *
  9784. * @method Phaser.Physics.P2#setImpactEvents
  9785. * @param {boolean} state - Set to true to enable impact events, or false to disable.
  9786. */
  9787. setImpactEvents: function (state) {
  9788. if (state)
  9789. {
  9790. this.world.on("impact", this.impactHandler, this);
  9791. }
  9792. else
  9793. {
  9794. this.world.off("impact", this.impactHandler, this);
  9795. }
  9796. },
  9797. /**
  9798. * Sets a callback to be fired after the Broadphase has collected collision pairs in the world.
  9799. * Just because a pair exists it doesn't mean they *will* collide, just that they potentially could do.
  9800. * If your calback returns `false` the pair will be removed from the narrowphase. This will stop them testing for collision this step.
  9801. * Returning `true` from the callback will ensure they are checked in the narrowphase.
  9802. *
  9803. * @method Phaser.Physics.P2#setPostBroadphaseCallback
  9804. * @param {function} callback - The callback that will receive the postBroadphase event data. It must return a boolean. Set to null to disable an existing callback.
  9805. * @param {object} context - The context under which the callback will be fired.
  9806. */
  9807. setPostBroadphaseCallback: function (callback, context) {
  9808. this.postBroadphaseCallback = callback;
  9809. this.callbackContext = context;
  9810. if (callback !== null)
  9811. {
  9812. this.world.on("postBroadphase", this.postBroadphaseHandler, this);
  9813. }
  9814. else
  9815. {
  9816. this.world.off("postBroadphase", this.postBroadphaseHandler, this);
  9817. }
  9818. },
  9819. /**
  9820. * Internal handler for the postBroadphase event.
  9821. *
  9822. * @method Phaser.Physics.P2#postBroadphaseHandler
  9823. * @private
  9824. * @param {object} event - The event data.
  9825. */
  9826. postBroadphaseHandler: function (event) {
  9827. if (this.postBroadphaseCallback)
  9828. {
  9829. var i = event.pairs.length;
  9830. while (i -= 2)
  9831. {
  9832. if (event.pairs[i].parent && event.pairs[i+1].parent && !this.postBroadphaseCallback.call(this.callbackContext, event.pairs[i].parent, event.pairs[i+1].parent))
  9833. {
  9834. event.pairs.splice(i, 2);
  9835. }
  9836. }
  9837. }
  9838. },
  9839. /**
  9840. * Handles a p2 impact event.
  9841. *
  9842. * @method Phaser.Physics.P2#impactHandler
  9843. * @private
  9844. * @param {object} event - The event data.
  9845. */
  9846. impactHandler: function (event) {
  9847. if (event.bodyA.parent && event.bodyB.parent)
  9848. {
  9849. // Body vs. Body callbacks
  9850. var a = event.bodyA.parent;
  9851. var b = event.bodyB.parent;
  9852. if (a._bodyCallbacks[event.bodyB.id])
  9853. {
  9854. a._bodyCallbacks[event.bodyB.id].call(a._bodyCallbackContext[event.bodyB.id], a, b, event.shapeA, event.shapeB);
  9855. }
  9856. if (b._bodyCallbacks[event.bodyA.id])
  9857. {
  9858. b._bodyCallbacks[event.bodyA.id].call(b._bodyCallbackContext[event.bodyA.id], b, a, event.shapeB, event.shapeA);
  9859. }
  9860. // Body vs. Group callbacks
  9861. if (a._groupCallbacks[event.shapeB.collisionGroup])
  9862. {
  9863. a._groupCallbacks[event.shapeB.collisionGroup].call(a._groupCallbackContext[event.shapeB.collisionGroup], a, b, event.shapeA, event.shapeB);
  9864. }
  9865. if (b._groupCallbacks[event.shapeA.collisionGroup])
  9866. {
  9867. b._groupCallbacks[event.shapeA.collisionGroup].call(b._groupCallbackContext[event.shapeA.collisionGroup], b, a, event.shapeB, event.shapeA);
  9868. }
  9869. }
  9870. },
  9871. /**
  9872. * Handles a p2 begin contact event.
  9873. *
  9874. * @method Phaser.Physics.P2#beginContactHandler
  9875. * @param {object} event - The event data.
  9876. */
  9877. beginContactHandler: function (event) {
  9878. this.onBeginContact.dispatch(event.bodyA, event.bodyB, event.shapeA, event.shapeB, event.contactEquations);
  9879. if (event.bodyA.parent)
  9880. {
  9881. event.bodyA.parent.onBeginContact.dispatch(event.bodyB.parent, event.shapeA, event.shapeB, event.contactEquations);
  9882. }
  9883. if (event.bodyB.parent)
  9884. {
  9885. event.bodyB.parent.onBeginContact.dispatch(event.bodyA.parent, event.shapeB, event.shapeA, event.contactEquations);
  9886. }
  9887. },
  9888. /**
  9889. * Handles a p2 end contact event.
  9890. *
  9891. * @method Phaser.Physics.P2#endContactHandler
  9892. * @param {object} event - The event data.
  9893. */
  9894. endContactHandler: function (event) {
  9895. this.onEndContact.dispatch(event.bodyA, event.bodyB, event.shapeA, event.shapeB);
  9896. if (event.bodyA.parent)
  9897. {
  9898. event.bodyA.parent.onEndContact.dispatch(event.bodyB.parent, event.shapeA, event.shapeB);
  9899. }
  9900. if (event.bodyB.parent)
  9901. {
  9902. event.bodyB.parent.onEndContact.dispatch(event.bodyA.parent, event.shapeB, event.shapeA);
  9903. }
  9904. },
  9905. /**
  9906. * Sets the bounds of the Physics world to match the Game.World dimensions.
  9907. * You can optionally set which 'walls' to create: left, right, top or bottom.
  9908. *
  9909. * @method Phaser.Physics#setBoundsToWorld
  9910. * @param {boolean} [left=true] - If true will create the left bounds wall.
  9911. * @param {boolean} [right=true] - If true will create the right bounds wall.
  9912. * @param {boolean} [top=true] - If true will create the top bounds wall.
  9913. * @param {boolean} [bottom=true] - If true will create the bottom bounds wall.
  9914. * @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
  9915. */
  9916. setBoundsToWorld: function (left, right, top, bottom, setCollisionGroup) {
  9917. this.setBounds(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, left, right, top, bottom, setCollisionGroup);
  9918. },
  9919. /**
  9920. * Sets the given material against the 4 bounds of this World.
  9921. *
  9922. * @method Phaser.Physics#setWorldMaterial
  9923. * @param {Phaser.Physics.P2.Material} material - The material to set.
  9924. * @param {boolean} [left=true] - If true will set the material on the left bounds wall.
  9925. * @param {boolean} [right=true] - If true will set the material on the right bounds wall.
  9926. * @param {boolean} [top=true] - If true will set the material on the top bounds wall.
  9927. * @param {boolean} [bottom=true] - If true will set the material on the bottom bounds wall.
  9928. */
  9929. setWorldMaterial: function (material, left, right, top, bottom) {
  9930. if (typeof left === 'undefined') { left = true; }
  9931. if (typeof right === 'undefined') { right = true; }
  9932. if (typeof top === 'undefined') { top = true; }
  9933. if (typeof bottom === 'undefined') { bottom = true; }
  9934. if (left && this.walls.left)
  9935. {
  9936. this.walls.left.shapes[0].material = material;
  9937. }
  9938. if (right && this.walls.right)
  9939. {
  9940. this.walls.right.shapes[0].material = material;
  9941. }
  9942. if (top && this.walls.top)
  9943. {
  9944. this.walls.top.shapes[0].material = material;
  9945. }
  9946. if (bottom && this.walls.bottom)
  9947. {
  9948. this.walls.bottom.shapes[0].material = material;
  9949. }
  9950. },
  9951. /**
  9952. * By default the World will be set to collide everything with everything. The bounds of the world is a Body with 4 shapes, one for each face.
  9953. * If you start to use your own collision groups then your objects will no longer collide with the bounds.
  9954. * To fix this you need to adjust the bounds to use its own collision group first BEFORE changing your Sprites collision group.
  9955. *
  9956. * @method Phaser.Physics.P2#updateBoundsCollisionGroup
  9957. * @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
  9958. */
  9959. updateBoundsCollisionGroup: function (setCollisionGroup) {
  9960. var mask = this.everythingCollisionGroup.mask;
  9961. if (typeof setCollisionGroup === 'undefined') { mask = this.boundsCollisionGroup.mask; }
  9962. if (this.walls.left)
  9963. {
  9964. this.walls.left.shapes[0].collisionGroup = mask;
  9965. }
  9966. if (this.walls.right)
  9967. {
  9968. this.walls.right.shapes[0].collisionGroup = mask;
  9969. }
  9970. if (this.walls.top)
  9971. {
  9972. this.walls.top.shapes[0].collisionGroup = mask;
  9973. }
  9974. if (this.walls.bottom)
  9975. {
  9976. this.walls.bottom.shapes[0].collisionGroup = mask;
  9977. }
  9978. },
  9979. /**
  9980. * Sets the bounds of the Physics world to match the given world pixel dimensions.
  9981. * You can optionally set which 'walls' to create: left, right, top or bottom.
  9982. *
  9983. * @method Phaser.Physics.P2#setBounds
  9984. * @param {number} x - The x coordinate of the top-left corner of the bounds.
  9985. * @param {number} y - The y coordinate of the top-left corner of the bounds.
  9986. * @param {number} width - The width of the bounds.
  9987. * @param {number} height - The height of the bounds.
  9988. * @param {boolean} [left=true] - If true will create the left bounds wall.
  9989. * @param {boolean} [right=true] - If true will create the right bounds wall.
  9990. * @param {boolean} [top=true] - If true will create the top bounds wall.
  9991. * @param {boolean} [bottom=true] - If true will create the bottom bounds wall.
  9992. * @param {boolean} [setCollisionGroup=true] - If true the Bounds will be set to use its own Collision Group.
  9993. */
  9994. setBounds: function (x, y, width, height, left, right, top, bottom, setCollisionGroup) {
  9995. if (typeof left === 'undefined') { left = true; }
  9996. if (typeof right === 'undefined') { right = true; }
  9997. if (typeof top === 'undefined') { top = true; }
  9998. if (typeof bottom === 'undefined') { bottom = true; }
  9999. if (typeof setCollisionGroup === 'undefined') { setCollisionGroup = true; }
  10000. if (this.walls.left)
  10001. {
  10002. this.world.removeBody(this.walls.left);
  10003. }
  10004. if (this.walls.right)
  10005. {
  10006. this.world.removeBody(this.walls.right);
  10007. }
  10008. if (this.walls.top)
  10009. {
  10010. this.world.removeBody(this.walls.top);
  10011. }
  10012. if (this.walls.bottom)
  10013. {
  10014. this.world.removeBody(this.walls.bottom);
  10015. }
  10016. if (left)
  10017. {
  10018. this.walls.left = new p2.Body({ mass: 0, position: [ this.pxmi(x), this.pxmi(y) ], angle: 1.5707963267948966 });
  10019. this.walls.left.addShape(new p2.Plane());
  10020. if (setCollisionGroup)
  10021. {
  10022. this.walls.left.shapes[0].collisionGroup = this.boundsCollisionGroup.mask;
  10023. }
  10024. this.world.addBody(this.walls.left);
  10025. }
  10026. if (right)
  10027. {
  10028. this.walls.right = new p2.Body({ mass: 0, position: [ this.pxmi(x + width), this.pxmi(y) ], angle: -1.5707963267948966 });
  10029. this.walls.right.addShape(new p2.Plane());
  10030. if (setCollisionGroup)
  10031. {
  10032. this.walls.right.shapes[0].collisionGroup = this.boundsCollisionGroup.mask;
  10033. }
  10034. this.world.addBody(this.walls.right);
  10035. }
  10036. if (top)
  10037. {
  10038. this.walls.top = new p2.Body({ mass: 0, position: [ this.pxmi(x), this.pxmi(y) ], angle: -3.141592653589793 });
  10039. this.walls.top.addShape(new p2.Plane());
  10040. if (setCollisionGroup)
  10041. {
  10042. this.walls.top.shapes[0].collisionGroup = this.boundsCollisionGroup.mask;
  10043. }
  10044. this.world.addBody(this.walls.top);
  10045. }
  10046. if (bottom)
  10047. {
  10048. this.walls.bottom = new p2.Body({ mass: 0, position: [ this.pxmi(x), this.pxmi(height) ] });
  10049. this.walls.bottom.addShape(new p2.Plane());
  10050. if (setCollisionGroup)
  10051. {
  10052. this.walls.bottom.shapes[0].collisionGroup = this.boundsCollisionGroup.mask;
  10053. }
  10054. this.world.addBody(this.walls.bottom);
  10055. }
  10056. },
  10057. /**
  10058. * @method Phaser.Physics.P2#update
  10059. */
  10060. update: function () {
  10061. if (this.useElapsedTime)
  10062. {
  10063. this.world.step(this.game.time.physicsElapsed);
  10064. }
  10065. else
  10066. {
  10067. this.world.step(this.frameRate);
  10068. }
  10069. },
  10070. /**
  10071. * Clears all bodies from the simulation, resets callbacks and resets the collision bitmask.
  10072. *
  10073. * @method Phaser.Physics.P2#clear
  10074. */
  10075. clear: function () {
  10076. this.world.clear();
  10077. this.world.off("beginContact", this.beginContactHandler, this);
  10078. this.world.off("endContact", this.endContactHandler, this);
  10079. this.postBroadphaseCallback = null;
  10080. this.callbackContext = null;
  10081. this.impactCallback = null;
  10082. this.collisionGroups = [];
  10083. this._toRemove = [];
  10084. this._collisionGroupID = 2;
  10085. this.boundsCollidesWith = [];
  10086. },
  10087. /**
  10088. * Clears all bodies from the simulation and unlinks World from Game. Should only be called on game shutdown. Call `clear` on a State change.
  10089. *
  10090. * @method Phaser.Physics.P2#destroy
  10091. */
  10092. destroy: function () {
  10093. this.clear();
  10094. this.game = null;
  10095. },
  10096. /**
  10097. * Add a body to the world.
  10098. *
  10099. * @method Phaser.Physics.P2#addBody
  10100. * @param {Phaser.Physics.P2.Body} body - The Body to add to the World.
  10101. * @return {boolean} True if the Body was added successfully, otherwise false.
  10102. */
  10103. addBody: function (body) {
  10104. if (body.data.world)
  10105. {
  10106. return false;
  10107. }
  10108. else
  10109. {
  10110. this.world.addBody(body.data);
  10111. this.onBodyAdded.dispatch(body);
  10112. return true;
  10113. }
  10114. },
  10115. /**
  10116. * Removes a body from the world. This will silently fail if the body wasn't part of the world to begin with.
  10117. *
  10118. * @method Phaser.Physics.P2#removeBody
  10119. * @param {Phaser.Physics.P2.Body} body - The Body to remove from the World.
  10120. * @return {Phaser.Physics.P2.Body} The Body that was removed.
  10121. */
  10122. removeBody: function (body) {
  10123. if (body.data.world == this.world)
  10124. {
  10125. this.world.removeBody(body.data);
  10126. this.onBodyRemoved.dispatch(body);
  10127. }
  10128. return body;
  10129. },
  10130. /**
  10131. * Adds a Spring to the world.
  10132. *
  10133. * @method Phaser.Physics.P2#addSpring
  10134. * @param {Phaser.Physics.P2.Spring} spring - The Spring to add to the World.
  10135. * @return {Phaser.Physics.P2.Spring} The Spring that was added.
  10136. */
  10137. addSpring: function (spring) {
  10138. this.world.addSpring(spring);
  10139. this.onSpringAdded.dispatch(spring);
  10140. return spring;
  10141. },
  10142. /**
  10143. * Removes a Spring from the world.
  10144. *
  10145. * @method Phaser.Physics.P2#removeSpring
  10146. * @param {Phaser.Physics.P2.Spring} spring - The Spring to remove from the World.
  10147. * @return {Phaser.Physics.P2.Spring} The Spring that was removed.
  10148. */
  10149. removeSpring: function (spring) {
  10150. this.world.removeSpring(spring);
  10151. this.onSpringRemoved.dispatch(spring);
  10152. return spring;
  10153. },
  10154. /**
  10155. * Creates a constraint that tries to keep the distance between two bodies constant.
  10156. *
  10157. * @method Phaser.Physics.P2#createDistanceConstraint
  10158. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  10159. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  10160. * @param {number} distance - The distance to keep between the bodies.
  10161. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  10162. * @return {Phaser.Physics.P2.DistanceConstraint} The constraint
  10163. */
  10164. createDistanceConstraint: function (bodyA, bodyB, distance, maxForce) {
  10165. bodyA = this.getBody(bodyA);
  10166. bodyB = this.getBody(bodyB);
  10167. if (!bodyA || !bodyB)
  10168. {
  10169. console.warn('Cannot create Constraint, invalid body objects given');
  10170. }
  10171. else
  10172. {
  10173. return this.addConstraint(new Phaser.Physics.P2.DistanceConstraint(this, bodyA, bodyB, distance, maxForce));
  10174. }
  10175. },
  10176. /**
  10177. * Creates a constraint that tries to keep the distance between two bodies constant.
  10178. *
  10179. * @method Phaser.Physics.P2#createGearConstraint
  10180. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  10181. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  10182. * @param {number} [angle=0] - The relative angle
  10183. * @param {number} [ratio=1] - The gear ratio.
  10184. * @return {Phaser.Physics.P2.GearConstraint} The constraint
  10185. */
  10186. createGearConstraint: function (bodyA, bodyB, angle, ratio) {
  10187. bodyA = this.getBody(bodyA);
  10188. bodyB = this.getBody(bodyB);
  10189. if (!bodyA || !bodyB)
  10190. {
  10191. console.warn('Cannot create Constraint, invalid body objects given');
  10192. }
  10193. else
  10194. {
  10195. return this.addConstraint(new Phaser.Physics.P2.GearConstraint(this, bodyA, bodyB, angle, ratio));
  10196. }
  10197. },
  10198. /**
  10199. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  10200. * The pivot points are given in world (pixel) coordinates.
  10201. *
  10202. * @method Phaser.Physics.P2#createRevoluteConstraint
  10203. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  10204. * @param {Array} pivotA - The point relative to the center of mass of bodyA which bodyA is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  10205. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  10206. * @param {Array} pivotB - The point relative to the center of mass of bodyB which bodyB is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  10207. * @param {number} [maxForce=0] - The maximum force that should be applied to constrain the bodies.
  10208. * @return {Phaser.Physics.P2.RevoluteConstraint} The constraint
  10209. */
  10210. createRevoluteConstraint: function (bodyA, pivotA, bodyB, pivotB, maxForce) {
  10211. bodyA = this.getBody(bodyA);
  10212. bodyB = this.getBody(bodyB);
  10213. if (!bodyA || !bodyB)
  10214. {
  10215. console.warn('Cannot create Constraint, invalid body objects given');
  10216. }
  10217. else
  10218. {
  10219. return this.addConstraint(new Phaser.Physics.P2.RevoluteConstraint(this, bodyA, pivotA, bodyB, pivotB, maxForce));
  10220. }
  10221. },
  10222. /**
  10223. * Locks the relative position between two bodies.
  10224. *
  10225. * @method Phaser.Physics.P2#createLockConstraint
  10226. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  10227. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  10228. * @param {Array} [offset] - The offset of bodyB in bodyA's frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  10229. * @param {number} [angle=0] - The angle of bodyB in bodyA's frame.
  10230. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  10231. * @return {Phaser.Physics.P2.LockConstraint} The constraint
  10232. */
  10233. createLockConstraint: function (bodyA, bodyB, offset, angle, maxForce) {
  10234. bodyA = this.getBody(bodyA);
  10235. bodyB = this.getBody(bodyB);
  10236. if (!bodyA || !bodyB)
  10237. {
  10238. console.warn('Cannot create Constraint, invalid body objects given');
  10239. }
  10240. else
  10241. {
  10242. return this.addConstraint(new Phaser.Physics.P2.LockConstraint(this, bodyA, bodyB, offset, angle, maxForce));
  10243. }
  10244. },
  10245. /**
  10246. * Constraint that only allows bodies to move along a line, relative to each other.
  10247. * See http://www.iforce2d.net/b2dtut/joints-prismatic
  10248. *
  10249. * @method Phaser.Physics.P2#createPrismaticConstraint
  10250. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  10251. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  10252. * @param {boolean} [lockRotation=true] - If set to false, bodyB will be free to rotate around its anchor point.
  10253. * @param {Array} [anchorA] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  10254. * @param {Array} [anchorB] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  10255. * @param {Array} [axis] - An axis, defined in body A frame, that body B's anchor point may slide along. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  10256. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  10257. * @return {Phaser.Physics.P2.PrismaticConstraint} The constraint
  10258. */
  10259. createPrismaticConstraint: function (bodyA, bodyB, lockRotation, anchorA, anchorB, axis, maxForce) {
  10260. bodyA = this.getBody(bodyA);
  10261. bodyB = this.getBody(bodyB);
  10262. if (!bodyA || !bodyB)
  10263. {
  10264. console.warn('Cannot create Constraint, invalid body objects given');
  10265. }
  10266. else
  10267. {
  10268. return this.addConstraint(new Phaser.Physics.P2.PrismaticConstraint(this, bodyA, bodyB, lockRotation, anchorA, anchorB, axis, maxForce));
  10269. }
  10270. },
  10271. /**
  10272. * Adds a Constraint to the world.
  10273. *
  10274. * @method Phaser.Physics.P2#addConstraint
  10275. * @param {Phaser.Physics.P2.Constraint} constraint - The Constraint to add to the World.
  10276. * @return {Phaser.Physics.P2.Constraint} The Constraint that was added.
  10277. */
  10278. addConstraint: function (constraint) {
  10279. this.world.addConstraint(constraint);
  10280. this.onConstraintAdded.dispatch(constraint);
  10281. return constraint;
  10282. },
  10283. /**
  10284. * Removes a Constraint from the world.
  10285. *
  10286. * @method Phaser.Physics.P2#removeConstraint
  10287. * @param {Phaser.Physics.P2.Constraint} constraint - The Constraint to be removed from the World.
  10288. * @return {Phaser.Physics.P2.Constraint} The Constraint that was removed.
  10289. */
  10290. removeConstraint: function (constraint) {
  10291. this.world.removeConstraint(constraint);
  10292. this.onConstraintRemoved.dispatch(constraint);
  10293. return constraint;
  10294. },
  10295. /**
  10296. * Adds a Contact Material to the world.
  10297. *
  10298. * @method Phaser.Physics.P2#addContactMaterial
  10299. * @param {Phaser.Physics.P2.ContactMaterial} material - The Contact Material to be added to the World.
  10300. * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was added.
  10301. */
  10302. addContactMaterial: function (material) {
  10303. this.world.addContactMaterial(material);
  10304. this.onContactMaterialAdded.dispatch(material);
  10305. return material;
  10306. },
  10307. /**
  10308. * Removes a Contact Material from the world.
  10309. *
  10310. * @method Phaser.Physics.P2#removeContactMaterial
  10311. * @param {Phaser.Physics.P2.ContactMaterial} material - The Contact Material to be removed from the World.
  10312. * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was removed.
  10313. */
  10314. removeContactMaterial: function (material) {
  10315. this.world.removeContactMaterial(material);
  10316. this.onContactMaterialRemoved.dispatch(material);
  10317. return material;
  10318. },
  10319. /**
  10320. * Gets a Contact Material based on the two given Materials.
  10321. *
  10322. * @method Phaser.Physics.P2#getContactMaterial
  10323. * @param {Phaser.Physics.P2.Material} materialA - The first Material to search for.
  10324. * @param {Phaser.Physics.P2.Material} materialB - The second Material to search for.
  10325. * @return {Phaser.Physics.P2.ContactMaterial|boolean} The Contact Material or false if none was found matching the Materials given.
  10326. */
  10327. getContactMaterial: function (materialA, materialB) {
  10328. return this.world.getContactMaterial(materialA, materialB);
  10329. },
  10330. /**
  10331. * Sets the given Material against all Shapes owned by all the Bodies in the given array.
  10332. *
  10333. * @method Phaser.Physics.P2#setMaterial
  10334. * @param {Phaser.Physics.P2.Material} material - The Material to be applied to the given Bodies.
  10335. * @param {array<Phaser.Physics.P2.Body>} bodies - An Array of Body objects that the given Material will be set on.
  10336. */
  10337. setMaterial: function (material, bodies) {
  10338. var i = bodies.length;
  10339. while (i--)
  10340. {
  10341. bodies.setMaterial(material);
  10342. }
  10343. },
  10344. /**
  10345. * Creates a Material. Materials are applied to Shapes owned by a Body and can be set with Body.setMaterial().
  10346. * Materials are a way to control what happens when Shapes collide. Combine unique Materials together to create Contact Materials.
  10347. * Contact Materials have properties such as friction and restitution that allow for fine-grained collision control between different Materials.
  10348. *
  10349. * @method Phaser.Physics.P2#createMaterial
  10350. * @param {string} [name] - Optional name of the Material. Each Material has a unique ID but string names are handy for debugging.
  10351. * @param {Phaser.Physics.P2.Body} [body] - Optional Body. If given it will assign the newly created Material to the Body shapes.
  10352. * @return {Phaser.Physics.P2.Material} The Material that was created. This is also stored in Phaser.Physics.P2.materials.
  10353. */
  10354. createMaterial: function (name, body) {
  10355. name = name || '';
  10356. var material = new Phaser.Physics.P2.Material(name);
  10357. this.materials.push(material);
  10358. if (typeof body !== 'undefined')
  10359. {
  10360. body.setMaterial(material);
  10361. }
  10362. return material;
  10363. },
  10364. /**
  10365. * Creates a Contact Material from the two given Materials. You can then edit the properties of the Contact Material directly.
  10366. *
  10367. * @method Phaser.Physics.P2#createContactMaterial
  10368. * @param {Phaser.Physics.P2.Material} [materialA] - The first Material to create the ContactMaterial from. If undefined it will create a new Material object first.
  10369. * @param {Phaser.Physics.P2.Material} [materialB] - The second Material to create the ContactMaterial from. If undefined it will create a new Material object first.
  10370. * @param {object} [options] - Material options object.
  10371. * @return {Phaser.Physics.P2.ContactMaterial} The Contact Material that was created.
  10372. */
  10373. createContactMaterial: function (materialA, materialB, options) {
  10374. if (typeof materialA === 'undefined') { materialA = this.createMaterial(); }
  10375. if (typeof materialB === 'undefined') { materialB = this.createMaterial(); }
  10376. var contact = new Phaser.Physics.P2.ContactMaterial(materialA, materialB, options);
  10377. return this.addContactMaterial(contact);
  10378. },
  10379. /**
  10380. * Populates and returns an array with references to of all current Bodies in the world.
  10381. *
  10382. * @method Phaser.Physics.P2#getBodies
  10383. * @return {array<Phaser.Physics.P2.Body>} An array containing all current Bodies in the world.
  10384. */
  10385. getBodies: function () {
  10386. var output = [];
  10387. var i = this.world.bodies.length;
  10388. while (i--)
  10389. {
  10390. output.push(this.world.bodies[i].parent);
  10391. }
  10392. return output;
  10393. },
  10394. /**
  10395. * Checks the given object to see if it has a p2.Body and if so returns it.
  10396. *
  10397. * @method Phaser.Physics.P2#getBody
  10398. * @param {object} object - The object to check for a p2.Body on.
  10399. * @return {p2.Body} The p2.Body, or null if not found.
  10400. */
  10401. getBody: function (object) {
  10402. if (object instanceof p2.Body)
  10403. {
  10404. // Native p2 body
  10405. return object;
  10406. }
  10407. else if (object instanceof Phaser.Physics.P2.Body)
  10408. {
  10409. // Phaser P2 Body
  10410. return object.data;
  10411. }
  10412. else if (object['body'] && object['body'].type === Phaser.Physics.P2JS)
  10413. {
  10414. // Sprite, TileSprite, etc
  10415. return object.body.data;
  10416. }
  10417. return null;
  10418. },
  10419. /**
  10420. * Populates and returns an array of all current Springs in the world.
  10421. *
  10422. * @method Phaser.Physics.P2#getSprings
  10423. * @return {array<Phaser.Physics.P2.Spring>} An array containing all current Springs in the world.
  10424. */
  10425. getSprings: function () {
  10426. var output = [];
  10427. var i = this.world.springs.length;
  10428. while (i--)
  10429. {
  10430. output.push(this.world.springs[i].parent);
  10431. }
  10432. return output;
  10433. },
  10434. /**
  10435. * Populates and returns an array of all current Constraints in the world.
  10436. *
  10437. * @method Phaser.Physics.P2#getConstraints
  10438. * @return {array<Phaser.Physics.P2.Constraint>} An array containing all current Constraints in the world.
  10439. */
  10440. getConstraints: function () {
  10441. var output = [];
  10442. var i = this.world.constraints.length;
  10443. while (i--)
  10444. {
  10445. output.push(this.world.constraints[i].parent);
  10446. }
  10447. return output;
  10448. },
  10449. /**
  10450. * Test if a world point overlaps bodies. You will get an array of actual P2 bodies back. You can find out which Sprite a Body belongs to
  10451. * (if any) by checking the Body.parent.sprite property. Body.parent is a Phaser.Physics.P2.Body property.
  10452. *
  10453. * @method Phaser.Physics.P2#hitTest
  10454. * @param {Phaser.Point} worldPoint - Point to use for intersection tests. The points values must be in world (pixel) coordinates.
  10455. * @param {Array<Phaser.Physics.P2.Body|Phaser.Sprite|p2.Body>} [bodies] - A list of objects to check for intersection. If not given it will check Phaser.Physics.P2.world.bodies (i.e. all world bodies)
  10456. * @param {number} [precision=5] - Used for matching against particles and lines. Adds some margin to these infinitesimal objects.
  10457. * @param {boolean} [filterStatic=false] - If true all Static objects will be removed from the results array.
  10458. * @return {Array} Array of bodies that overlap the point.
  10459. */
  10460. hitTest: function (worldPoint, bodies, precision, filterStatic) {
  10461. if (typeof bodies === 'undefined') { bodies = this.world.bodies; }
  10462. if (typeof precision === 'undefined') { precision = 5; }
  10463. if (typeof filterStatic === 'undefined') { filterStatic = false; }
  10464. var physicsPosition = [ this.pxmi(worldPoint.x), this.pxmi(worldPoint.y) ];
  10465. var query = [];
  10466. var i = bodies.length;
  10467. while (i--)
  10468. {
  10469. if (bodies[i] instanceof Phaser.Physics.P2.Body && !(filterStatic && bodies[i].data.motionState === p2.Body.STATIC))
  10470. {
  10471. query.push(bodies[i].data);
  10472. }
  10473. else if (bodies[i] instanceof p2.Body && bodies[i].parent && !(filterStatic && bodies[i].motionState === p2.Body.STATIC))
  10474. {
  10475. query.push(bodies[i]);
  10476. }
  10477. else if (bodies[i] instanceof Phaser.Sprite && bodies[i].hasOwnProperty('body') && !(filterStatic && bodies[i].body.data.motionState === p2.Body.STATIC))
  10478. {
  10479. query.push(bodies[i].body.data);
  10480. }
  10481. }
  10482. return this.world.hitTest(physicsPosition, query, precision);
  10483. },
  10484. /**
  10485. * Converts the current world into a JSON object.
  10486. *
  10487. * @method Phaser.Physics.P2#toJSON
  10488. * @return {object} A JSON representation of the world.
  10489. */
  10490. toJSON: function () {
  10491. return this.world.toJSON();
  10492. },
  10493. /**
  10494. * Creates a new Collision Group and optionally applies it to the given object.
  10495. * Collision Groups are handled using bitmasks, therefore you have a fixed limit you can create before you need to re-use older groups.
  10496. *
  10497. * @method Phaser.Physics.P2#createCollisionGroup
  10498. * @param {Phaser.Group|Phaser.Sprite} [object] - An optional Sprite or Group to apply the Collision Group to. If a Group is given it will be applied to all top-level children.
  10499. * @protected
  10500. */
  10501. createCollisionGroup: function (object) {
  10502. var bitmask = Math.pow(2, this._collisionGroupID);
  10503. if (this.walls.left)
  10504. {
  10505. this.walls.left.shapes[0].collisionMask = this.walls.left.shapes[0].collisionMask | bitmask;
  10506. }
  10507. if (this.walls.right)
  10508. {
  10509. this.walls.right.shapes[0].collisionMask = this.walls.right.shapes[0].collisionMask | bitmask;
  10510. }
  10511. if (this.walls.top)
  10512. {
  10513. this.walls.top.shapes[0].collisionMask = this.walls.top.shapes[0].collisionMask | bitmask;
  10514. }
  10515. if (this.walls.bottom)
  10516. {
  10517. this.walls.bottom.shapes[0].collisionMask = this.walls.bottom.shapes[0].collisionMask | bitmask;
  10518. }
  10519. this._collisionGroupID++;
  10520. var group = new Phaser.Physics.P2.CollisionGroup(bitmask);
  10521. this.collisionGroups.push(group);
  10522. if (object)
  10523. {
  10524. this.setCollisionGroup(object, group);
  10525. }
  10526. return group;
  10527. },
  10528. /**
  10529. * Sets the given CollisionGroup to be the collision group for all shapes in this Body, unless a shape is specified.
  10530. * Note that this resets the collisionMask and any previously set groups. See Body.collides() for appending them.
  10531. *
  10532. * @method Phaser.Physics.P2y#setCollisionGroup
  10533. * @param {Phaser.Group|Phaser.Sprite} object - A Sprite or Group to apply the Collision Group to. If a Group is given it will be applied to all top-level children.
  10534. * @param {Phaser.Physics.CollisionGroup} group - The Collision Group that this Bodies shapes will use.
  10535. */
  10536. setCollisionGroup: function (object, group) {
  10537. if (object instanceof Phaser.Group)
  10538. {
  10539. for (var i = 0; i < object.total; i++)
  10540. {
  10541. if (object.children[i]['body'] && object.children[i]['body'].type === Phaser.Physics.P2JS)
  10542. {
  10543. object.children[i].body.setCollisionGroup(group);
  10544. }
  10545. }
  10546. }
  10547. else
  10548. {
  10549. object.body.setCollisionGroup(group);
  10550. }
  10551. },
  10552. /**
  10553. * Creates a spring, connecting two bodies. A spring can have a resting length, a stiffness and damping.
  10554. *
  10555. * @method Phaser.Physics.P2#createSpring
  10556. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyA - First connected body.
  10557. * @param {Phaser.Sprite|Phaser.Physics.P2.Body|p2.Body} bodyB - Second connected body.
  10558. * @param {number} [restLength=1] - Rest length of the spring. A number > 0.
  10559. * @param {number} [stiffness=100] - Stiffness of the spring. A number >= 0.
  10560. * @param {number} [damping=1] - Damping of the spring. A number >= 0.
  10561. * @param {number} [restLength=1] - Rest length of the spring. A number > 0.
  10562. * @param {number} [stiffness=100] - Stiffness of the spring. A number >= 0.
  10563. * @param {number} [damping=1] - Damping of the spring. A number >= 0.
  10564. * @param {Array} [worldA] - Where to hook the spring to body A in world coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  10565. * @param {Array} [worldB] - Where to hook the spring to body B in world coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  10566. * @param {Array} [localA] - Where to hook the spring to body A in local body coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  10567. * @param {Array} [localB] - Where to hook the spring to body B in local body coordinates. This value is an array by 2 elements, x and y, i.e: [32, 32].
  10568. * @return {Phaser.Physics.P2.Spring} The spring
  10569. */
  10570. createSpring: function (bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB) {
  10571. bodyA = this.getBody(bodyA);
  10572. bodyB = this.getBody(bodyB);
  10573. if (!bodyA || !bodyB)
  10574. {
  10575. console.warn('Cannot create Spring, invalid body objects given');
  10576. }
  10577. else
  10578. {
  10579. return this.addSpring(new Phaser.Physics.P2.Spring(this, bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB));
  10580. }
  10581. },
  10582. /**
  10583. * Creates a new Body and adds it to the World.
  10584. *
  10585. * @method Phaser.Physics.P2#createBody
  10586. * @param {number} x - The x coordinate of Body.
  10587. * @param {number} y - The y coordinate of Body.
  10588. * @param {number} mass - The mass of the Body. A mass of 0 means a 'static' Body is created.
  10589. * @param {boolean} [addToWorld=false] - Automatically add this Body to the world? (usually false as it won't have any shapes on construction).
  10590. * @param {object} options - An object containing the build options:
  10591. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  10592. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  10593. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  10594. * @param {(number[]|...number)} points - An array of 2d vectors that form the convex or concave polygon.
  10595. * Either [[0,0], [0,1],...] or a flat array of numbers that will be interpreted as [x,y, x,y, ...],
  10596. * or the arguments passed can be flat x,y values e.g. `setPolygon(options, x,y, x,y, x,y, ...)` where `x` and `y` are numbers.
  10597. * @return {Phaser.Physics.P2.Body} The body
  10598. */
  10599. createBody: function (x, y, mass, addToWorld, options, data) {
  10600. if (typeof addToWorld === 'undefined') { addToWorld = false; }
  10601. var body = new Phaser.Physics.P2.Body(this.game, null, x, y, mass);
  10602. if (data)
  10603. {
  10604. var result = body.addPolygon(options, data);
  10605. if (!result)
  10606. {
  10607. return false;
  10608. }
  10609. }
  10610. if (addToWorld)
  10611. {
  10612. this.world.addBody(body.data);
  10613. }
  10614. return body;
  10615. },
  10616. /**
  10617. * Creates a new Particle and adds it to the World.
  10618. *
  10619. * @method Phaser.Physics.P2#createParticle
  10620. * @param {number} x - The x coordinate of Body.
  10621. * @param {number} y - The y coordinate of Body.
  10622. * @param {number} mass - The mass of the Body. A mass of 0 means a 'static' Body is created.
  10623. * @param {boolean} [addToWorld=false] - Automatically add this Body to the world? (usually false as it won't have any shapes on construction).
  10624. * @param {object} options - An object containing the build options:
  10625. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  10626. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  10627. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  10628. * @param {(number[]|...number)} points - An array of 2d vectors that form the convex or concave polygon.
  10629. * Either [[0,0], [0,1],...] or a flat array of numbers that will be interpreted as [x,y, x,y, ...],
  10630. * or the arguments passed can be flat x,y values e.g. `setPolygon(options, x,y, x,y, x,y, ...)` where `x` and `y` are numbers.
  10631. */
  10632. createParticle: function (x, y, mass, addToWorld, options, data) {
  10633. if (typeof addToWorld === 'undefined') { addToWorld = false; }
  10634. var body = new Phaser.Physics.P2.Body(this.game, null, x, y, mass);
  10635. if (data)
  10636. {
  10637. var result = body.addPolygon(options, data);
  10638. if (!result)
  10639. {
  10640. return false;
  10641. }
  10642. }
  10643. if (addToWorld)
  10644. {
  10645. this.world.addBody(body.data);
  10646. }
  10647. return body;
  10648. },
  10649. /**
  10650. * Converts all of the polylines objects inside a Tiled ObjectGroup into physics bodies that are added to the world.
  10651. * Note that the polylines must be created in such a way that they can withstand polygon decomposition.
  10652. *
  10653. * @method Phaser.Physics.P2#convertCollisionObjects
  10654. * @param {Phaser.Tilemap} map - The Tilemap to get the map data from.
  10655. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to map.currentLayer.
  10656. * @param {boolean} [addToWorld=true] - If true it will automatically add each body to the world.
  10657. * @return {array} An array of the Phaser.Physics.Body objects that have been created.
  10658. */
  10659. convertCollisionObjects: function (map, layer, addToWorld) {
  10660. if (typeof addToWorld === 'undefined') { addToWorld = true; }
  10661. var output = [];
  10662. for (var i = 0, len = map.collision[layer].length; i < len; i++)
  10663. {
  10664. // name: json.layers[i].objects[v].name,
  10665. // x: json.layers[i].objects[v].x,
  10666. // y: json.layers[i].objects[v].y,
  10667. // width: json.layers[i].objects[v].width,
  10668. // height: json.layers[i].objects[v].height,
  10669. // visible: json.layers[i].objects[v].visible,
  10670. // properties: json.layers[i].objects[v].properties,
  10671. // polyline: json.layers[i].objects[v].polyline
  10672. var object = map.collision[layer][i];
  10673. var body = this.createBody(object.x, object.y, 0, addToWorld, {}, object.polyline);
  10674. if (body)
  10675. {
  10676. output.push(body);
  10677. }
  10678. }
  10679. return output;
  10680. },
  10681. /**
  10682. * Clears all physics bodies from the given TilemapLayer that were created with `World.convertTilemap`.
  10683. *
  10684. * @method Phaser.Physics.P2#clearTilemapLayerBodies
  10685. * @param {Phaser.Tilemap} map - The Tilemap to get the map data from.
  10686. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to map.currentLayer.
  10687. */
  10688. clearTilemapLayerBodies: function (map, layer) {
  10689. layer = map.getLayer(layer);
  10690. var i = map.layers[layer].bodies.length;
  10691. while (i--)
  10692. {
  10693. map.layers[layer].bodies[i].destroy();
  10694. }
  10695. map.layers[layer].bodies.length = [];
  10696. },
  10697. /**
  10698. * Goes through all tiles in the given Tilemap and TilemapLayer and converts those set to collide into physics bodies.
  10699. * Only call this *after* you have specified all of the tiles you wish to collide with calls like Tilemap.setCollisionBetween, etc.
  10700. * Every time you call this method it will destroy any previously created bodies and remove them from the world.
  10701. * Therefore understand it's a very expensive operation and not to be done in a core game update loop.
  10702. *
  10703. * @method Phaser.Physics.P2#convertTilemap
  10704. * @param {Phaser.Tilemap} map - The Tilemap to get the map data from.
  10705. * @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to map.currentLayer.
  10706. * @param {boolean} [addToWorld=true] - If true it will automatically add each body to the world, otherwise it's up to you to do so.
  10707. * @param {boolean} [optimize=true] - If true adjacent colliding tiles will be combined into a single body to save processing. However it means you cannot perform specific Tile to Body collision responses.
  10708. * @return {array} An array of the Phaser.Physics.P2.Body objects that were created.
  10709. */
  10710. convertTilemap: function (map, layer, addToWorld, optimize) {
  10711. layer = map.getLayer(layer);
  10712. if (typeof addToWorld === 'undefined') { addToWorld = true; }
  10713. if (typeof optimize === 'undefined') { optimize = true; }
  10714. // If the bodies array is already populated we need to nuke it
  10715. this.clearTilemapLayerBodies(map, layer);
  10716. var width = 0;
  10717. var sx = 0;
  10718. var sy = 0;
  10719. for (var y = 0, h = map.layers[layer].height; y < h; y++)
  10720. {
  10721. width = 0;
  10722. for (var x = 0, w = map.layers[layer].width; x < w; x++)
  10723. {
  10724. var tile = map.layers[layer].data[y][x];
  10725. if (tile)
  10726. {
  10727. if (optimize)
  10728. {
  10729. var right = map.getTileRight(layer, x, y);
  10730. if (width === 0)
  10731. {
  10732. sx = tile.x * tile.width;
  10733. sy = tile.y * tile.height;
  10734. width = tile.width;
  10735. }
  10736. if (right && right.collides)
  10737. {
  10738. width += tile.width;
  10739. }
  10740. else
  10741. {
  10742. var body = this.createBody(sx, sy, 0, false);
  10743. body.addRectangle(width, tile.height, width / 2, tile.height / 2, 0);
  10744. if (addToWorld)
  10745. {
  10746. this.addBody(body);
  10747. }
  10748. map.layers[layer].bodies.push(body);
  10749. width = 0;
  10750. }
  10751. }
  10752. else
  10753. {
  10754. var body = this.createBody(tile.x * tile.width, tile.y * tile.height, 0, false);
  10755. body.addRectangle(tile.width, tile.height, tile.width / 2, tile.height / 2, 0);
  10756. if (addToWorld)
  10757. {
  10758. this.addBody(body);
  10759. }
  10760. map.layers[layer].bodies.push(body);
  10761. }
  10762. }
  10763. }
  10764. }
  10765. return map.layers[layer].bodies;
  10766. },
  10767. /**
  10768. * Convert p2 physics value (meters) to pixel scale.
  10769. * By default Phaser uses a scale of 20px per meter.
  10770. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  10771. *
  10772. * @method Phaser.Physics.P2#mpx
  10773. * @param {number} v - The value to convert.
  10774. * @return {number} The scaled value.
  10775. */
  10776. mpx: function (v) {
  10777. return v *= 20;
  10778. },
  10779. /**
  10780. * Convert pixel value to p2 physics scale (meters).
  10781. * By default Phaser uses a scale of 20px per meter.
  10782. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  10783. *
  10784. * @method Phaser.Physics.P2#pxm
  10785. * @param {number} v - The value to convert.
  10786. * @return {number} The scaled value.
  10787. */
  10788. pxm: function (v) {
  10789. return v * 0.05;
  10790. },
  10791. /**
  10792. * Convert p2 physics value (meters) to pixel scale and inverses it.
  10793. * By default Phaser uses a scale of 20px per meter.
  10794. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  10795. *
  10796. * @method Phaser.Physics.P2#mpxi
  10797. * @param {number} v - The value to convert.
  10798. * @return {number} The scaled value.
  10799. */
  10800. mpxi: function (v) {
  10801. return v *= -20;
  10802. },
  10803. /**
  10804. * Convert pixel value to p2 physics scale (meters) and inverses it.
  10805. * By default Phaser uses a scale of 20px per meter.
  10806. * If you need to modify this you can over-ride these functions via the Physics Configuration object.
  10807. *
  10808. * @method Phaser.Physics.P2#pxmi
  10809. * @param {number} v - The value to convert.
  10810. * @return {number} The scaled value.
  10811. */
  10812. pxmi: function (v) {
  10813. return v * -0.05;
  10814. }
  10815. };
  10816. /**
  10817. * @name Phaser.Physics.P2#friction
  10818. * @property {number} friction - Friction between colliding bodies. This value is used if no matching ContactMaterial is found for a Material pair.
  10819. */
  10820. Object.defineProperty(Phaser.Physics.P2.prototype, "friction", {
  10821. get: function () {
  10822. return this.world.defaultContactMaterial.friction;
  10823. },
  10824. set: function (value) {
  10825. this.world.defaultContactMaterial.friction = value;
  10826. }
  10827. });
  10828. /**
  10829. * @name Phaser.Physics.P2#defaultFriction
  10830. * @property {number} defaultFriction - DEPRECATED: Use World.friction instead.
  10831. */
  10832. Object.defineProperty(Phaser.Physics.P2.prototype, "defaultFriction", {
  10833. get: function () {
  10834. return this.world.defaultContactMaterial.friction;
  10835. },
  10836. set: function (value) {
  10837. this.world.defaultContactMaterial.friction = value;
  10838. }
  10839. });
  10840. /**
  10841. * @name Phaser.Physics.P2#restitution
  10842. * @property {number} restitution - Default coefficient of restitution between colliding bodies. This value is used if no matching ContactMaterial is found for a Material pair.
  10843. */
  10844. Object.defineProperty(Phaser.Physics.P2.prototype, "restitution", {
  10845. get: function () {
  10846. return this.world.defaultContactMaterial.restitution;
  10847. },
  10848. set: function (value) {
  10849. this.world.defaultContactMaterial.restitution = value;
  10850. }
  10851. });
  10852. /**
  10853. * @name Phaser.Physics.P2#defaultRestitution
  10854. * @property {number} defaultRestitution - DEPRECATED: Use World.restitution instead.
  10855. */
  10856. Object.defineProperty(Phaser.Physics.P2.prototype, "defaultRestitution", {
  10857. get: function () {
  10858. return this.world.defaultContactMaterial.restitution;
  10859. },
  10860. set: function (value) {
  10861. this.world.defaultContactMaterial.restitution = value;
  10862. }
  10863. });
  10864. /**
  10865. * @name Phaser.Physics.P2#contactMaterial
  10866. * @property {p2.ContactMaterial} contactMaterial - The default Contact Material being used by the World.
  10867. */
  10868. Object.defineProperty(Phaser.Physics.P2.prototype, "contactMaterial", {
  10869. get: function () {
  10870. return this.world.defaultContactMaterial;
  10871. },
  10872. set: function (value) {
  10873. this.world.defaultContactMaterial = value;
  10874. }
  10875. });
  10876. /**
  10877. * @name Phaser.Physics.P2#applySpringForces
  10878. * @property {boolean} applySpringForces - Enable to automatically apply spring forces each step.
  10879. */
  10880. Object.defineProperty(Phaser.Physics.P2.prototype, "applySpringForces", {
  10881. get: function () {
  10882. return this.world.applySpringForces;
  10883. },
  10884. set: function (value) {
  10885. this.world.applySpringForces = value;
  10886. }
  10887. });
  10888. /**
  10889. * @name Phaser.Physics.P2#applyDamping
  10890. * @property {boolean} applyDamping - Enable to automatically apply body damping each step.
  10891. */
  10892. Object.defineProperty(Phaser.Physics.P2.prototype, "applyDamping", {
  10893. get: function () {
  10894. return this.world.applyDamping;
  10895. },
  10896. set: function (value) {
  10897. this.world.applyDamping = value;
  10898. }
  10899. });
  10900. /**
  10901. * @name Phaser.Physics.P2#applyGravity
  10902. * @property {boolean} applyGravity - Enable to automatically apply gravity each step.
  10903. */
  10904. Object.defineProperty(Phaser.Physics.P2.prototype, "applyGravity", {
  10905. get: function () {
  10906. return this.world.applyGravity;
  10907. },
  10908. set: function (value) {
  10909. this.world.applyGravity = value;
  10910. }
  10911. });
  10912. /**
  10913. * @name Phaser.Physics.P2#solveConstraints
  10914. * @property {boolean} solveConstraints - Enable/disable constraint solving in each step.
  10915. */
  10916. Object.defineProperty(Phaser.Physics.P2.prototype, "solveConstraints", {
  10917. get: function () {
  10918. return this.world.solveConstraints;
  10919. },
  10920. set: function (value) {
  10921. this.world.solveConstraints = value;
  10922. }
  10923. });
  10924. /**
  10925. * @name Phaser.Physics.P2#time
  10926. * @property {boolean} time - The World time.
  10927. * @readonly
  10928. */
  10929. Object.defineProperty(Phaser.Physics.P2.prototype, "time", {
  10930. get: function () {
  10931. return this.world.time;
  10932. }
  10933. });
  10934. /**
  10935. * @name Phaser.Physics.P2#emitImpactEvent
  10936. * @property {boolean} emitImpactEvent - Set to true if you want to the world to emit the "impact" event. Turning this off could improve performance.
  10937. */
  10938. Object.defineProperty(Phaser.Physics.P2.prototype, "emitImpactEvent", {
  10939. get: function () {
  10940. return this.world.emitImpactEvent;
  10941. },
  10942. set: function (value) {
  10943. this.world.emitImpactEvent = value;
  10944. }
  10945. });
  10946. /**
  10947. * @name Phaser.Physics.P2#enableBodySleeping
  10948. * @property {boolean} enableBodySleeping - Enable / disable automatic body sleeping.
  10949. */
  10950. Object.defineProperty(Phaser.Physics.P2.prototype, "enableBodySleeping", {
  10951. get: function () {
  10952. return this.world.enableBodySleeping;
  10953. },
  10954. set: function (value) {
  10955. this.world.enableBodySleeping = value;
  10956. }
  10957. });
  10958. /**
  10959. * @name Phaser.Physics.P2#total
  10960. * @property {number} total - The total number of bodies in the world.
  10961. * @readonly
  10962. */
  10963. Object.defineProperty(Phaser.Physics.P2.prototype, "total", {
  10964. get: function () {
  10965. return this.world.bodies.length;
  10966. }
  10967. });
  10968. /* jshint noarg: false */
  10969. /**
  10970. * @author Georgios Kaleadis https://github.com/georgiee
  10971. * @author Richard Davey <rich@photonstorm.com>
  10972. * @copyright 2014 Photon Storm Ltd.
  10973. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  10974. */
  10975. /**
  10976. * Allow to access a list of created fixture (coming from Body#addPhaserPolygon)
  10977. * which itself parse the input from PhysicsEditor with the custom phaser exporter.
  10978. * You can access fixtures of a Body by a group index or even by providing a fixture Key.
  10979. * You can set the fixture key and also the group index for a fixture in PhysicsEditor.
  10980. * This gives you the power to create a complex body built of many fixtures and modify them
  10981. * during runtime (to remove parts, set masks, categories & sensor properties)
  10982. *
  10983. * @class Phaser.Physics.P2.FixtureList
  10984. * @classdesc Collection for generated P2 fixtures
  10985. * @constructor
  10986. * @param {Array} list - A list of fixtures (from Phaser.Physics.P2.Body#addPhaserPolygon)
  10987. */
  10988. Phaser.Physics.P2.FixtureList = function (list) {
  10989. if (!Array.isArray(list))
  10990. {
  10991. list = [list];
  10992. }
  10993. this.rawList = list;
  10994. this.init();
  10995. this.parse(this.rawList);
  10996. };
  10997. Phaser.Physics.P2.FixtureList.prototype = {
  10998. /**
  10999. * @method Phaser.Physics.P2.FixtureList#init
  11000. */
  11001. init: function () {
  11002. /**
  11003. * @property {object} namedFixtures - Collect all fixtures with a key
  11004. * @private
  11005. */
  11006. this.namedFixtures = {};
  11007. /**
  11008. * @property {Array} groupedFixtures - Collect all given fixtures per group index. Notice: Every fixture with a key also belongs to a group
  11009. * @private
  11010. */
  11011. this.groupedFixtures = [];
  11012. /**
  11013. * @property {Array} allFixtures - This is a list of everything in this collection
  11014. * @private
  11015. */
  11016. this.allFixtures = [];
  11017. },
  11018. /**
  11019. * @method Phaser.Physics.P2.FixtureList#setCategory
  11020. * @param {number} bit - The bit to set as the collision group.
  11021. * @param {string} fixtureKey - Only apply to the fixture with the given key.
  11022. */
  11023. setCategory: function (bit, fixtureKey) {
  11024. var setter = function(fixture) {
  11025. fixture.collisionGroup = bit;
  11026. };
  11027. this.getFixtures(fixtureKey).forEach(setter);
  11028. },
  11029. /**
  11030. * @method Phaser.Physics.P2.FixtureList#setMask
  11031. * @param {number} bit - The bit to set as the collision mask
  11032. * @param {string} fixtureKey - Only apply to the fixture with the given key
  11033. */
  11034. setMask: function (bit, fixtureKey) {
  11035. var setter = function(fixture) {
  11036. fixture.collisionMask = bit;
  11037. };
  11038. this.getFixtures(fixtureKey).forEach(setter);
  11039. },
  11040. /**
  11041. * @method Phaser.Physics.P2.FixtureList#setSensor
  11042. * @param {boolean} value - sensor true or false
  11043. * @param {string} fixtureKey - Only apply to the fixture with the given key
  11044. */
  11045. setSensor: function (value, fixtureKey) {
  11046. var setter = function(fixture) {
  11047. fixture.sensor = value;
  11048. };
  11049. this.getFixtures(fixtureKey).forEach(setter);
  11050. },
  11051. /**
  11052. * @method Phaser.Physics.P2.FixtureList#setMaterial
  11053. * @param {Object} material - The contact material for a fixture
  11054. * @param {string} fixtureKey - Only apply to the fixture with the given key
  11055. */
  11056. setMaterial: function (material, fixtureKey) {
  11057. var setter = function(fixture) {
  11058. fixture.material = material;
  11059. };
  11060. this.getFixtures(fixtureKey).forEach(setter);
  11061. },
  11062. /**
  11063. * Accessor to get either a list of specified fixtures by key or the whole fixture list
  11064. *
  11065. * @method Phaser.Physics.P2.FixtureList#getFixtures
  11066. * @param {array} keys - A list of fixture keys
  11067. */
  11068. getFixtures: function (keys) {
  11069. var fixtures = [];
  11070. if (keys)
  11071. {
  11072. if (!(keys instanceof Array))
  11073. {
  11074. keys = [keys];
  11075. }
  11076. var self = this;
  11077. keys.forEach(function(key) {
  11078. if (self.namedFixtures[key])
  11079. {
  11080. fixtures.push(self.namedFixtures[key]);
  11081. }
  11082. });
  11083. return this.flatten(fixtures);
  11084. }
  11085. else
  11086. {
  11087. return this.allFixtures;
  11088. }
  11089. },
  11090. /**
  11091. * Accessor to get either a single fixture by its key.
  11092. *
  11093. * @method Phaser.Physics.P2.FixtureList#getFixtureByKey
  11094. * @param {string} key - The key of the fixture.
  11095. */
  11096. getFixtureByKey: function (key) {
  11097. return this.namedFixtures[key];
  11098. },
  11099. /**
  11100. * Accessor to get a group of fixtures by its group index.
  11101. *
  11102. * @method Phaser.Physics.P2.FixtureList#getGroup
  11103. * @param {number} groupID - The group index.
  11104. */
  11105. getGroup: function (groupID) {
  11106. return this.groupedFixtures[groupID];
  11107. },
  11108. /**
  11109. * Parser for the output of Phaser.Physics.P2.Body#addPhaserPolygon
  11110. *
  11111. * @method Phaser.Physics.P2.FixtureList#parse
  11112. */
  11113. parse: function () {
  11114. var key, value, _ref, _results;
  11115. _ref = this.rawList;
  11116. _results = [];
  11117. for (key in _ref)
  11118. {
  11119. value = _ref[key];
  11120. if (!isNaN(key - 0))
  11121. {
  11122. this.groupedFixtures[key] = this.groupedFixtures[key] || [];
  11123. this.groupedFixtures[key] = this.groupedFixtures[key].concat(value);
  11124. }
  11125. else
  11126. {
  11127. this.namedFixtures[key] = this.flatten(value);
  11128. }
  11129. _results.push(this.allFixtures = this.flatten(this.groupedFixtures));
  11130. }
  11131. },
  11132. /**
  11133. * A helper to flatten arrays. This is very useful as the fixtures are nested from time to time due to the way P2 creates and splits polygons.
  11134. *
  11135. * @method Phaser.Physics.P2.FixtureList#flatten
  11136. * @param {array} array - The array to flatten. Notice: This will happen recursive not shallow.
  11137. */
  11138. flatten: function (array) {
  11139. var result, self;
  11140. result = [];
  11141. self = arguments.callee;
  11142. array.forEach(function(item) {
  11143. return Array.prototype.push.apply(result, (Array.isArray(item) ? self(item) : [item]));
  11144. });
  11145. return result;
  11146. }
  11147. };
  11148. /**
  11149. * @author Richard Davey <rich@photonstorm.com>
  11150. * @copyright 2014 Photon Storm Ltd.
  11151. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11152. */
  11153. /**
  11154. * A PointProxy is an internal class that allows for direct getter/setter style property access to Arrays and TypedArrays.
  11155. *
  11156. * @class Phaser.Physics.P2.PointProxy
  11157. * @classdesc PointProxy
  11158. * @constructor
  11159. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  11160. * @param {any} destination - The object to bind to.
  11161. */
  11162. Phaser.Physics.P2.PointProxy = function (world, destination) {
  11163. this.world = world;
  11164. this.destination = destination;
  11165. };
  11166. Phaser.Physics.P2.PointProxy.prototype.constructor = Phaser.Physics.P2.PointProxy;
  11167. /**
  11168. * @name Phaser.Physics.P2.PointProxy#x
  11169. * @property {number} x - The x property of this PointProxy.
  11170. */
  11171. Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "x", {
  11172. get: function () {
  11173. return this.destination[0];
  11174. },
  11175. set: function (value) {
  11176. this.destination[0] = this.world.pxm(value);
  11177. }
  11178. });
  11179. /**
  11180. * @name Phaser.Physics.P2.PointProxy#y
  11181. * @property {number} y - The y property of this PointProxy.
  11182. */
  11183. Object.defineProperty(Phaser.Physics.P2.PointProxy.prototype, "y", {
  11184. get: function () {
  11185. return this.destination[1];
  11186. },
  11187. set: function (value) {
  11188. this.destination[1] = this.world.pxm(value);
  11189. }
  11190. });
  11191. /**
  11192. * @author Richard Davey <rich@photonstorm.com>
  11193. * @copyright 2014 Photon Storm Ltd.
  11194. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11195. */
  11196. /**
  11197. * A InversePointProxy is an internal class that allows for direct getter/setter style property access to Arrays and TypedArrays but inverses the values on set.
  11198. *
  11199. * @class Phaser.Physics.P2.InversePointProxy
  11200. * @classdesc InversePointProxy
  11201. * @constructor
  11202. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  11203. * @param {any} destination - The object to bind to.
  11204. */
  11205. Phaser.Physics.P2.InversePointProxy = function (world, destination) {
  11206. this.world = world;
  11207. this.destination = destination;
  11208. };
  11209. Phaser.Physics.P2.InversePointProxy.prototype.constructor = Phaser.Physics.P2.InversePointProxy;
  11210. /**
  11211. * @name Phaser.Physics.P2.InversePointProxy#x
  11212. * @property {number} x - The x property of this InversePointProxy.
  11213. */
  11214. Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "x", {
  11215. get: function () {
  11216. return this.destination[0];
  11217. },
  11218. set: function (value) {
  11219. this.destination[0] = this.world.pxm(-value);
  11220. }
  11221. });
  11222. /**
  11223. * @name Phaser.Physics.P2.InversePointProxy#y
  11224. * @property {number} y - The y property of this InversePointProxy.
  11225. */
  11226. Object.defineProperty(Phaser.Physics.P2.InversePointProxy.prototype, "y", {
  11227. get: function () {
  11228. return this.destination[1];
  11229. },
  11230. set: function (value) {
  11231. this.destination[1] = this.world.pxm(-value);
  11232. }
  11233. });
  11234. /**
  11235. * @author Richard Davey <rich@photonstorm.com>
  11236. * @copyright 2014 Photon Storm Ltd.
  11237. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  11238. */
  11239. /**
  11240. * The Physics Body is typically linked to a single Sprite and defines properties that determine how the physics body is simulated.
  11241. * These properties affect how the body reacts to forces, what forces it generates on itself (to simulate friction), and how it reacts to collisions in the scene.
  11242. * In most cases, the properties are used to simulate physical effects. Each body also has its own property values that determine exactly how it reacts to forces and collisions in the scene.
  11243. * By default a single Rectangle shape is added to the Body that matches the dimensions of the parent Sprite. See addShape, removeShape, clearShapes to add extra shapes around the Body.
  11244. * Note: When bound to a Sprite to avoid single-pixel jitters on mobile devices we strongly recommend using Sprite sizes that are even on both axis, i.e. 128x128 not 127x127.
  11245. *
  11246. * @class Phaser.Physics.P2.Body
  11247. * @classdesc Physics Body Constructor
  11248. * @constructor
  11249. * @param {Phaser.Game} game - Game reference to the currently running game.
  11250. * @param {Phaser.Sprite} [sprite] - The Sprite object this physics body belongs to.
  11251. * @param {number} [x=0] - The x coordinate of this Body.
  11252. * @param {number} [y=0] - The y coordinate of this Body.
  11253. * @param {number} [mass=1] - The default mass of this Body (0 = static).
  11254. */
  11255. Phaser.Physics.P2.Body = function (game, sprite, x, y, mass) {
  11256. sprite = sprite || null;
  11257. x = x || 0;
  11258. y = y || 0;
  11259. if (typeof mass === 'undefined') { mass = 1; }
  11260. /**
  11261. * @property {Phaser.Game} game - Local reference to game.
  11262. */
  11263. this.game = game;
  11264. /**
  11265. * @property {Phaser.Physics.P2} world - Local reference to the P2 World.
  11266. */
  11267. this.world = game.physics.p2;
  11268. /**
  11269. * @property {Phaser.Sprite} sprite - Reference to the parent Sprite.
  11270. */
  11271. this.sprite = sprite;
  11272. /**
  11273. * @property {number} type - The type of physics system this body belongs to.
  11274. */
  11275. this.type = Phaser.Physics.P2JS;
  11276. /**
  11277. * @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
  11278. */
  11279. this.offset = new Phaser.Point();
  11280. /**
  11281. * @property {p2.Body} data - The p2 Body data.
  11282. * @protected
  11283. */
  11284. this.data = new p2.Body({ position: [ this.world.pxmi(x), this.world.pxmi(y) ], mass: mass });
  11285. this.data.parent = this;
  11286. /**
  11287. * @property {Phaser.InversePointProxy} velocity - The velocity of the body. Set velocity.x to a negative value to move to the left, position to the right. velocity.y negative values move up, positive move down.
  11288. */
  11289. this.velocity = new Phaser.Physics.P2.InversePointProxy(this.world, this.data.velocity);
  11290. /**
  11291. * @property {Phaser.InversePointProxy} force - The force applied to the body.
  11292. */
  11293. this.force = new Phaser.Physics.P2.InversePointProxy(this.world, this.data.force);
  11294. /**
  11295. * @property {Phaser.Point} gravity - A locally applied gravity force to the Body. Applied directly before the world step. NOTE: Not currently implemented.
  11296. */
  11297. this.gravity = new Phaser.Point();
  11298. /**
  11299. * Dispatched when a first contact is created between shapes in two bodies. This event is fired during the step, so collision has already taken place.
  11300. * The event will be sent 4 parameters: The body it is in contact with, the shape from this body that caused the contact, the shape from the contact body and the contact equation data array.
  11301. * @property {Phaser.Signal} onBeginContact
  11302. */
  11303. this.onBeginContact = new Phaser.Signal();
  11304. /**
  11305. * Dispatched when contact ends between shapes in two bodies. This event is fired during the step, so collision has already taken place.
  11306. * The event will be sent 3 parameters: The body it is in contact with, the shape from this body that caused the contact and the shape from the contact body.
  11307. * @property {Phaser.Signal} onEndContact
  11308. */
  11309. this.onEndContact = new Phaser.Signal();
  11310. /**
  11311. * @property {array} collidesWith - Array of CollisionGroups that this Bodies shapes collide with.
  11312. */
  11313. this.collidesWith = [];
  11314. /**
  11315. * @property {boolean} removeNextStep - To avoid deleting this body during a physics step, and causing all kinds of problems, set removeNextStep to true to have it removed in the next preUpdate.
  11316. */
  11317. this.removeNextStep = false;
  11318. /**
  11319. * @property {Phaser.Physics.P2.BodyDebug} debugBody - Reference to the debug body.
  11320. */
  11321. this.debugBody = null;
  11322. /**
  11323. * @property {boolean} _collideWorldBounds - Internal var that determines if this Body collides with the world bounds or not.
  11324. * @private
  11325. */
  11326. this._collideWorldBounds = true;
  11327. /**
  11328. * @property {object} _bodyCallbacks - Array of Body callbacks.
  11329. * @private
  11330. */
  11331. this._bodyCallbacks = {};
  11332. /**
  11333. * @property {object} _bodyCallbackContext - Array of Body callback contexts.
  11334. * @private
  11335. */
  11336. this._bodyCallbackContext = {};
  11337. /**
  11338. * @property {object} _groupCallbacks - Array of Group callbacks.
  11339. * @private
  11340. */
  11341. this._groupCallbacks = {};
  11342. /**
  11343. * @property {object} _bodyCallbackContext - Array of Grouo callback contexts.
  11344. * @private
  11345. */
  11346. this._groupCallbackContext = {};
  11347. // Set-up the default shape
  11348. if (sprite)
  11349. {
  11350. this.setRectangleFromSprite(sprite);
  11351. if (sprite.exists)
  11352. {
  11353. this.game.physics.p2.addBody(this);
  11354. }
  11355. }
  11356. };
  11357. Phaser.Physics.P2.Body.prototype = {
  11358. /**
  11359. * Sets a callback to be fired any time a shape in this Body impacts with a shape in the given Body. The impact test is performed against body.id values.
  11360. * The callback will be sent 4 parameters: This body, the body that impacted, the Shape in this body and the shape in the impacting body.
  11361. * Note that the impact event happens after collision resolution, so it cannot be used to prevent a collision from happening.
  11362. * It also happens mid-step. So do not destroy a Body during this callback, instead set safeDestroy to true so it will be killed on the next preUpdate.
  11363. *
  11364. * @method Phaser.Physics.P2.Body#createBodyCallback
  11365. * @param {Phaser.Sprite|Phaser.TileSprite|Phaser.Physics.P2.Body|p2.Body} object - The object to send impact events for.
  11366. * @param {function} callback - The callback to fire on impact. Set to null to clear a previously set callback.
  11367. * @param {object} callbackContext - The context under which the callback will fire.
  11368. */
  11369. createBodyCallback: function (object, callback, callbackContext) {
  11370. var id = -1;
  11371. if (object['id'])
  11372. {
  11373. id = object.id;
  11374. }
  11375. else if (object['body'])
  11376. {
  11377. id = object.body.id;
  11378. }
  11379. if (id > -1)
  11380. {
  11381. if (callback === null)
  11382. {
  11383. delete (this._bodyCallbacks[id]);
  11384. delete (this._bodyCallbackContext[id]);
  11385. }
  11386. else
  11387. {
  11388. this._bodyCallbacks[id] = callback;
  11389. this._bodyCallbackContext[id] = callbackContext;
  11390. }
  11391. }
  11392. },
  11393. /**
  11394. * Sets a callback to be fired any time this Body impacts with the given Group. The impact test is performed against shape.collisionGroup values.
  11395. * The callback will be sent 4 parameters: This body, the body that impacted, the Shape in this body and the shape in the impacting body.
  11396. * This callback will only fire if this Body has been assigned a collision group.
  11397. * Note that the impact event happens after collision resolution, so it cannot be used to prevent a collision from happening.
  11398. * It also happens mid-step. So do not destroy a Body during this callback, instead set safeDestroy to true so it will be killed on the next preUpdate.
  11399. *
  11400. * @method Phaser.Physics.P2.Body#createGroupCallback
  11401. * @param {Phaser.Physics.CollisionGroup} group - The Group to send impact events for.
  11402. * @param {function} callback - The callback to fire on impact. Set to null to clear a previously set callback.
  11403. * @param {object} callbackContext - The context under which the callback will fire.
  11404. */
  11405. createGroupCallback: function (group, callback, callbackContext) {
  11406. if (callback === null)
  11407. {
  11408. delete (this._groupCallbacks[group.mask]);
  11409. delete (this._groupCallbacksContext[group.mask]);
  11410. }
  11411. else
  11412. {
  11413. this._groupCallbacks[group.mask] = callback;
  11414. this._groupCallbackContext[group.mask] = callbackContext;
  11415. }
  11416. },
  11417. /**
  11418. * Gets the collision bitmask from the groups this body collides with.
  11419. *
  11420. * @method Phaser.Physics.P2.Body#getCollisionMask
  11421. * @return {number} The bitmask.
  11422. */
  11423. getCollisionMask: function () {
  11424. var mask = 0;
  11425. if (this._collideWorldBounds)
  11426. {
  11427. mask = this.game.physics.p2.boundsCollisionGroup.mask;
  11428. }
  11429. for (var i = 0; i < this.collidesWith.length; i++)
  11430. {
  11431. mask = mask | this.collidesWith[i].mask;
  11432. }
  11433. return mask;
  11434. },
  11435. /**
  11436. * Updates the collisionMask.
  11437. *
  11438. * @method Phaser.Physics.P2.Body#updateCollisionMask
  11439. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision group will be added to all Shapes in this Body.
  11440. */
  11441. updateCollisionMask: function (shape) {
  11442. var mask = this.getCollisionMask();
  11443. if (typeof shape === 'undefined')
  11444. {
  11445. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  11446. {
  11447. this.data.shapes[i].collisionMask = mask;
  11448. }
  11449. }
  11450. else
  11451. {
  11452. shape.collisionMask = mask;
  11453. }
  11454. },
  11455. /**
  11456. * Sets the given CollisionGroup to be the collision group for all shapes in this Body, unless a shape is specified.
  11457. * This also resets the collisionMask.
  11458. *
  11459. * @method Phaser.Physics.P2.Body#setCollisionGroup
  11460. * @param {Phaser.Physics.CollisionGroup} group - The Collision Group that this Bodies shapes will use.
  11461. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision group will be added to all Shapes in this Body.
  11462. */
  11463. setCollisionGroup: function (group, shape) {
  11464. var mask = this.getCollisionMask();
  11465. if (typeof shape === 'undefined')
  11466. {
  11467. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  11468. {
  11469. this.data.shapes[i].collisionGroup = group.mask;
  11470. this.data.shapes[i].collisionMask = mask;
  11471. }
  11472. }
  11473. else
  11474. {
  11475. shape.collisionGroup = group.mask;
  11476. shape.collisionMask = mask;
  11477. }
  11478. },
  11479. /**
  11480. * Clears the collision data from the shapes in this Body. Optionally clears Group and/or Mask.
  11481. *
  11482. * @method Phaser.Physics.P2.Body#clearCollision
  11483. * @param {boolean} [clearGroup=true] - Clear the collisionGroup value from the shape/s?
  11484. * @param {boolean} [clearMask=true] - Clear the collisionMask value from the shape/s?
  11485. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision data will be cleared from all Shapes in this Body.
  11486. */
  11487. clearCollision: function (clearGroup, clearMask, shape) {
  11488. if (typeof shape === 'undefined')
  11489. {
  11490. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  11491. {
  11492. if (clearGroup)
  11493. {
  11494. this.data.shapes[i].collisionGroup = null;
  11495. }
  11496. if (clearMask)
  11497. {
  11498. this.data.shapes[i].collisionMask = null;
  11499. }
  11500. }
  11501. }
  11502. else
  11503. {
  11504. if (clearGroup)
  11505. {
  11506. shape.collisionGroup = null;
  11507. }
  11508. if (clearMask)
  11509. {
  11510. shape.collisionMask = null;
  11511. }
  11512. }
  11513. if (clearGroup)
  11514. {
  11515. this.collidesWith.length = 0;
  11516. }
  11517. },
  11518. /**
  11519. * Adds the given CollisionGroup, or array of CollisionGroups, to the list of groups that this body will collide with and updates the collision masks.
  11520. *
  11521. * @method Phaser.Physics.P2.Body#collides
  11522. * @param {Phaser.Physics.CollisionGroup|array} group - The Collision Group or Array of Collision Groups that this Bodies shapes will collide with.
  11523. * @param {function} [callback] - Optional callback that will be triggered when this Body impacts with the given Group.
  11524. * @param {object} [callbackContext] - The context under which the callback will be called.
  11525. * @param {p2.Shape} [shape] - An optional Shape. If not provided the collision mask will be added to all Shapes in this Body.
  11526. */
  11527. collides: function (group, callback, callbackContext, shape) {
  11528. if (Array.isArray(group))
  11529. {
  11530. for (var i = 0; i < group.length; i++)
  11531. {
  11532. if (this.collidesWith.indexOf(group[i]) === -1)
  11533. {
  11534. this.collidesWith.push(group[i]);
  11535. if (callback)
  11536. {
  11537. this.createGroupCallback(group[i], callback, callbackContext);
  11538. }
  11539. }
  11540. }
  11541. }
  11542. else
  11543. {
  11544. if (this.collidesWith.indexOf(group) === -1)
  11545. {
  11546. this.collidesWith.push(group);
  11547. if (callback)
  11548. {
  11549. this.createGroupCallback(group, callback, callbackContext);
  11550. }
  11551. }
  11552. }
  11553. var mask = this.getCollisionMask();
  11554. if (typeof shape === 'undefined')
  11555. {
  11556. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  11557. {
  11558. this.data.shapes[i].collisionMask = mask;
  11559. }
  11560. }
  11561. else
  11562. {
  11563. shape.collisionMask = mask;
  11564. }
  11565. },
  11566. /**
  11567. * Moves the shape offsets so their center of mass becomes the body center of mass.
  11568. *
  11569. * @method Phaser.Physics.P2.Body#adjustCenterOfMass
  11570. */
  11571. adjustCenterOfMass: function () {
  11572. this.data.adjustCenterOfMass();
  11573. },
  11574. /**
  11575. * Apply damping, see http://code.google.com/p/bullet/issues/detail?id=74 for details.
  11576. *
  11577. * @method Phaser.Physics.P2.Body#applyDamping
  11578. * @param {number} dt - Current time step.
  11579. */
  11580. applyDamping: function (dt) {
  11581. this.data.applyDamping(dt);
  11582. },
  11583. /**
  11584. * Apply force to a world point. This could for example be a point on the RigidBody surface. Applying force this way will add to Body.force and Body.angularForce.
  11585. *
  11586. * @method Phaser.Physics.P2.Body#applyForce
  11587. * @param {number} force - The force to add.
  11588. * @param {number} worldX - The world x point to apply the force on.
  11589. * @param {number} worldY - The world y point to apply the force on.
  11590. */
  11591. applyForce: function (force, worldX, worldY) {
  11592. this.data.applyForce(force, [this.world.pxm(worldX), this.world.pxm(worldY)]);
  11593. },
  11594. /**
  11595. * Sets the force on the body to zero.
  11596. *
  11597. * @method Phaser.Physics.P2.Body#setZeroForce
  11598. */
  11599. setZeroForce: function () {
  11600. this.data.setZeroForce();
  11601. },
  11602. /**
  11603. * If this Body is dynamic then this will zero its angular velocity.
  11604. *
  11605. * @method Phaser.Physics.P2.Body#setZeroRotation
  11606. */
  11607. setZeroRotation: function () {
  11608. this.data.angularVelocity = 0;
  11609. },
  11610. /**
  11611. * If this Body is dynamic then this will zero its velocity on both axis.
  11612. *
  11613. * @method Phaser.Physics.P2.Body#setZeroVelocity
  11614. */
  11615. setZeroVelocity: function () {
  11616. this.data.velocity[0] = 0;
  11617. this.data.velocity[1] = 0;
  11618. },
  11619. /**
  11620. * Sets the Body damping and angularDamping to zero.
  11621. *
  11622. * @method Phaser.Physics.P2.Body#setZeroDamping
  11623. */
  11624. setZeroDamping: function () {
  11625. this.data.damping = 0;
  11626. this.data.angularDamping = 0;
  11627. },
  11628. /**
  11629. * Transform a world point to local body frame.
  11630. *
  11631. * @method Phaser.Physics.P2.Body#toLocalFrame
  11632. * @param {Float32Array|Array} out - The vector to store the result in.
  11633. * @param {Float32Array|Array} worldPoint - The input world vector.
  11634. */
  11635. toLocalFrame: function (out, worldPoint) {
  11636. return this.data.toLocalFrame(out, worldPoint);
  11637. },
  11638. /**
  11639. * Transform a local point to world frame.
  11640. *
  11641. * @method Phaser.Physics.P2.Body#toWorldFrame
  11642. * @param {Array} out - The vector to store the result in.
  11643. * @param {Array} localPoint - The input local vector.
  11644. */
  11645. toWorldFrame: function (out, localPoint) {
  11646. return this.data.toWorldFrame(out, localPoint);
  11647. },
  11648. /**
  11649. * This will rotate the Body by the given speed to the left (counter-clockwise).
  11650. *
  11651. * @method Phaser.Physics.P2.Body#rotateLeft
  11652. * @param {number} speed - The speed at which it should rotate.
  11653. */
  11654. rotateLeft: function (speed) {
  11655. this.data.angularVelocity = this.world.pxm(-speed);
  11656. },
  11657. /**
  11658. * This will rotate the Body by the given speed to the left (clockwise).
  11659. *
  11660. * @method Phaser.Physics.P2.Body#rotateRight
  11661. * @param {number} speed - The speed at which it should rotate.
  11662. */
  11663. rotateRight: function (speed) {
  11664. this.data.angularVelocity = this.world.pxm(speed);
  11665. },
  11666. /**
  11667. * Moves the Body forwards based on its current angle and the given speed.
  11668. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11669. *
  11670. * @method Phaser.Physics.P2.Body#moveForward
  11671. * @param {number} speed - The speed at which it should move forwards.
  11672. */
  11673. moveForward: function (speed) {
  11674. var magnitude = this.world.pxmi(-speed);
  11675. var angle = this.data.angle + Math.PI / 2;
  11676. this.data.velocity[0] = magnitude * Math.cos(angle);
  11677. this.data.velocity[1] = magnitude * Math.sin(angle);
  11678. },
  11679. /**
  11680. * Moves the Body backwards based on its current angle and the given speed.
  11681. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11682. *
  11683. * @method Phaser.Physics.P2.Body#moveBackward
  11684. * @param {number} speed - The speed at which it should move backwards.
  11685. */
  11686. moveBackward: function (speed) {
  11687. var magnitude = this.world.pxmi(-speed);
  11688. var angle = this.data.angle + Math.PI / 2;
  11689. this.data.velocity[0] = -(magnitude * Math.cos(angle));
  11690. this.data.velocity[1] = -(magnitude * Math.sin(angle));
  11691. },
  11692. /**
  11693. * Applies a force to the Body that causes it to 'thrust' forwards, based on its current angle and the given speed.
  11694. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11695. *
  11696. * @method Phaser.Physics.P2.Body#thrust
  11697. * @param {number} speed - The speed at which it should thrust.
  11698. */
  11699. thrust: function (speed) {
  11700. var magnitude = this.world.pxmi(-speed);
  11701. var angle = this.data.angle + Math.PI / 2;
  11702. this.data.force[0] += magnitude * Math.cos(angle);
  11703. this.data.force[1] += magnitude * Math.sin(angle);
  11704. },
  11705. /**
  11706. * Applies a force to the Body that causes it to 'thrust' backwards (in reverse), based on its current angle and the given speed.
  11707. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11708. *
  11709. * @method Phaser.Physics.P2.Body#rever
  11710. * @param {number} speed - The speed at which it should reverse.
  11711. */
  11712. reverse: function (speed) {
  11713. var magnitude = this.world.pxmi(-speed);
  11714. var angle = this.data.angle + Math.PI / 2;
  11715. this.data.force[0] -= magnitude * Math.cos(angle);
  11716. this.data.force[1] -= magnitude * Math.sin(angle);
  11717. },
  11718. /**
  11719. * If this Body is dynamic then this will move it to the left by setting its x velocity to the given speed.
  11720. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11721. *
  11722. * @method Phaser.Physics.P2.Body#moveLeft
  11723. * @param {number} speed - The speed at which it should move to the left, in pixels per second.
  11724. */
  11725. moveLeft: function (speed) {
  11726. this.data.velocity[0] = this.world.pxmi(-speed);
  11727. },
  11728. /**
  11729. * If this Body is dynamic then this will move it to the right by setting its x velocity to the given speed.
  11730. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11731. *
  11732. * @method Phaser.Physics.P2.Body#moveRight
  11733. * @param {number} speed - The speed at which it should move to the right, in pixels per second.
  11734. */
  11735. moveRight: function (speed) {
  11736. this.data.velocity[0] = this.world.pxmi(speed);
  11737. },
  11738. /**
  11739. * If this Body is dynamic then this will move it up by setting its y velocity to the given speed.
  11740. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11741. *
  11742. * @method Phaser.Physics.P2.Body#moveUp
  11743. * @param {number} speed - The speed at which it should move up, in pixels per second.
  11744. */
  11745. moveUp: function (speed) {
  11746. this.data.velocity[1] = this.world.pxmi(-speed);
  11747. },
  11748. /**
  11749. * If this Body is dynamic then this will move it down by setting its y velocity to the given speed.
  11750. * The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
  11751. *
  11752. * @method Phaser.Physics.P2.Body#moveDown
  11753. * @param {number} speed - The speed at which it should move down, in pixels per second.
  11754. */
  11755. moveDown: function (speed) {
  11756. this.data.velocity[1] = this.world.pxmi(speed);
  11757. },
  11758. /**
  11759. * Internal method. This is called directly before the sprites are sent to the renderer and after the update function has finished.
  11760. *
  11761. * @method Phaser.Physics.P2.Body#preUpdate
  11762. * @protected
  11763. */
  11764. preUpdate: function () {
  11765. if (this.removeNextStep)
  11766. {
  11767. this.removeFromWorld();
  11768. this.removeNextStep = false;
  11769. }
  11770. },
  11771. /**
  11772. * Internal method. This is called directly before the sprites are sent to the renderer and after the update function has finished.
  11773. *
  11774. * @method Phaser.Physics.P2.Body#postUpdate
  11775. * @protected
  11776. */
  11777. postUpdate: function () {
  11778. this.sprite.x = this.world.mpxi(this.data.position[0]);
  11779. this.sprite.y = this.world.mpxi(this.data.position[1]);
  11780. if (!this.fixedRotation)
  11781. {
  11782. this.sprite.rotation = this.data.angle;
  11783. }
  11784. },
  11785. /**
  11786. * Resets the Body force, velocity (linear and angular) and rotation. Optionally resets damping and mass.
  11787. *
  11788. * @method Phaser.Physics.P2.Body#reset
  11789. * @param {number} x - The new x position of the Body.
  11790. * @param {number} y - The new x position of the Body.
  11791. * @param {boolean} [resetDamping=false] - Resets the linear and angular damping.
  11792. * @param {boolean} [resetMass=false] - Sets the Body mass back to 1.
  11793. */
  11794. reset: function (x, y, resetDamping, resetMass) {
  11795. if (typeof resetDamping === 'undefined') { resetDamping = false; }
  11796. if (typeof resetMass === 'undefined') { resetMass = false; }
  11797. this.setZeroForce();
  11798. this.setZeroVelocity();
  11799. this.setZeroRotation();
  11800. if (resetDamping)
  11801. {
  11802. this.setZeroDamping();
  11803. }
  11804. if (resetMass)
  11805. {
  11806. this.mass = 1;
  11807. }
  11808. this.x = x;
  11809. this.y = y;
  11810. },
  11811. /**
  11812. * Adds this physics body to the world.
  11813. *
  11814. * @method Phaser.Physics.P2.Body#addToWorld
  11815. */
  11816. addToWorld: function () {
  11817. if (this.data.world !== this.game.physics.p2.world)
  11818. {
  11819. this.game.physics.p2.addBody(this);
  11820. }
  11821. },
  11822. /**
  11823. * Removes this physics body from the world.
  11824. *
  11825. * @method Phaser.Physics.P2.Body#removeFromWorld
  11826. */
  11827. removeFromWorld: function () {
  11828. if (this.data.world === this.game.physics.p2.world)
  11829. {
  11830. this.game.physics.p2.removeBodyNextStep(this);
  11831. }
  11832. },
  11833. /**
  11834. * Destroys this Body and all references it holds to other objects.
  11835. *
  11836. * @method Phaser.Physics.P2.Body#destroy
  11837. */
  11838. destroy: function () {
  11839. this.removeFromWorld();
  11840. this.clearShapes();
  11841. this._bodyCallbacks = {};
  11842. this._bodyCallbackContext = {};
  11843. this._groupCallbacks = {};
  11844. this._groupCallbackContext = {};
  11845. if (this.debugBody)
  11846. {
  11847. this.debugBody.destroy();
  11848. }
  11849. this.debugBody = null;
  11850. this.sprite = null;
  11851. },
  11852. /**
  11853. * Removes all Shapes from this Body.
  11854. *
  11855. * @method Phaser.Physics.P2.Body#clearShapes
  11856. */
  11857. clearShapes: function () {
  11858. var i = this.data.shapes.length;
  11859. while (i--)
  11860. {
  11861. this.data.removeShape(this.data.shapes[i]);
  11862. }
  11863. this.shapeChanged();
  11864. },
  11865. /**
  11866. * Add a shape to the body. You can pass a local transform when adding a shape, so that the shape gets an offset and an angle relative to the body center of mass.
  11867. * Will automatically update the mass properties and bounding radius.
  11868. *
  11869. * @method Phaser.Physics.P2.Body#addShape
  11870. * @param {p2.Shape} shape - The shape to add to the body.
  11871. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  11872. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  11873. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  11874. * @return {p2.Shape} The shape that was added to the body.
  11875. */
  11876. addShape: function (shape, offsetX, offsetY, rotation) {
  11877. if (typeof offsetX === 'undefined') { offsetX = 0; }
  11878. if (typeof offsetY === 'undefined') { offsetY = 0; }
  11879. if (typeof rotation === 'undefined') { rotation = 0; }
  11880. this.data.addShape(shape, [this.world.pxmi(offsetX), this.world.pxmi(offsetY)], rotation);
  11881. this.shapeChanged();
  11882. return shape;
  11883. },
  11884. /**
  11885. * Adds a Circle shape to this Body. You can control the offset from the center of the body and the rotation.
  11886. *
  11887. * @method Phaser.Physics.P2.Body#addCircle
  11888. * @param {number} radius - The radius of this circle (in pixels)
  11889. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  11890. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  11891. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  11892. * @return {p2.Circle} The Circle shape that was added to the Body.
  11893. */
  11894. addCircle: function (radius, offsetX, offsetY, rotation) {
  11895. var shape = new p2.Circle(this.world.pxm(radius));
  11896. return this.addShape(shape, offsetX, offsetY, rotation);
  11897. },
  11898. /**
  11899. * Adds a Rectangle shape to this Body. You can control the offset from the center of the body and the rotation.
  11900. *
  11901. * @method Phaser.Physics.P2.Body#addRectangle
  11902. * @param {number} width - The width of the rectangle in pixels.
  11903. * @param {number} height - The height of the rectangle in pixels.
  11904. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  11905. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  11906. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  11907. * @return {p2.Rectangle} The Rectangle shape that was added to the Body.
  11908. */
  11909. addRectangle: function (width, height, offsetX, offsetY, rotation) {
  11910. var shape = new p2.Rectangle(this.world.pxm(width), this.world.pxm(height));
  11911. return this.addShape(shape, offsetX, offsetY, rotation);
  11912. },
  11913. /**
  11914. * Adds a Plane shape to this Body. The plane is facing in the Y direction. You can control the offset from the center of the body and the rotation.
  11915. *
  11916. * @method Phaser.Physics.P2.Body#addPlane
  11917. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  11918. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  11919. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  11920. * @return {p2.Plane} The Plane shape that was added to the Body.
  11921. */
  11922. addPlane: function (offsetX, offsetY, rotation) {
  11923. var shape = new p2.Plane();
  11924. return this.addShape(shape, offsetX, offsetY, rotation);
  11925. },
  11926. /**
  11927. * Adds a Particle shape to this Body. You can control the offset from the center of the body and the rotation.
  11928. *
  11929. * @method Phaser.Physics.P2.Body#addParticle
  11930. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  11931. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  11932. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  11933. * @return {p2.Particle} The Particle shape that was added to the Body.
  11934. */
  11935. addParticle: function (offsetX, offsetY, rotation) {
  11936. var shape = new p2.Particle();
  11937. return this.addShape(shape, offsetX, offsetY, rotation);
  11938. },
  11939. /**
  11940. * Adds a Line shape to this Body.
  11941. * The line shape is along the x direction, and stretches from [-length/2, 0] to [length/2,0].
  11942. * You can control the offset from the center of the body and the rotation.
  11943. *
  11944. * @method Phaser.Physics.P2.Body#addLine
  11945. * @param {number} length - The length of this line (in pixels)
  11946. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  11947. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  11948. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  11949. * @return {p2.Line} The Line shape that was added to the Body.
  11950. */
  11951. addLine: function (length, offsetX, offsetY, rotation) {
  11952. var shape = new p2.Line(this.world.pxm(length));
  11953. return this.addShape(shape, offsetX, offsetY, rotation);
  11954. },
  11955. /**
  11956. * Adds a Capsule shape to this Body.
  11957. * You can control the offset from the center of the body and the rotation.
  11958. *
  11959. * @method Phaser.Physics.P2.Body#addCapsule
  11960. * @param {number} length - The distance between the end points in pixels.
  11961. * @param {number} radius - Radius of the capsule in radians.
  11962. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  11963. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  11964. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  11965. * @return {p2.Capsule} The Capsule shape that was added to the Body.
  11966. */
  11967. addCapsule: function (length, radius, offsetX, offsetY, rotation) {
  11968. var shape = new p2.Capsule(this.world.pxm(length), radius);
  11969. return this.addShape(shape, offsetX, offsetY, rotation);
  11970. },
  11971. /**
  11972. * Reads a polygon shape path, and assembles convex shapes from that and puts them at proper offset points. The shape must be simple and without holes.
  11973. * This function expects the x.y values to be given in pixels. If you want to provide them at p2 world scales then call Body.data.fromPolygon directly.
  11974. *
  11975. * @method Phaser.Physics.P2.Body#addPolygon
  11976. * @param {object} options - An object containing the build options:
  11977. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  11978. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  11979. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  11980. * @param {(number[]|...number)} points - An array of 2d vectors that form the convex or concave polygon.
  11981. * Either [[0,0], [0,1],...] or a flat array of numbers that will be interpreted as [x,y, x,y, ...],
  11982. * or the arguments passed can be flat x,y values e.g. `setPolygon(options, x,y, x,y, x,y, ...)` where `x` and `y` are numbers.
  11983. * @return {boolean} True on success, else false.
  11984. */
  11985. addPolygon: function (options, points) {
  11986. options = options || {};
  11987. points = Array.prototype.slice.call(arguments, 1);
  11988. var path = [];
  11989. // Did they pass in a single array of points?
  11990. if (points.length === 1 && Array.isArray(points[0]))
  11991. {
  11992. path = points[0].slice(0);
  11993. }
  11994. else if (Array.isArray(points[0]))
  11995. {
  11996. path = points[0].slice(0);
  11997. }
  11998. else if (typeof points[0] === 'number')
  11999. {
  12000. // We've a list of numbers
  12001. for (var i = 0, len = points.length; i < len; i += 2)
  12002. {
  12003. path.push([points[i], points[i + 1]]);
  12004. }
  12005. }
  12006. // top and tail
  12007. var idx = path.length - 1;
  12008. if (path[idx][0] === path[0][0] && path[idx][1] === path[0][1])
  12009. {
  12010. path.pop();
  12011. }
  12012. // Now process them into p2 values
  12013. for (var p = 0; p < path.length; p++)
  12014. {
  12015. path[p][0] = this.world.pxmi(path[p][0]);
  12016. path[p][1] = this.world.pxmi(path[p][1]);
  12017. }
  12018. var result = this.data.fromPolygon(path, options);
  12019. this.shapeChanged();
  12020. return result;
  12021. },
  12022. /**
  12023. * Remove a shape from the body. Will automatically update the mass properties and bounding radius.
  12024. *
  12025. * @method Phaser.Physics.P2.Body#removeShape
  12026. * @param {p2.Circle|p2.Rectangle|p2.Plane|p2.Line|p2.Particle} shape - The shape to remove from the body.
  12027. * @return {boolean} True if the shape was found and removed, else false.
  12028. */
  12029. removeShape: function (shape) {
  12030. return this.data.removeShape(shape);
  12031. },
  12032. /**
  12033. * Clears any previously set shapes. Then creates a new Circle shape and adds it to this Body.
  12034. *
  12035. * @method Phaser.Physics.P2.Body#setCircle
  12036. * @param {number} radius - The radius of this circle (in pixels)
  12037. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  12038. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  12039. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  12040. */
  12041. setCircle: function (radius, offsetX, offsetY, rotation) {
  12042. this.clearShapes();
  12043. return this.addCircle(radius, offsetX, offsetY, rotation);
  12044. },
  12045. /**
  12046. * Clears any previously set shapes. The creates a new Rectangle shape at the given size and offset, and adds it to this Body.
  12047. * If you wish to create a Rectangle to match the size of a Sprite or Image see Body.setRectangleFromSprite.
  12048. *
  12049. * @method Phaser.Physics.P2.Body#setRectangle
  12050. * @param {number} [width=16] - The width of the rectangle in pixels.
  12051. * @param {number} [height=16] - The height of the rectangle in pixels.
  12052. * @param {number} [offsetX=0] - Local horizontal offset of the shape relative to the body center of mass.
  12053. * @param {number} [offsetY=0] - Local vertical offset of the shape relative to the body center of mass.
  12054. * @param {number} [rotation=0] - Local rotation of the shape relative to the body center of mass, specified in radians.
  12055. * @return {p2.Rectangle} The Rectangle shape that was added to the Body.
  12056. */
  12057. setRectangle: function (width, height, offsetX, offsetY, rotation) {
  12058. if (typeof width === 'undefined') { width = 16; }
  12059. if (typeof height === 'undefined') { height = 16; }
  12060. this.clearShapes();
  12061. return this.addRectangle(width, height, offsetX, offsetY, rotation);
  12062. },
  12063. /**
  12064. * Clears any previously set shapes.
  12065. * Then creates a Rectangle shape sized to match the dimensions and orientation of the Sprite given.
  12066. * If no Sprite is given it defaults to using the parent of this Body.
  12067. *
  12068. * @method Phaser.Physics.P2.Body#setRectangleFromSprite
  12069. * @param {Phaser.Sprite|Phaser.Image} [sprite] - The Sprite on which the Rectangle will get its dimensions.
  12070. * @return {p2.Rectangle} The Rectangle shape that was added to the Body.
  12071. */
  12072. setRectangleFromSprite: function (sprite) {
  12073. if (typeof sprite === 'undefined') { sprite = this.sprite; }
  12074. this.clearShapes();
  12075. return this.addRectangle(sprite.width, sprite.height, 0, 0, sprite.rotation);
  12076. },
  12077. /**
  12078. * Adds the given Material to all Shapes that belong to this Body.
  12079. * If you only wish to apply it to a specific Shape in this Body then provide that as the 2nd parameter.
  12080. *
  12081. * @method Phaser.Physics.P2.Body#setMaterial
  12082. * @param {Phaser.Physics.P2.Material} material - The Material that will be applied.
  12083. * @param {p2.Shape} [shape] - An optional Shape. If not provided the Material will be added to all Shapes in this Body.
  12084. */
  12085. setMaterial: function (material, shape) {
  12086. if (typeof shape === 'undefined')
  12087. {
  12088. for (var i = this.data.shapes.length - 1; i >= 0; i--)
  12089. {
  12090. this.data.shapes[i].material = material;
  12091. }
  12092. }
  12093. else
  12094. {
  12095. shape.material = material;
  12096. }
  12097. },
  12098. /**
  12099. * Updates the debug draw if any body shapes change.
  12100. *
  12101. * @method Phaser.Physics.P2.Body#shapeChanged
  12102. */
  12103. shapeChanged: function() {
  12104. if (this.debugBody)
  12105. {
  12106. this.debugBody.draw();
  12107. }
  12108. },
  12109. /**
  12110. * Reads the shape data from a physics data file stored in the Game.Cache and adds it as a polygon to this Body.
  12111. * The shape data format is based on the custom phaser export in.
  12112. *
  12113. * @method Phaser.Physics.P2.Body#addPhaserPolygon
  12114. * @param {string} key - The key of the Physics Data file as stored in Game.Cache.
  12115. * @param {string} object - The key of the object within the Physics data file that you wish to load the shape data from.
  12116. */
  12117. addPhaserPolygon: function (key, object) {
  12118. var data = this.game.cache.getPhysicsData(key, object);
  12119. var createdFixtures = [];
  12120. // Cycle through the fixtures
  12121. for (var i = 0; i < data.length; i++)
  12122. {
  12123. var fixtureData = data[i];
  12124. var shapesOfFixture = this.addFixture(fixtureData);
  12125. // Always add to a group
  12126. createdFixtures[fixtureData.filter.group] = createdFixtures[fixtureData.filter.group] || [];
  12127. createdFixtures[fixtureData.filter.group] = createdFixtures[fixtureData.filter.group].concat(shapesOfFixture);
  12128. // if (unique) fixture key is provided
  12129. if (fixtureData.fixtureKey)
  12130. {
  12131. createdFixtures[fixtureData.fixtureKey] = shapesOfFixture;
  12132. }
  12133. }
  12134. this.data.aabbNeedsUpdate = true;
  12135. this.shapeChanged();
  12136. return createdFixtures;
  12137. },
  12138. /**
  12139. * Add a polygon fixture. This is used during #loadPhaserPolygon.
  12140. *
  12141. * @method Phaser.Physics.P2.Body#addFixture
  12142. * @param {string} fixtureData - The data for the fixture. It contains: isSensor, filter (collision) and the actual polygon shapes.
  12143. * @return {array} An array containing the generated shapes for the given polygon.
  12144. */
  12145. addFixture: function (fixtureData) {
  12146. var generatedShapes = [];
  12147. if (fixtureData.circle)
  12148. {
  12149. var shape = new p2.Circle(this.world.pxm(fixtureData.circle.radius));
  12150. shape.collisionGroup = fixtureData.filter.categoryBits;
  12151. shape.collisionMask = fixtureData.filter.maskBits;
  12152. shape.sensor = fixtureData.isSensor;
  12153. var offset = p2.vec2.create();
  12154. offset[0] = this.world.pxmi(fixtureData.circle.position[0] - this.sprite.width/2);
  12155. offset[1] = this.world.pxmi(fixtureData.circle.position[1] - this.sprite.height/2);
  12156. this.data.addShape(shape, offset);
  12157. generatedShapes.push(shape);
  12158. }
  12159. else
  12160. {
  12161. var polygons = fixtureData.polygons;
  12162. var cm = p2.vec2.create();
  12163. for (var i = 0; i < polygons.length; i++)
  12164. {
  12165. var shapes = polygons[i];
  12166. var vertices = [];
  12167. for (var s = 0; s < shapes.length; s += 2)
  12168. {
  12169. vertices.push([ this.world.pxmi(shapes[s]), this.world.pxmi(shapes[s + 1]) ]);
  12170. }
  12171. var shape = new p2.Convex(vertices);
  12172. // Move all vertices so its center of mass is in the local center of the convex
  12173. for (var j = 0; j !== shape.vertices.length; j++)
  12174. {
  12175. var v = shape.vertices[j];
  12176. p2.vec2.sub(v, v, shape.centerOfMass);
  12177. }
  12178. p2.vec2.scale(cm, shape.centerOfMass, 1);
  12179. cm[0] -= this.world.pxmi(this.sprite.width / 2);
  12180. cm[1] -= this.world.pxmi(this.sprite.height / 2);
  12181. shape.updateTriangles();
  12182. shape.updateCenterOfMass();
  12183. shape.updateBoundingRadius();
  12184. shape.collisionGroup = fixtureData.filter.categoryBits;
  12185. shape.collisionMask = fixtureData.filter.maskBits;
  12186. shape.sensor = fixtureData.isSensor;
  12187. this.data.addShape(shape, cm);
  12188. generatedShapes.push(shape);
  12189. }
  12190. }
  12191. return generatedShapes;
  12192. },
  12193. /**
  12194. * Reads the shape data from a physics data file stored in the Game.Cache and adds it as a polygon to this Body.
  12195. *
  12196. * @method Phaser.Physics.P2.Body#loadPolygon
  12197. * @param {string} key - The key of the Physics Data file as stored in Game.Cache.
  12198. * @param {string} object - The key of the object within the Physics data file that you wish to load the shape data from.
  12199. * @param {object} options - An object containing the build options. Note that this isn't used if the data file contains multiple shapes.
  12200. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  12201. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  12202. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  12203. * @return {boolean} True on success, else false.
  12204. */
  12205. loadPolygon: function (key, object, options) {
  12206. var data = this.game.cache.getPhysicsData(key, object);
  12207. if (data.length === 1)
  12208. {
  12209. var temp = [];
  12210. var localData = data[data.length - 1];
  12211. // We've a list of numbers
  12212. for (var i = 0, len = localData.shape.length; i < len; i += 2)
  12213. {
  12214. temp.push([localData.shape[i], localData.shape[i + 1]]);
  12215. }
  12216. return this.addPolygon(options, temp);
  12217. }
  12218. else
  12219. {
  12220. // We've multiple Convex shapes, they should be CCW automatically
  12221. var cm = p2.vec2.create();
  12222. for (var i = 0; i < data.length; i++)
  12223. {
  12224. var vertices = [];
  12225. for (var s = 0; s < data[i].shape.length; s += 2)
  12226. {
  12227. vertices.push([ this.world.pxmi(data[i].shape[s]), this.world.pxmi(data[i].shape[s + 1]) ]);
  12228. }
  12229. var c = new p2.Convex(vertices);
  12230. // Move all vertices so its center of mass is in the local center of the convex
  12231. for (var j = 0; j !== c.vertices.length; j++)
  12232. {
  12233. var v = c.vertices[j];
  12234. p2.vec2.sub(v, v, c.centerOfMass);
  12235. }
  12236. p2.vec2.scale(cm, c.centerOfMass, 1);
  12237. cm[0] -= this.world.pxmi(this.sprite.width / 2);
  12238. cm[1] -= this.world.pxmi(this.sprite.height / 2);
  12239. c.updateTriangles();
  12240. c.updateCenterOfMass();
  12241. c.updateBoundingRadius();
  12242. this.data.addShape(c, cm);
  12243. }
  12244. this.data.aabbNeedsUpdate = true;
  12245. this.shapeChanged();
  12246. return true;
  12247. }
  12248. return false;
  12249. },
  12250. /**
  12251. * Reads the physics data from a physics data file stored in the Game.Cache.
  12252. * It will add the shape data to this Body, as well as set the density (mass), friction and bounce (restitution) values.
  12253. *
  12254. * @method Phaser.Physics.P2.Body#loadPolygon
  12255. * @param {string} key - The key of the Physics Data file as stored in Game.Cache.
  12256. * @param {string} object - The key of the object within the Physics data file that you wish to load the shape data from.
  12257. * @param {object} options - An object containing the build options:
  12258. * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices.
  12259. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself.
  12260. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points.
  12261. * @return {boolean} True on success, else false.
  12262. */
  12263. loadData: function (key, object, options) {
  12264. var data = this.game.cache.getPhysicsData(key, object);
  12265. if (data && data.shape)
  12266. {
  12267. this.mass = data.density;
  12268. this.loadPolygon(key, object, options);
  12269. // TODO set friction + bounce here
  12270. }
  12271. }
  12272. };
  12273. Phaser.Physics.P2.Body.prototype.constructor = Phaser.Physics.P2.Body;
  12274. /**
  12275. * Dynamic body.
  12276. * @property DYNAMIC
  12277. * @type {Number}
  12278. * @static
  12279. */
  12280. Phaser.Physics.P2.Body.DYNAMIC = 1;
  12281. /**
  12282. * Static body.
  12283. * @property STATIC
  12284. * @type {Number}
  12285. * @static
  12286. */
  12287. Phaser.Physics.P2.Body.STATIC = 2;
  12288. /**
  12289. * Kinematic body.
  12290. * @property KINEMATIC
  12291. * @type {Number}
  12292. * @static
  12293. */
  12294. Phaser.Physics.P2.Body.KINEMATIC = 4;
  12295. /**
  12296. * @name Phaser.Physics.P2.Body#static
  12297. * @property {boolean} static - Returns true if the Body is static. Setting Body.static to 'false' will make it dynamic.
  12298. */
  12299. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "static", {
  12300. get: function () {
  12301. return (this.data.motionState === Phaser.Physics.P2.Body.STATIC);
  12302. },
  12303. set: function (value) {
  12304. if (value && this.data.motionState !== Phaser.Physics.P2.Body.STATIC)
  12305. {
  12306. this.data.motionState = Phaser.Physics.P2.Body.STATIC;
  12307. this.mass = 0;
  12308. }
  12309. else if (!value && this.data.motionState === Phaser.Physics.P2.Body.STATIC)
  12310. {
  12311. this.data.motionState = Phaser.Physics.P2.Body.DYNAMIC;
  12312. if (this.mass === 0)
  12313. {
  12314. this.mass = 1;
  12315. }
  12316. }
  12317. }
  12318. });
  12319. /**
  12320. * @name Phaser.Physics.P2.Body#dynamic
  12321. * @property {boolean} dynamic - Returns true if the Body is dynamic. Setting Body.dynamic to 'false' will make it static.
  12322. */
  12323. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "dynamic", {
  12324. get: function () {
  12325. return (this.data.motionState === Phaser.Physics.P2.Body.DYNAMIC);
  12326. },
  12327. set: function (value) {
  12328. if (value && this.data.motionState !== Phaser.Physics.P2.Body.DYNAMIC)
  12329. {
  12330. this.data.motionState = Phaser.Physics.P2.Body.DYNAMIC;
  12331. if (this.mass === 0)
  12332. {
  12333. this.mass = 1;
  12334. }
  12335. }
  12336. else if (!value && this.data.motionState === Phaser.Physics.P2.Body.DYNAMIC)
  12337. {
  12338. this.data.motionState = Phaser.Physics.P2.Body.STATIC;
  12339. this.mass = 0;
  12340. }
  12341. }
  12342. });
  12343. /**
  12344. * @name Phaser.Physics.P2.Body#kinematic
  12345. * @property {boolean} kinematic - Returns true if the Body is kinematic. Setting Body.kinematic to 'false' will make it static.
  12346. */
  12347. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "kinematic", {
  12348. get: function () {
  12349. return (this.data.motionState === Phaser.Physics.P2.Body.KINEMATIC);
  12350. },
  12351. set: function (value) {
  12352. if (value && this.data.motionState !== Phaser.Physics.P2.Body.KINEMATIC)
  12353. {
  12354. this.data.motionState = Phaser.Physics.P2.Body.KINEMATIC;
  12355. this.mass = 4;
  12356. }
  12357. else if (!value && this.data.motionState === Phaser.Physics.P2.Body.KINEMATIC)
  12358. {
  12359. this.data.motionState = Phaser.Physics.P2.Body.STATIC;
  12360. this.mass = 0;
  12361. }
  12362. }
  12363. });
  12364. /**
  12365. * @name Phaser.Physics.P2.Body#allowSleep
  12366. * @property {boolean} allowSleep -
  12367. */
  12368. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "allowSleep", {
  12369. get: function () {
  12370. return this.data.allowSleep;
  12371. },
  12372. set: function (value) {
  12373. if (value !== this.data.allowSleep)
  12374. {
  12375. this.data.allowSleep = value;
  12376. }
  12377. }
  12378. });
  12379. /**
  12380. * The angle of the Body in degrees from its original orientation. Values from 0 to 180 represent clockwise rotation; values from 0 to -180 represent counterclockwise rotation.
  12381. * Values outside this range are added to or subtracted from 360 to obtain a value within the range. For example, the statement Body.angle = 450 is the same as Body.angle = 90.
  12382. * If you wish to work in radians instead of degrees use the property Body.rotation instead. Working in radians is faster as it doesn't have to convert values.
  12383. *
  12384. * @name Phaser.Physics.P2.Body#angle
  12385. * @property {number} angle - The angle of this Body in degrees.
  12386. */
  12387. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angle", {
  12388. get: function() {
  12389. return Phaser.Math.wrapAngle(Phaser.Math.radToDeg(this.data.angle));
  12390. },
  12391. set: function(value) {
  12392. this.data.angle = Phaser.Math.degToRad(Phaser.Math.wrapAngle(value));
  12393. }
  12394. });
  12395. /**
  12396. * Damping is specified as a value between 0 and 1, which is the proportion of velocity lost per second.
  12397. * @name Phaser.Physics.P2.Body#angularDamping
  12398. * @property {number} angularDamping - The angular damping acting acting on the body.
  12399. */
  12400. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angularDamping", {
  12401. get: function () {
  12402. return this.data.angularDamping;
  12403. },
  12404. set: function (value) {
  12405. this.data.angularDamping = value;
  12406. }
  12407. });
  12408. /**
  12409. * @name Phaser.Physics.P2.Body#angularForce
  12410. * @property {number} angularForce - The angular force acting on the body.
  12411. */
  12412. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angularForce", {
  12413. get: function () {
  12414. return this.data.angularForce;
  12415. },
  12416. set: function (value) {
  12417. this.data.angularForce = value;
  12418. }
  12419. });
  12420. /**
  12421. * @name Phaser.Physics.P2.Body#angularVelocity
  12422. * @property {number} angularVelocity - The angular velocity of the body.
  12423. */
  12424. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "angularVelocity", {
  12425. get: function () {
  12426. return this.data.angularVelocity;
  12427. },
  12428. set: function (value) {
  12429. this.data.angularVelocity = value;
  12430. }
  12431. });
  12432. /**
  12433. * Damping is specified as a value between 0 and 1, which is the proportion of velocity lost per second.
  12434. * @name Phaser.Physics.P2.Body#damping
  12435. * @property {number} damping - The linear damping acting on the body in the velocity direction.
  12436. */
  12437. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "damping", {
  12438. get: function () {
  12439. return this.data.damping;
  12440. },
  12441. set: function (value) {
  12442. this.data.damping = value;
  12443. }
  12444. });
  12445. /**
  12446. * @name Phaser.Physics.P2.Body#fixedRotation
  12447. * @property {boolean} fixedRotation -
  12448. */
  12449. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "fixedRotation", {
  12450. get: function () {
  12451. return this.data.fixedRotation;
  12452. },
  12453. set: function (value) {
  12454. if (value !== this.data.fixedRotation)
  12455. {
  12456. this.data.fixedRotation = value;
  12457. }
  12458. }
  12459. });
  12460. /**
  12461. * @name Phaser.Physics.P2.Body#inertia
  12462. * @property {number} inertia - The inertia of the body around the Z axis..
  12463. */
  12464. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "inertia", {
  12465. get: function () {
  12466. return this.data.inertia;
  12467. },
  12468. set: function (value) {
  12469. this.data.inertia = value;
  12470. }
  12471. });
  12472. /**
  12473. * @name Phaser.Physics.P2.Body#mass
  12474. * @property {number} mass -
  12475. */
  12476. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "mass", {
  12477. get: function () {
  12478. return this.data.mass;
  12479. },
  12480. set: function (value) {
  12481. if (value !== this.data.mass)
  12482. {
  12483. this.data.mass = value;
  12484. this.data.updateMassProperties();
  12485. }
  12486. }
  12487. });
  12488. /**
  12489. * @name Phaser.Physics.P2.Body#motionState
  12490. * @property {number} motionState - The type of motion this body has. Should be one of: Body.STATIC (the body does not move), Body.DYNAMIC (body can move and respond to collisions) and Body.KINEMATIC (only moves according to its .velocity).
  12491. */
  12492. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "motionState", {
  12493. get: function () {
  12494. return this.data.motionState;
  12495. },
  12496. set: function (value) {
  12497. if (value !== this.data.motionState)
  12498. {
  12499. this.data.motionState = value;
  12500. }
  12501. }
  12502. });
  12503. /**
  12504. * The angle of the Body in radians.
  12505. * If you wish to work in degrees instead of radians use the Body.angle property instead. Working in radians is faster as it doesn't have to convert values.
  12506. *
  12507. * @name Phaser.Physics.P2.Body#rotation
  12508. * @property {number} rotation - The angle of this Body in radians.
  12509. */
  12510. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "rotation", {
  12511. get: function() {
  12512. return this.data.angle;
  12513. },
  12514. set: function(value) {
  12515. this.data.angle = value;
  12516. }
  12517. });
  12518. /**
  12519. * @name Phaser.Physics.P2.Body#sleepSpeedLimit
  12520. * @property {number} sleepSpeedLimit - .
  12521. */
  12522. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "sleepSpeedLimit", {
  12523. get: function () {
  12524. return this.data.sleepSpeedLimit;
  12525. },
  12526. set: function (value) {
  12527. this.data.sleepSpeedLimit = value;
  12528. }
  12529. });
  12530. /**
  12531. * @name Phaser.Physics.P2.Body#x
  12532. * @property {number} x - The x coordinate of this Body.
  12533. */
  12534. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "x", {
  12535. get: function () {
  12536. return this.world.mpxi(this.data.position[0]);
  12537. },
  12538. set: function (value) {
  12539. this.data.position[0] = this.world.pxmi(value);
  12540. }
  12541. });
  12542. /**
  12543. * @name Phaser.Physics.P2.Body#y
  12544. * @property {number} y - The y coordinate of this Body.
  12545. */
  12546. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "y", {
  12547. get: function () {
  12548. return this.world.mpxi(this.data.position[1]);
  12549. },
  12550. set: function (value) {
  12551. this.data.position[1] = this.world.pxmi(value);
  12552. }
  12553. });
  12554. /**
  12555. * @name Phaser.Physics.P2.Body#id
  12556. * @property {number} id - The Body ID. Each Body that has been added to the World has a unique ID.
  12557. * @readonly
  12558. */
  12559. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "id", {
  12560. get: function () {
  12561. return this.data.id;
  12562. }
  12563. });
  12564. /**
  12565. * @name Phaser.Physics.P2.Body#debug
  12566. * @property {boolean} debug - Enable or disable debug drawing of this body
  12567. */
  12568. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "debug", {
  12569. get: function () {
  12570. return (!this.debugBody);
  12571. },
  12572. set: function (value) {
  12573. if (value && !this.debugBody)
  12574. {
  12575. // This will be added to the global space
  12576. this.debugBody = new Phaser.Physics.P2.BodyDebug(this.game, this.data);
  12577. }
  12578. else if (!value && this.debugBody)
  12579. {
  12580. this.debugBody.destroy();
  12581. this.debugBody = null;
  12582. }
  12583. }
  12584. });
  12585. /**
  12586. * A Body can be set to collide against the World bounds automatically if this is set to true. Otherwise it will leave the World.
  12587. * Note that this only applies if your World has bounds! The response to the collision should be managed via CollisionMaterials.
  12588. * @name Phaser.Physics.P2.Body#collideWorldBounds
  12589. * @property {boolean} collideWorldBounds - Should the Body collide with the World bounds?
  12590. */
  12591. Object.defineProperty(Phaser.Physics.P2.Body.prototype, "collideWorldBounds", {
  12592. get: function () {
  12593. return this._collideWorldBounds;
  12594. },
  12595. set: function (value) {
  12596. if (value && !this._collideWorldBounds)
  12597. {
  12598. this._collideWorldBounds = true;
  12599. this.updateCollisionMask();
  12600. }
  12601. else if (!value && this._collideWorldBounds)
  12602. {
  12603. this._collideWorldBounds = false;
  12604. this.updateCollisionMask();
  12605. }
  12606. }
  12607. });
  12608. /**
  12609. * @author George https://github.com/georgiee
  12610. * @author Richard Davey <rich@photonstorm.com>
  12611. * @copyright 2014 Photon Storm Ltd.
  12612. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  12613. */
  12614. /**
  12615. * Draws a P2 Body to a Graphics instance for visual debugging.
  12616. * Needless to say, for every body you enable debug drawing on, you are adding processor and graphical overhead.
  12617. * So use sparingly and rarely (if ever) in production code.
  12618. *
  12619. * @class Phaser.Physics.P2.BodyDebug
  12620. * @classdesc Physics Body Debug Constructor
  12621. * @constructor
  12622. * @extends Phaser.Group
  12623. * @param {Phaser.Game} game - Game reference to the currently running game.
  12624. * @param {Phaser.Physics.P2.Body} body - The P2 Body to display debug data for.
  12625. * @param {object} settings - Settings object.
  12626. */
  12627. Phaser.Physics.P2.BodyDebug = function(game, body, settings) {
  12628. Phaser.Group.call(this, game);
  12629. /**
  12630. * @property {object} defaultSettings - Default debug settings.
  12631. * @private
  12632. */
  12633. var defaultSettings = {
  12634. pixelsPerLengthUnit: 20,
  12635. debugPolygons: false,
  12636. lineWidth: 1,
  12637. alpha: 0.5
  12638. };
  12639. this.settings = Phaser.Utils.extend(defaultSettings, settings);
  12640. /**
  12641. * @property {number} ppu - Pixels per Length Unit.
  12642. */
  12643. this.ppu = this.settings.pixelsPerLengthUnit;
  12644. this.ppu = -1 * this.ppu;
  12645. /**
  12646. * @property {Phaser.Physics.P2.Body} body - The P2 Body to display debug data for.
  12647. */
  12648. this.body = body;
  12649. /**
  12650. * @property {Phaser.Graphics} canvas - The canvas to render the debug info to.
  12651. */
  12652. this.canvas = new Phaser.Graphics(game);
  12653. this.canvas.alpha = this.settings.alpha;
  12654. this.add(this.canvas);
  12655. this.draw();
  12656. };
  12657. Phaser.Physics.P2.BodyDebug.prototype = Object.create(Phaser.Group.prototype);
  12658. Phaser.Physics.P2.BodyDebug.prototype.constructor = Phaser.Physics.P2.BodyDebug;
  12659. Phaser.Utils.extend(Phaser.Physics.P2.BodyDebug.prototype, {
  12660. /**
  12661. * Core update.
  12662. *
  12663. * @method Phaser.Physics.P2.BodyDebug#update
  12664. */
  12665. update: function() {
  12666. this.updateSpriteTransform();
  12667. },
  12668. /**
  12669. * Core update.
  12670. *
  12671. * @method Phaser.Physics.P2.BodyDebug#updateSpriteTransform
  12672. */
  12673. updateSpriteTransform: function() {
  12674. this.position.x = this.body.position[0] * this.ppu;
  12675. this.position.y = this.body.position[1] * this.ppu;
  12676. return this.rotation = this.body.angle;
  12677. },
  12678. /**
  12679. * Draws the P2 shapes to the Graphics object.
  12680. *
  12681. * @method Phaser.Physics.P2.BodyDebug#draw
  12682. */
  12683. draw: function() {
  12684. var angle, child, color, i, j, lineColor, lw, obj, offset, sprite, v, verts, vrot, _j, _ref1;
  12685. obj = this.body;
  12686. sprite = this.canvas;
  12687. sprite.clear();
  12688. color = parseInt(this.randomPastelHex(), 16);
  12689. lineColor = 0xff0000;
  12690. lw = this.lineWidth;
  12691. if (obj instanceof p2.Body && obj.shapes.length)
  12692. {
  12693. var l = obj.shapes.length;
  12694. i = 0;
  12695. while (i !== l)
  12696. {
  12697. child = obj.shapes[i];
  12698. offset = obj.shapeOffsets[i];
  12699. angle = obj.shapeAngles[i];
  12700. offset = offset || 0;
  12701. angle = angle || 0;
  12702. if (child instanceof p2.Circle)
  12703. {
  12704. this.drawCircle(sprite, offset[0] * this.ppu, offset[1] * this.ppu, angle, child.radius * this.ppu, color, lw);
  12705. }
  12706. else if (child instanceof p2.Convex)
  12707. {
  12708. verts = [];
  12709. vrot = p2.vec2.create();
  12710. for (j = _j = 0, _ref1 = child.vertices.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; j = 0 <= _ref1 ? ++_j : --_j)
  12711. {
  12712. v = child.vertices[j];
  12713. p2.vec2.rotate(vrot, v, angle);
  12714. verts.push([(vrot[0] + offset[0]) * this.ppu, -(vrot[1] + offset[1]) * this.ppu]);
  12715. }
  12716. this.drawConvex(sprite, verts, child.triangles, lineColor, color, lw, this.settings.debugPolygons, [offset[0] * this.ppu, -offset[1] * this.ppu]);
  12717. }
  12718. else if (child instanceof p2.Plane)
  12719. {
  12720. this.drawPlane(sprite, offset[0] * this.ppu, -offset[1] * this.ppu, color, lineColor, lw * 5, lw * 10, lw * 10, this.ppu * 100, angle);
  12721. }
  12722. else if (child instanceof p2.Line)
  12723. {
  12724. this.drawLine(sprite, child.length * this.ppu, lineColor, lw);
  12725. }
  12726. else if (child instanceof p2.Rectangle)
  12727. {
  12728. this.drawRectangle(sprite, offset[0] * this.ppu, -offset[1] * this.ppu, angle, child.width * this.ppu, child.height * this.ppu, lineColor, color, lw);
  12729. }
  12730. i++;
  12731. }
  12732. }
  12733. },
  12734. /**
  12735. * Draws the P2 shapes to the Graphics object.
  12736. *
  12737. * @method Phaser.Physics.P2.BodyDebug#draw
  12738. */
  12739. drawRectangle: function(g, x, y, angle, w, h, color, fillColor, lineWidth) {
  12740. if (typeof lineWidth === 'undefined') { lineWidth = 1; }
  12741. if (typeof color === 'undefined') { color = 0x000000; }
  12742. g.lineStyle(lineWidth, color, 1);
  12743. g.beginFill(fillColor);
  12744. g.drawRect(x - w / 2, y - h / 2, w, h);
  12745. },
  12746. /**
  12747. * Draws a P2 Circle shape.
  12748. *
  12749. * @method Phaser.Physics.P2.BodyDebug#drawCircle
  12750. */
  12751. drawCircle: function(g, x, y, angle, radius, color, lineWidth) {
  12752. if (typeof lineWidth === 'undefined') { lineWidth = 1; }
  12753. if (typeof color === 'undefined') { color = 0xffffff; }
  12754. g.lineStyle(lineWidth, 0x000000, 1);
  12755. g.beginFill(color, 1.0);
  12756. g.drawCircle(x, y, -radius);
  12757. g.endFill();
  12758. g.moveTo(x, y);
  12759. g.lineTo(x + radius * Math.cos(-angle), y + radius * Math.sin(-angle));
  12760. },
  12761. /**
  12762. * Draws a P2 Line shape.
  12763. *
  12764. * @method Phaser.Physics.P2.BodyDebug#drawCircle
  12765. */
  12766. drawLine: function(g, len, color, lineWidth) {
  12767. if (typeof lineWidth === 'undefined') { lineWidth = 1; }
  12768. if (typeof color === 'undefined') { color = 0x000000; }
  12769. g.lineStyle(lineWidth * 5, color, 1);
  12770. g.moveTo(-len / 2, 0);
  12771. g.lineTo(len / 2, 0);
  12772. },
  12773. /**
  12774. * Draws a P2 Convex shape.
  12775. *
  12776. * @method Phaser.Physics.P2.BodyDebug#drawConvex
  12777. */
  12778. drawConvex: function(g, verts, triangles, color, fillColor, lineWidth, debug, offset) {
  12779. var colors, i, v, v0, v1, x, x0, x1, y, y0, y1;
  12780. if (typeof lineWidth === 'undefined') { lineWidth = 1; }
  12781. if (typeof color === 'undefined') { color = 0x000000; }
  12782. if (!debug)
  12783. {
  12784. g.lineStyle(lineWidth, color, 1);
  12785. g.beginFill(fillColor);
  12786. i = 0;
  12787. while (i !== verts.length)
  12788. {
  12789. v = verts[i];
  12790. x = v[0];
  12791. y = v[1];
  12792. if (i === 0)
  12793. {
  12794. g.moveTo(x, -y);
  12795. }
  12796. else
  12797. {
  12798. g.lineTo(x, -y);
  12799. }
  12800. i++;
  12801. }
  12802. g.endFill();
  12803. if (verts.length > 2)
  12804. {
  12805. g.moveTo(verts[verts.length - 1][0], -verts[verts.length - 1][1]);
  12806. return g.lineTo(verts[0][0], -verts[0][1]);
  12807. }
  12808. }
  12809. else
  12810. {
  12811. colors = [0xff0000, 0x00ff00, 0x0000ff];
  12812. i = 0;
  12813. while (i !== verts.length + 1)
  12814. {
  12815. v0 = verts[i % verts.length];
  12816. v1 = verts[(i + 1) % verts.length];
  12817. x0 = v0[0];
  12818. y0 = v0[1];
  12819. x1 = v1[0];
  12820. y1 = v1[1];
  12821. g.lineStyle(lineWidth, colors[i % colors.length], 1);
  12822. g.moveTo(x0, -y0);
  12823. g.lineTo(x1, -y1);
  12824. g.drawCircle(x0, -y0, lineWidth * 2);
  12825. i++;
  12826. }
  12827. g.lineStyle(lineWidth, 0x000000, 1);
  12828. return g.drawCircle(offset[0], offset[1], lineWidth * 2);
  12829. }
  12830. },
  12831. /**
  12832. * Draws a P2 Path.
  12833. *
  12834. * @method Phaser.Physics.P2.BodyDebug#drawPath
  12835. */
  12836. drawPath: function(g, path, color, fillColor, lineWidth) {
  12837. var area, i, lastx, lasty, p1x, p1y, p2x, p2y, p3x, p3y, v, x, y;
  12838. if (typeof lineWidth === 'undefined') { lineWidth = 1; }
  12839. if (typeof color === 'undefined') { color = 0x000000; }
  12840. g.lineStyle(lineWidth, color, 1);
  12841. if (typeof fillColor === "number")
  12842. {
  12843. g.beginFill(fillColor);
  12844. }
  12845. lastx = null;
  12846. lasty = null;
  12847. i = 0;
  12848. while (i < path.length)
  12849. {
  12850. v = path[i];
  12851. x = v[0];
  12852. y = v[1];
  12853. if (x !== lastx || y !== lasty)
  12854. {
  12855. if (i === 0)
  12856. {
  12857. g.moveTo(x, y);
  12858. }
  12859. else
  12860. {
  12861. p1x = lastx;
  12862. p1y = lasty;
  12863. p2x = x;
  12864. p2y = y;
  12865. p3x = path[(i + 1) % path.length][0];
  12866. p3y = path[(i + 1) % path.length][1];
  12867. area = ((p2x - p1x) * (p3y - p1y)) - ((p3x - p1x) * (p2y - p1y));
  12868. if (area !== 0)
  12869. {
  12870. g.lineTo(x, y);
  12871. }
  12872. }
  12873. lastx = x;
  12874. lasty = y;
  12875. }
  12876. i++;
  12877. }
  12878. if (typeof fillColor === "number")
  12879. {
  12880. g.endFill();
  12881. }
  12882. if (path.length > 2 && typeof fillColor === "number")
  12883. {
  12884. g.moveTo(path[path.length - 1][0], path[path.length - 1][1]);
  12885. g.lineTo(path[0][0], path[0][1]);
  12886. }
  12887. },
  12888. /**
  12889. * Draws a P2 Plane shape.
  12890. *
  12891. * @method Phaser.Physics.P2.BodyDebug#drawPlane
  12892. */
  12893. drawPlane: function(g, x0, x1, color, lineColor, lineWidth, diagMargin, diagSize, maxLength, angle) {
  12894. var max, xd, yd;
  12895. if (typeof lineWidth === 'undefined') { lineWidth = 1; }
  12896. if (typeof color === 'undefined') { color = 0xffffff; }
  12897. g.lineStyle(lineWidth, lineColor, 11);
  12898. g.beginFill(color);
  12899. max = maxLength;
  12900. g.moveTo(x0, -x1);
  12901. xd = x0 + Math.cos(angle) * this.game.width;
  12902. yd = x1 + Math.sin(angle) * this.game.height;
  12903. g.lineTo(xd, -yd);
  12904. g.moveTo(x0, -x1);
  12905. xd = x0 + Math.cos(angle) * -this.game.width;
  12906. yd = x1 + Math.sin(angle) * -this.game.height;
  12907. g.lineTo(xd, -yd);
  12908. },
  12909. /**
  12910. * Picks a random pastel color.
  12911. *
  12912. * @method Phaser.Physics.P2.BodyDebug#randomPastelHex
  12913. */
  12914. randomPastelHex: function() {
  12915. var blue, green, mix, red;
  12916. mix = [255, 255, 255];
  12917. red = Math.floor(Math.random() * 256);
  12918. green = Math.floor(Math.random() * 256);
  12919. blue = Math.floor(Math.random() * 256);
  12920. red = Math.floor((red + 3 * mix[0]) / 4);
  12921. green = Math.floor((green + 3 * mix[1]) / 4);
  12922. blue = Math.floor((blue + 3 * mix[2]) / 4);
  12923. return this.rgbToHex(red, green, blue);
  12924. },
  12925. /**
  12926. * Converts from RGB to Hex.
  12927. *
  12928. * @method Phaser.Physics.P2.BodyDebug#rgbToHex
  12929. */
  12930. rgbToHex: function(r, g, b) {
  12931. return this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b);
  12932. },
  12933. /**
  12934. * Component to hex conversion.
  12935. *
  12936. * @method Phaser.Physics.P2.BodyDebug#componentToHex
  12937. */
  12938. componentToHex: function(c) {
  12939. var hex;
  12940. hex = c.toString(16);
  12941. if (hex.len === 2)
  12942. {
  12943. return hex;
  12944. }
  12945. else
  12946. {
  12947. return hex + '0';
  12948. }
  12949. }
  12950. });
  12951. /**
  12952. * @author Richard Davey <rich@photonstorm.com>
  12953. * @copyright 2014 Photon Storm Ltd.
  12954. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  12955. */
  12956. /**
  12957. * Creates a spring, connecting two bodies. A spring can have a resting length, a stiffness and damping.
  12958. *
  12959. * @class Phaser.Physics.P2.Spring
  12960. * @classdesc Physics Spring Constructor
  12961. * @constructor
  12962. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  12963. * @param {p2.Body} bodyA - First connected body.
  12964. * @param {p2.Body} bodyB - Second connected body.
  12965. * @param {number} [restLength=1] - Rest length of the spring. A number > 0.
  12966. * @param {number} [stiffness=100] - Stiffness of the spring. A number >= 0.
  12967. * @param {number} [damping=1] - Damping of the spring. A number >= 0.
  12968. * @param {Array} [worldA] - Where to hook the spring to body A in world coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  12969. * @param {Array} [worldB] - Where to hook the spring to body B in world coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  12970. * @param {Array} [localA] - Where to hook the spring to body A in local body coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  12971. * @param {Array} [localB] - Where to hook the spring to body B in local body coordinates. This value is an array with 2 elements matching x and y, i.e: [32, 32].
  12972. */
  12973. Phaser.Physics.P2.Spring = function (world, bodyA, bodyB, restLength, stiffness, damping, worldA, worldB, localA, localB) {
  12974. /**
  12975. * @property {Phaser.Game} game - Local reference to game.
  12976. */
  12977. this.game = world.game;
  12978. /**
  12979. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  12980. */
  12981. this.world = world;
  12982. if (typeof restLength === 'undefined') { restLength = 1; }
  12983. if (typeof stiffness === 'undefined') { stiffness = 100; }
  12984. if (typeof damping === 'undefined') { damping = 1; }
  12985. restLength = world.pxm(restLength);
  12986. var options = {
  12987. restLength: restLength,
  12988. stiffness: stiffness,
  12989. damping: damping
  12990. };
  12991. if (typeof worldA !== 'undefined' && worldA !== null)
  12992. {
  12993. options.worldAnchorA = [ world.pxm(worldA[0]), world.pxm(worldA[1]) ];
  12994. }
  12995. if (typeof worldB !== 'undefined' && worldB !== null)
  12996. {
  12997. options.worldAnchorB = [ world.pxm(worldB[0]), world.pxm(worldB[1]) ];
  12998. }
  12999. if (typeof localA !== 'undefined' && localA !== null)
  13000. {
  13001. options.localAnchorA = [ world.pxm(localA[0]), world.pxm(localA[1]) ];
  13002. }
  13003. if (typeof localB !== 'undefined' && localB !== null)
  13004. {
  13005. options.localAnchorB = [ world.pxm(localB[0]), world.pxm(localB[1]) ];
  13006. }
  13007. p2.Spring.call(this, bodyA, bodyB, options);
  13008. };
  13009. Phaser.Physics.P2.Spring.prototype = Object.create(p2.Spring.prototype);
  13010. Phaser.Physics.P2.Spring.prototype.constructor = Phaser.Physics.P2.Spring;
  13011. /**
  13012. * @author Richard Davey <rich@photonstorm.com>
  13013. * @copyright 2014 Photon Storm Ltd.
  13014. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13015. */
  13016. /**
  13017. * \o/ ~ "Because I'm a Material girl"
  13018. *
  13019. * @class Phaser.Physics.P2.Material
  13020. * @classdesc Physics Material Constructor
  13021. * @constructor
  13022. */
  13023. Phaser.Physics.P2.Material = function (name) {
  13024. /**
  13025. * @property {string} name - The user defined name given to this Material.
  13026. * @default
  13027. */
  13028. this.name = name;
  13029. p2.Material.call(this);
  13030. };
  13031. Phaser.Physics.P2.Material.prototype = Object.create(p2.Material.prototype);
  13032. Phaser.Physics.P2.Material.prototype.constructor = Phaser.Physics.P2.Material;
  13033. /**
  13034. * @author Richard Davey <rich@photonstorm.com>
  13035. * @copyright 2014 Photon Storm Ltd.
  13036. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13037. */
  13038. /**
  13039. * Defines a physics material
  13040. *
  13041. * @class Phaser.Physics.P2.ContactMaterial
  13042. * @classdesc Physics ContactMaterial Constructor
  13043. * @constructor
  13044. * @param {Phaser.Physics.P2.Material} materialA
  13045. * @param {Phaser.Physics.P2.Material} materialB
  13046. * @param {object} [options]
  13047. */
  13048. Phaser.Physics.P2.ContactMaterial = function (materialA, materialB, options) {
  13049. /**
  13050. * @property {number} id - The contact material identifier.
  13051. */
  13052. /**
  13053. * @property {Phaser.Physics.P2.Material} materialA - First material participating in the contact material.
  13054. */
  13055. /**
  13056. * @property {Phaser.Physics.P2.Material} materialB - First second participating in the contact material.
  13057. */
  13058. /**
  13059. * @property {number} [friction=0.3] - Friction to use in the contact of these two materials.
  13060. */
  13061. /**
  13062. * @property {number} [restitution=0.0] - Restitution to use in the contact of these two materials.
  13063. */
  13064. /**
  13065. * @property {number} [stiffness=1e7] - Stiffness of the resulting ContactEquation that this ContactMaterial generate.
  13066. */
  13067. /**
  13068. * @property {number} [relaxation=3] - Relaxation of the resulting ContactEquation that this ContactMaterial generate.
  13069. */
  13070. /**
  13071. * @property {number} [frictionStiffness=1e7] - Stiffness of the resulting FrictionEquation that this ContactMaterial generate.
  13072. */
  13073. /**
  13074. * @property {number} [frictionRelaxation=3] - Relaxation of the resulting FrictionEquation that this ContactMaterial generate.
  13075. */
  13076. /**
  13077. * @property {number} [surfaceVelocity=0] - Will add surface velocity to this material. If bodyA rests on top if bodyB, and the surface velocity is positive, bodyA will slide to the right.
  13078. */
  13079. p2.ContactMaterial.call(this, materialA, materialB, options);
  13080. };
  13081. Phaser.Physics.P2.ContactMaterial.prototype = Object.create(p2.ContactMaterial.prototype);
  13082. Phaser.Physics.P2.ContactMaterial.prototype.constructor = Phaser.Physics.P2.ContactMaterial;
  13083. /**
  13084. * @author Richard Davey <rich@photonstorm.com>
  13085. * @copyright 2014 Photon Storm Ltd.
  13086. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13087. */
  13088. /**
  13089. * Collision Group
  13090. *
  13091. * @class Phaser.Physics.P2.CollisionGroup
  13092. * @classdesc Physics Collision Group Constructor
  13093. * @constructor
  13094. */
  13095. Phaser.Physics.P2.CollisionGroup = function (bitmask) {
  13096. /**
  13097. * @property {number} mask - The CollisionGroup bitmask.
  13098. */
  13099. this.mask = bitmask;
  13100. };
  13101. /**
  13102. * @author Richard Davey <rich@photonstorm.com>
  13103. * @copyright 2014 Photon Storm Ltd.
  13104. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13105. */
  13106. /**
  13107. * A constraint that tries to keep the distance between two bodies constant.
  13108. *
  13109. * @class Phaser.Physics.P2.DistanceConstraint
  13110. * @classdesc Physics DistanceConstraint Constructor
  13111. * @constructor
  13112. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  13113. * @param {p2.Body} bodyA - First connected body.
  13114. * @param {p2.Body} bodyB - Second connected body.
  13115. * @param {number} distance - The distance to keep between the bodies.
  13116. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  13117. */
  13118. Phaser.Physics.P2.DistanceConstraint = function (world, bodyA, bodyB, distance, maxForce) {
  13119. if (typeof distance === 'undefined') { distance = 100; }
  13120. /**
  13121. * @property {Phaser.Game} game - Local reference to game.
  13122. */
  13123. this.game = world.game;
  13124. /**
  13125. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  13126. */
  13127. this.world = world;
  13128. distance = world.pxm(distance);
  13129. p2.DistanceConstraint.call(this, bodyA, bodyB, distance, maxForce);
  13130. };
  13131. Phaser.Physics.P2.DistanceConstraint.prototype = Object.create(p2.DistanceConstraint.prototype);
  13132. Phaser.Physics.P2.DistanceConstraint.prototype.constructor = Phaser.Physics.P2.DistanceConstraint;
  13133. /**
  13134. * @author Richard Davey <rich@photonstorm.com>
  13135. * @copyright 2014 Photon Storm Ltd.
  13136. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13137. */
  13138. /**
  13139. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  13140. *
  13141. * @class Phaser.Physics.P2.GearConstraint
  13142. * @classdesc Physics GearConstraint Constructor
  13143. * @constructor
  13144. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  13145. * @param {p2.Body} bodyA - First connected body.
  13146. * @param {p2.Body} bodyB - Second connected body.
  13147. * @param {number} [angle=0] - The relative angle
  13148. * @param {number} [ratio=1] - The gear ratio.
  13149. */
  13150. Phaser.Physics.P2.GearConstraint = function (world, bodyA, bodyB, angle, ratio) {
  13151. if (typeof angle === 'undefined') { angle = 0; }
  13152. if (typeof ratio === 'undefined') { ratio = 1; }
  13153. /**
  13154. * @property {Phaser.Game} game - Local reference to game.
  13155. */
  13156. this.game = world.game;
  13157. /**
  13158. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  13159. */
  13160. this.world = world;
  13161. var options = { angle: angle, ratio: ratio };
  13162. p2.GearConstraint.call(this, bodyA, bodyB, options);
  13163. };
  13164. Phaser.Physics.P2.GearConstraint.prototype = Object.create(p2.GearConstraint.prototype);
  13165. Phaser.Physics.P2.GearConstraint.prototype.constructor = Phaser.Physics.P2.GearConstraint;
  13166. /**
  13167. * @author Richard Davey <rich@photonstorm.com>
  13168. * @copyright 2014 Photon Storm Ltd.
  13169. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13170. */
  13171. /**
  13172. * Locks the relative position between two bodies.
  13173. *
  13174. * @class Phaser.Physics.P2.LockConstraint
  13175. * @classdesc Physics LockConstraint Constructor
  13176. * @constructor
  13177. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  13178. * @param {p2.Body} bodyA - First connected body.
  13179. * @param {p2.Body} bodyB - Second connected body.
  13180. * @param {Array} [offset] - The offset of bodyB in bodyA's frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  13181. * @param {number} [angle=0] - The angle of bodyB in bodyA's frame.
  13182. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  13183. */
  13184. Phaser.Physics.P2.LockConstraint = function (world, bodyA, bodyB, offset, angle, maxForce) {
  13185. if (typeof offset === 'undefined') { offset = [0, 0]; }
  13186. if (typeof angle === 'undefined') { angle = 0; }
  13187. if (typeof maxForce === 'undefined') { maxForce = Number.MAX_VALUE; }
  13188. /**
  13189. * @property {Phaser.Game} game - Local reference to game.
  13190. */
  13191. this.game = world.game;
  13192. /**
  13193. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  13194. */
  13195. this.world = world;
  13196. offset = [ world.pxm(offset[0]), world.pxm(offset[1]) ];
  13197. var options = { localOffsetB: offset, localAngleB: angle, maxForce: maxForce };
  13198. p2.LockConstraint.call(this, bodyA, bodyB, options);
  13199. };
  13200. Phaser.Physics.P2.LockConstraint.prototype = Object.create(p2.LockConstraint.prototype);
  13201. Phaser.Physics.P2.LockConstraint.prototype.constructor = Phaser.Physics.P2.LockConstraint;
  13202. /**
  13203. * @author Richard Davey <rich@photonstorm.com>
  13204. * @copyright 2014 Photon Storm Ltd.
  13205. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13206. */
  13207. /**
  13208. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  13209. *
  13210. * @class Phaser.Physics.P2.PrismaticConstraint
  13211. * @classdesc Physics PrismaticConstraint Constructor
  13212. * @constructor
  13213. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  13214. * @param {p2.Body} bodyA - First connected body.
  13215. * @param {p2.Body} bodyB - Second connected body.
  13216. * @param {boolean} [lockRotation=true] - If set to false, bodyB will be free to rotate around its anchor point.
  13217. * @param {Array} [anchorA] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  13218. * @param {Array} [anchorB] - Body A's anchor point, defined in its own local frame. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  13219. * @param {Array} [axis] - An axis, defined in body A frame, that body B's anchor point may slide along. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  13220. * @param {number} [maxForce] - The maximum force that should be applied to constrain the bodies.
  13221. */
  13222. Phaser.Physics.P2.PrismaticConstraint = function (world, bodyA, bodyB, lockRotation, anchorA, anchorB, axis, maxForce) {
  13223. if (typeof lockRotation === 'undefined') { lockRotation = true; }
  13224. if (typeof anchorA === 'undefined') { anchorA = [0, 0]; }
  13225. if (typeof anchorB === 'undefined') { anchorB = [0, 0]; }
  13226. if (typeof axis === 'undefined') { axis = [0, 0]; }
  13227. if (typeof maxForce === 'undefined') { maxForce = Number.MAX_VALUE; }
  13228. /**
  13229. * @property {Phaser.Game} game - Local reference to game.
  13230. */
  13231. this.game = world.game;
  13232. /**
  13233. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  13234. */
  13235. this.world = world;
  13236. anchorA = [ world.pxmi(anchorA[0]), world.pxmi(anchorA[1]) ];
  13237. anchorB = [ world.pxmi(anchorB[0]), world.pxmi(anchorB[1]) ];
  13238. var options = { localAnchorA: anchorA, localAnchorB: anchorB, localAxisA: axis, maxForce: maxForce, disableRotationalLock: !lockRotation };
  13239. p2.PrismaticConstraint.call(this, bodyA, bodyB, options);
  13240. };
  13241. Phaser.Physics.P2.PrismaticConstraint.prototype = Object.create(p2.PrismaticConstraint.prototype);
  13242. Phaser.Physics.P2.PrismaticConstraint.prototype.constructor = Phaser.Physics.P2.PrismaticConstraint;
  13243. /**
  13244. * @author Richard Davey <rich@photonstorm.com>
  13245. * @copyright 2014 Photon Storm Ltd.
  13246. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
  13247. */
  13248. /**
  13249. * Connects two bodies at given offset points, letting them rotate relative to each other around this point.
  13250. * The pivot points are given in world (pixel) coordinates.
  13251. *
  13252. * @class Phaser.Physics.P2.RevoluteConstraint
  13253. * @classdesc Physics RevoluteConstraint Constructor
  13254. * @constructor
  13255. * @param {Phaser.Physics.P2} world - A reference to the P2 World.
  13256. * @param {p2.Body} bodyA - First connected body.
  13257. * @param {Float32Array} pivotA - The point relative to the center of mass of bodyA which bodyA is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  13258. * @param {p2.Body} bodyB - Second connected body.
  13259. * @param {Float32Array} pivotB - The point relative to the center of mass of bodyB which bodyB is constrained to. The value is an array with 2 elements matching x and y, i.e: [32, 32].
  13260. * @param {number} [maxForce=0] - The maximum force that should be applied to constrain the bodies.
  13261. */
  13262. Phaser.Physics.P2.RevoluteConstraint = function (world, bodyA, pivotA, bodyB, pivotB, maxForce) {
  13263. if (typeof maxForce === 'undefined') { maxForce = Number.MAX_VALUE; }
  13264. /**
  13265. * @property {Phaser.Game} game - Local reference to game.
  13266. */
  13267. this.game = world.game;
  13268. /**
  13269. * @property {Phaser.Physics.P2} world - Local reference to P2 World.
  13270. */
  13271. this.world = world;
  13272. pivotA = [ world.pxmi(pivotA[0]), world.pxmi(pivotA[1]) ];
  13273. pivotB = [ world.pxmi(pivotB[0]), world.pxmi(pivotB[1]) ];
  13274. p2.RevoluteConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  13275. };
  13276. Phaser.Physics.P2.RevoluteConstraint.prototype = Object.create(p2.RevoluteConstraint.prototype);
  13277. Phaser.Physics.P2.RevoluteConstraint.prototype.constructor = Phaser.Physics.P2.RevoluteConstraint;