vendor: 22,746 bytes, lines 1-621
1/** 2* matter-js 0.14.2 by @liabru 2018-06-11 3* http://brm.io/matter-js/ 4* License MIT 5*/ 6 7/** 8 * The MIT License (MIT) 9 * 10 * Copyright (c) Liam Brummitt and contributors. 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a copy 13 * of this software and associated documentation files (the "Software"), to deal 14 * in the Software without restriction, including without limitation the rights 15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 * copies of the Software, and to permit persons to whom the Software is 17 * furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included in 20 * all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 * THE SOFTWARE. 29 */ 30 31(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Matter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(_dereq_,module,exports){ 32/** 33* The `Matter.Body` module contains methods for creating and manipulating body models. 34* A `Matter.Body` is a rigid body that can be simulated by a `Matter.Engine`. 35* Factories for commonly used body configurations (such as rectangles, circles and other polygons) can be found in the module `Matter.Bodies`. 36* 37* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 38 39* @class Body 40*/ 41 42var Body = {}; 43 44module.exports = Body; 45 46var Vertices = _dereq_('../geometry/Vertices'); 47var Vector = _dereq_('../geometry/Vector'); 48var Sleeping = _dereq_('../core/Sleeping'); 49var Render = _dereq_('../render/Render'); 50var Common = _dereq_('../core/Common'); 51var Bounds = _dereq_('../geometry/Bounds'); 52var Axes = _dereq_('../geometry/Axes'); 53 54(function() { 55 56 Body._inertiaScale = 4; 57 Body._nextCollidingGroupId = 1; 58 Body._nextNonCollidingGroupId = -1; 59 Body._nextCategory = 0x0001; 60 61 /** 62 * Creates a new rigid body model. The options parameter is an object that specifies any properties you wish to override the defaults. 63 * All properties have default values, and many are pre-calculated automatically based on other properties. 64 * Vertices must be specified in clockwise order. 65 * See the properties section below for detailed information on what you can pass via the `options` object. 66 * @method create 67 * @param {} options 68 * @return {body} body 69 */ 70 Body.create = function(options) { 71 var defaults = { 72 id: Common.nextId(), 73 type: 'body', 74 label: 'Body', 75 parts: [], 76 plugin: {}, 77 angle: 0, 78 vertices: Vertices.fromPath('L 0 0 L 40 0 L 40 40 L 0 40'), 79 position: { x: 0, y: 0 }, 80 force: { x: 0, y: 0 }, 81 torque: 0, 82 positionImpulse: { x: 0, y: 0 }, 83 constraintImpulse: { x: 0, y: 0, angle: 0 }, 84 totalContacts: 0, 85 speed: 0, 86 angularSpeed: 0, 87 velocity: { x: 0, y: 0 }, 88 angularVelocity: 0, 89 isSensor: false, 90 isStatic: false, 91 isSleeping: false, 92 motion: 0, 93 sleepThreshold: 60, 94 density: 0.001, 95 restitution: 0, 96 friction: 0.1, 97 frictionStatic: 0.5, 98 frictionAir: 0.01, 99 collisionFilter: { 100 category: 0x0001, 101 mask: 0xFFFFFFFF, 102 group: 0 103 }, 104 slop: 0.05, 105 timeScale: 1, 106 render: { 107 visible: true, 108 opacity: 1, 109 sprite: { 110 xScale: 1, 111 yScale: 1, 112 xOffset: 0, 113 yOffset: 0 114 }, 115 lineWidth: 0 116 } 117 }; 118 119 var body = Common.extend(defaults, options); 120 121 _initProperties(body, options); 122 123 return body; 124 }; 125 126 /** 127 * Returns the next unique group index for which bodies will collide. 128 * If `isNonColliding` is `true`, returns the next unique group index for which bodies will _not_ collide. 129 * See `body.collisionFilter` for more information. 130 * @method nextGroup 131 * @param {bool} [isNonColliding=false] 132 * @return {Number} Unique group index 133 */ 134 Body.nextGroup = function(isNonColliding) { 135 if (isNonColliding) 136 return Body._nextNonCollidingGroupId--; 137 138 return Body._nextCollidingGroupId++; 139 }; 140 141 /** 142 * Returns the next unique category bitfield (starting after the initial default category `0x0001`). 143 * There are 32 available. See `body.collisionFilter` for more information. 144 * @method nextCategory 145 * @return {Number} Unique category bitfield 146 */ 147 Body.nextCategory = function() { 148 Body._nextCategory = Body._nextCategory << 1; 149 return Body._nextCategory; 150 }; 151 152 /** 153 * Initialises body properties. 154 * @method _initProperties 155 * @private 156 * @param {body} body 157 * @param {} [options] 158 */ 159 var _initProperties = function(body, options) { 160 options = options || {}; 161 162 // init required properties (order is important) 163 Body.set(body, { 164 bounds: body.bounds || Bounds.create(body.vertices), 165 positionPrev: body.positionPrev || Vector.clone(body.position), 166 anglePrev: body.anglePrev || body.angle, 167 vertices: body.vertices, 168 parts: body.parts || [body], 169 isStatic: body.isStatic, 170 isSleeping: body.isSleeping, 171 parent: body.parent || body 172 }); 173 174 Vertices.rotate(body.vertices, body.angle, body.position); 175 Axes.rotate(body.axes, body.angle); 176 Bounds.update(body.bounds, body.vertices, body.velocity); 177 178 // allow options to override the automatically calculated properties 179 Body.set(body, { 180 axes: options.axes || body.axes, 181 area: options.area || body.area, 182 mass: options.mass || body.mass, 183 inertia: options.inertia || body.inertia 184 }); 185 186 // render properties 187 var defaultFillStyle = (body.isStatic ? '#2e2b44' : Common.choose(['#006BA6', '#0496FF', '#FFBC42', '#D81159', '#8F2D56'])), 188 defaultStrokeStyle = '#000'; 189 body.render.fillStyle = body.render.fillStyle || defaultFillStyle; 190 body.render.strokeStyle = body.render.strokeStyle || defaultStrokeStyle; 191 body.render.sprite.xOffset += -(body.bounds.min.x - body.position.x) / (body.bounds.max.x - body.bounds.min.x); 192 body.render.sprite.yOffset += -(body.bounds.min.y - body.position.y) / (body.bounds.max.y - body.bounds.min.y); 193 }; 194 195 /** 196 * Given a property and a value (or map of), sets the property(s) on the body, using the appropriate setter functions if they exist. 197 * Prefer to use the actual setter functions in performance critical situations. 198 * @method set 199 * @param {body} body 200 * @param {} settings A property name (or map of properties and values) to set on the body. 201 * @param {} value The value to set if `settings` is a single property name. 202 */ 203 Body.set = function(body, settings, value) { 204 var property; 205 206 if (typeof settings === 'string') { 207 property = settings; 208 settings = {}; 209 settings[property] = value; 210 } 211 212 for (property in settings) { 213 value = settings[property]; 214 215 if (!settings.hasOwnProperty(property)) 216 continue; 217 218 switch (property) { 219 220 case 'isStatic': 221 Body.setStatic(body, value); 222 break; 223 case 'isSleeping': 224 Sleeping.set(body, value); 225 break; 226 case 'mass': 227 Body.setMass(body, value); 228 break; 229 case 'density': 230 Body.setDensity(body, value); 231 break; 232 case 'inertia': 233 Body.setInertia(body, value); 234 break; 235 case 'vertices': 236 Body.setVertices(body, value); 237 break; 238 case 'position': 239 Body.setPosition(body, value); 240 break; 241 case 'angle': 242 Body.setAngle(body, value); 243 break; 244 case 'velocity': 245 Body.setVelocity(body, value); 246 break; 247 case 'angularVelocity': 248 Body.setAngularVelocity(body, value); 249 break; 250 case 'parts': 251 Body.setParts(body, value); 252 break; 253 default: 254 body[property] = value; 255 256 } 257 } 258 }; 259 260 /** 261 * Sets the body as static, including isStatic flag and setting mass and inertia to Infinity. 262 * @method setStatic 263 * @param {body} body 264 * @param {bool} isStatic 265 */ 266 Body.setStatic = function(body, isStatic) { 267 for (var i = 0; i < body.parts.length; i++) { 268 var part = body.parts[i]; 269 part.isStatic = isStatic; 270 271 if (isStatic) { 272 part._original = { 273 restitution: part.restitution, 274 friction: part.friction, 275 mass: part.mass, 276 inertia: part.inertia, 277 density: part.density, 278 inverseMass: part.inverseMass, 279 inverseInertia: part.inverseInertia 280 }; 281 282 part.restitution = 0; 283 part.friction = 1; 284 part.mass = part.inertia = part.density = Infinity; 285 part.inverseMass = part.inverseInertia = 0; 286 287 part.positionPrev.x = part.position.x; 288 part.positionPrev.y = part.position.y; 289 part.anglePrev = part.angle; 290 part.angularVelocity = 0; 291 part.speed = 0; 292 part.angularSpeed = 0; 293 part.motion = 0; 294 } else if (part._original) { 295 part.restitution = part._original.restitution; 296 part.friction = part._original.friction; 297 part.mass = part._original.mass; 298 part.inertia = part._original.inertia; 299 part.density = part._original.density; 300 part.inverseMass = part._original.inverseMass; 301 part.inverseInertia = part._original.inverseInertia; 302 303 delete part._original; 304 } 305 } 306 }; 307 308 /** 309 * Sets the mass of the body. Inverse mass, density and inertia are automatically updated to reflect the change. 310 * @method setMass 311 * @param {body} body 312 * @param {number} mass 313 */ 314 Body.setMass = function(body, mass) { 315 var moment = body.inertia / (body.mass / 6); 316 body.inertia = moment * (mass / 6); 317 body.inverseInertia = 1 / body.inertia; 318 319 body.mass = mass; 320 body.inverseMass = 1 / body.mass; 321 body.density = body.mass / body.area; 322 }; 323 324 /** 325 * Sets the density of the body. Mass and inertia are automatically updated to reflect the change. 326 * @method setDensity 327 * @param {body} body 328 * @param {number} density 329 */ 330 Body.setDensity = function(body, density) { 331 Body.setMass(body, density * body.area); 332 body.density = density; 333 }; 334 335 /** 336 * Sets the moment of inertia (i.e. second moment of area) of the body of the body. 337 * Inverse inertia is automatically updated to reflect the change. Mass is not changed. 338 * @method setInertia 339 * @param {body} body 340 * @param {number} inertia 341 */ 342 Body.setInertia = function(body, inertia) { 343 body.inertia = inertia; 344 body.inverseInertia = 1 / body.inertia; 345 }; 346 347 /** 348 * Sets the body's vertices and updates body properties accordingly, including inertia, area and mass (with respect to `body.density`). 349 * Vertices will be automatically transformed to be orientated around their centre of mass as the origin. 350 * They are then automatically translated to world space based on `body.position`. 351 * 352 * The `vertices` argument should be passed as an array of `Matter.Vector` points (or a `Matter.Vertices` array). 353 * Vertices must form a convex hull, concave hulls are not supported. 354 * 355 * @method setVertices 356 * @param {body} body 357 * @param {vector[]} vertices 358 */ 359 Body.setVertices = function(body, vertices) { 360 // change vertices 361 if (vertices[0].body === body) { 362 body.vertices = vertices; 363 } else { 364 body.vertices = Vertices.create(vertices, body); 365 } 366 367 // update properties 368 body.axes = Axes.fromVertices(body.vertices); 369 body.area = Vertices.area(body.vertices); 370 Body.setMass(body, body.density * body.area); 371 372 // orient vertices around the centre of mass at origin (0, 0) 373 var centre = Vertices.centre(body.vertices); 374 Vertices.translate(body.vertices, centre, -1); 375 376 // update inertia while vertices are at origin (0, 0) 377 Body.setInertia(body, Body._inertiaScale * Vertices.inertia(body.vertices, body.mass)); 378 379 // update geometry 380 Vertices.translate(body.vertices, body.position); 381 Bounds.update(body.bounds, body.vertices, body.velocity); 382 }; 383 384 /** 385 * Sets the parts of the `body` and updates mass, inertia and centroid. 386 * Each part will have its parent set to `body`. 387 * By default the convex hull will be automatically computed and set on `body`, unless `autoHull` is set to `false.` 388 * Note that this method will ensure that the first part in `body.parts` will always be the `body`. 389 * @method setParts 390 * @param {body} body 391 * @param [body] parts 392 * @param {bool} [autoHull=true] 393 */ 394 Body.setParts = function(body, parts, autoHull) { 395 var i; 396 397 // add all the parts, ensuring that the first part is always the parent body 398 parts = parts.slice(0); 399 body.parts.length = 0; 400 body.parts.push(body); 401 body.parent = body; 402 403 for (i = 0; i < parts.length; i++) { 404 var part = parts[i]; 405 if (part !== body) { 406 part.parent = body; 407 body.parts.push(part); 408 } 409 } 410 411 if (body.parts.length === 1) 412 return; 413 414 autoHull = typeof autoHull !== 'undefined' ? autoHull : true; 415 416 // find the convex hull of all parts to set on the parent body 417 if (autoHull) { 418 var vertices = []; 419 for (i = 0; i < parts.length; i++) { 420 vertices = vertices.concat(parts[i].vertices); 421 } 422 423 Vertices.clockwiseSort(vertices); 424 425 var hull = Vertices.hull(vertices), 426 hullCentre = Vertices.centre(hull); 427 428 Body.setVertices(body, hull); 429 Vertices.translate(body.vertices, hullCentre); 430 } 431 432 // sum the properties of all compound parts of the parent body 433 var total = Body._totalProperties(body); 434 435 body.area = total.area; 436 body.parent = body; 437 body.position.x = total.centre.x; 438 body.position.y = total.centre.y; 439 body.positionPrev.x = total.centre.x; 440 body.positionPrev.y = total.centre.y; 441 442 Body.setMass(body, total.mass); 443 Body.setInertia(body, total.inertia); 444 Body.setPosition(body, total.centre); 445 }; 446 447 /** 448 * Sets the position of the body instantly. Velocity, angle, force etc. are unchanged. 449 * @method setPosition 450 * @param {body} body 451 * @param {vector} position 452 */ 453 Body.setPosition = function(body, position) { 454 var delta = Vector.sub(position, body.position); 455 body.positionPrev.x += delta.x; 456 body.positionPrev.y += delta.y; 457 458 for (var i = 0; i < body.parts.length; i++) { 459 var part = body.parts[i]; 460 part.position.x += delta.x; 461 part.position.y += delta.y; 462 Vertices.translate(part.vertices, delta); 463 Bounds.update(part.bounds, part.vertices, body.velocity); 464 } 465 }; 466 467 /** 468 * Sets the angle of the body instantly. Angular velocity, position, force etc. are unchanged. 469 * @method setAngle 470 * @param {body} body 471 * @param {number} angle 472 */ 473 Body.setAngle = function(body, angle) { 474 var delta = angle - body.angle; 475 body.anglePrev += delta; 476 477 for (var i = 0; i < body.parts.length; i++) { 478 var part = body.parts[i]; 479 part.angle += delta; 480 Vertices.rotate(part.vertices, delta, body.position); 481 Axes.rotate(part.axes, delta); 482 Bounds.update(part.bounds, part.vertices, body.velocity); 483 if (i > 0) { 484 Vector.rotateAbout(part.position, delta, body.position, part.position); 485 } 486 } 487 }; 488 489 /** 490 * Sets the linear velocity of the body instantly. Position, angle, force etc. are unchanged. See also `Body.applyForce`. 491 * @method setVelocity 492 * @param {body} body 493 * @param {vector} velocity 494 */ 495 Body.setVelocity = function(body, velocity) { 496 body.positionPrev.x = body.position.x - velocity.x; 497 body.positionPrev.y = body.position.y - velocity.y; 498 body.velocity.x = velocity.x; 499 body.velocity.y = velocity.y; 500 body.speed = Vector.magnitude(body.velocity); 501 }; 502 503 /** 504 * Sets the angular velocity of the body instantly. Position, angle, force etc. are unchanged. See also `Body.applyForce`. 505 * @method setAngularVelocity 506 * @param {body} body 507 * @param {number} velocity 508 */ 509 Body.setAngularVelocity = function(body, velocity) { 510 body.anglePrev = body.angle - velocity; 511 body.angularVelocity = velocity; 512 body.angularSpeed = Math.abs(body.angularVelocity); 513 }; 514 515 /** 516 * Moves a body by a given vector relative to its current position, without imparting any velocity. 517 * @method translate 518 * @param {body} body 519 * @param {vector} translation 520 */ 521 Body.translate = function(body, translation) { 522 Body.setPosition(body, Vector.add(body.position, translation)); 523 }; 524 525 /** 526 * Rotates a body by a given angle relative to its current angle, without imparting any angular velocity. 527 * @method rotate 528 * @param {body} body 529 * @param {number} rotation 530 * @param {vector} [point] 531 */ 532 Body.rotate = function(body, rotation, point) { 533 if (!point) { 534 Body.setAngle(body, body.angle + rotation); 535 } else { 536 var cos = Math.cos(rotation), 537 sin = Math.sin(rotation), 538 dx = body.position.x - point.x, 539 dy = body.position.y - point.y; 540 541 Body.setPosition(body, { 542 x: point.x + (dx * cos - dy * sin), 543 y: point.y + (dx * sin + dy * cos) 544 }); 545 546 Body.setAngle(body, body.angle + rotation); 547 } 548 }; 549 550 /** 551 * Scales the body, including updating physical properties (mass, area, axes, inertia), from a world-space point (default is body centre). 552 * @method scale 553 * @param {body} body 554 * @param {number} scaleX 555 * @param {number} scaleY 556 * @param {vector} [point] 557 */ 558 Body.scale = function(body, scaleX, scaleY, point) { 559 var totalArea = 0, 560 totalInertia = 0; 561 562 point = point || body.position; 563 564 for (var i = 0; i < body.parts.length; i++) { 565 var part = body.parts[i]; 566 567 // scale vertices 568 Vertices.scale(part.vertices, scaleX, scaleY, point); 569 570 // update properties 571 part.axes = Axes.fromVertices(part.vertices); 572 part.area = Vertices.area(part.vertices); 573 Body.setMass(part, body.density * part.area); 574 575 // update inertia (requires vertices to be at origin) 576 Vertices.translate(part.vertices, { x: -part.position.x, y: -part.position.y }); 577 Body.setInertia(part, Body._inertiaScale * Vertices.inertia(part.vertices, part.mass)); 578 Vertices.translate(part.vertices, { x: part.position.x, y: part.position.y }); 579 580 if (i > 0) { 581 totalArea += part.area; 582 totalInertia += part.inertia; 583 } 584 585 // scale position 586 part.position.x = point.x + (part.position.x - point.x) * scaleX; 587 part.position.y = point.y + (part.position.y - point.y) * scaleY; 588 589 // update bounds 590 Bounds.update(part.bounds, part.vertices, body.velocity); 591 } 592 593 // handle parent body 594 if (body.parts.length > 1) { 595 body.area = totalArea; 596 597 if (!body.isStatic) { 598 Body.setMass(body, body.density * totalArea); 599 Body.setInertia(body, totalInertia); 600 } 601 } 602 603 // handle circles 604 if (body.circleRadius) { 605 if (scaleX === scaleY) { 606 body.circleRadius *= scaleX; 607 } else { 608 // body is no longer a circle 609 body.circleRadius = null; 610 } 611 } 612 }; 613 614 /** 615 * Performs a simulation step for the given `body`, including updating position and angle using Verlet integration. 616 * @method update 617 * @param {body} body 618 * @param {number} deltaTime 619 * @param {number} timeScale 620 * @param {number} correction 621 */
622 Body.update = function(body, deltaTime, timeScale, correction) { 623 var deltaTimeSquared = Math.pow(deltaTime * timeScale * body.timeScale, 2); 624 625 // from the previous step 626 var frictionAir = 1 - body.frictionAir * timeScale * body.timeScale, 627 velocityPrevX = body.position.x - body.positionPrev.x, 628 velocityPrevY = body.position.y - body.positionPrev.y; 629 630 // update velocity with Verlet integration 631 body.velocity.x = (velocityPrevX * frictionAir * correction) + (body.force.x / body.mass) * deltaTimeSquared; 632 body.velocity.y = (velocityPrevY * frictionAir * correction) + (body.force.y / body.mass) * deltaTimeSquared; 633 634 body.positionPrev.x = body.position.x; 635 body.positionPrev.y = body.position.y; 636 body.position.x += body.velocity.x; 637 body.position.y += body.velocity.y; 638 639 // update angular velocity with Verlet integration 640 body.angularVelocity = ((body.angle - body.anglePrev) * frictionAir * correction) + (body.torque / body.inertia) * deltaTimeSquared; 641 body.anglePrev = body.angle; 642 body.angle += body.angularVelocity; 643 644 // track speed and acceleration 645 body.speed = Vector.magnitude(body.velocity); 646 body.angularSpeed = Math.abs(body.angularVelocity); 647 648 // transform the body geometry 649 for (var i = 0; i < body.parts.length; i++) { 650 var part = body.parts[i]; 651 652 Vertices.translate(part.vertices, body.velocity); 653 654 if (i > 0) { 655 part.position.x += body.velocity.x; 656 part.position.y += body.velocity.y; 657 } 658 659 if (body.angularVelocity !== 0) { 660 Vertices.rotate(part.vertices, body.angularVelocity, body.position); 661 Axes.rotate(part.axes, body.angularVelocity); 662 if (i > 0) { 663 Vector.rotateAbout(part.position, body.angularVelocity, body.position, part.position); 664 } 665 } 666 667 Bounds.update(part.bounds, part.vertices, body.velocity); 668 } 669 }; 670 671 /** 672 * Applies a force to a body from a given world-space position, including resulting torque. 673 * @method applyForce 674 * @param {body} body 675 * @param {vector} position 676 * @param {vector} force 677 */ 678 Body.applyForce = function(body, position, force) { 679 body.force.x += force.x; 680 body.force.y += force.y; 681 var offset = { x: position.x - body.position.x, y: position.y - body.position.y }; 682 body.torque += offset.x * force.y - offset.y * force.x; 683 }; 684 685 /** 686 * Returns the sums of the properties of all compound parts of the parent body. 687 * @method _totalProperties 688 * @private 689 * @param {body} body 690 * @return {} 691 */ 692 Body._totalProperties = function(body) { 693 // from equations at: 694 // https://ecourses.ou.edu/cgi-bin/ebook.cgi?doc=&topic=st&chap_sec=07.2&page=theory 695 // http://output.to/sideway/default.asp?qno=121100087 696 697 var properties = { 698 mass: 0, 699 area: 0, 700 inertia: 0, 701 centre: { x: 0, y: 0 } 702 }; 703 704 // sum the properties of all compound parts of the parent body 705 for (var i = body.parts.length === 1 ? 0 : 1; i < body.parts.length; i++) { 706 var part = body.parts[i], 707 mass = part.mass !== Infinity ? part.mass : 1; 708 709 properties.mass += mass; 710 properties.area += part.area; 711 properties.inertia += part.inertia; 712 properties.centre = Vector.add(properties.centre, Vector.mult(part.position, mass)); 713 } 714 715 properties.centre = Vector.div(properties.centre, properties.mass); 716 717 return properties; 718 }; 719 720 /* 721 * 722 * Events Documentation 723 * 724 */ 725 726 /** 727 * Fired when a body starts sleeping (where `this` is the body). 728 * 729 * @event sleepStart 730 * @this {body} The body that has started sleeping 731 * @param {} event An event object 732 * @param {} event.source The source object of the event 733 * @param {} event.name The name of the event 734 */ 735 736 /** 737 * Fired when a body ends sleeping (where `this` is the body). 738 * 739 * @event sleepEnd 740 * @this {body} The body that has ended sleeping 741 * @param {} event An event object 742 * @param {} event.source The source object of the event 743 * @param {} event.name The name of the event 744 */ 745 746 /* 747 * 748 * Properties Documentation 749 * 750 */ 751 752 /** 753 * An integer `Number` uniquely identifying number generated in `Body.create` by `Common.nextId`. 754 * 755 * @property id 756 * @type number 757 */ 758 759 /** 760 * A `String` denoting the type of object. 761 * 762 * @property type 763 * @type string 764 * @default "body" 765 * @readOnly 766 */ 767 768 /** 769 * An arbitrary `String` name to help the user identify and manage bodies. 770 * 771 * @property label 772 * @type string 773 * @default "Body" 774 */ 775 776 /** 777 * An array of bodies that make up this body.
778 * The first body in the array must always be a self reference to the current body instance. 779 * All bodies in the `parts` array together form a single rigid compound body. 780 * Parts are allowed to overlap, have gaps or holes or even form concave bodies. 781 * Parts themselves should never be added to a `World`, only the parent body should be. 782 * Use `Body.setParts` when setting parts to ensure correct updates of all properties. 783 * 784 * @property parts 785 * @type body[] 786 */ 787 788 /** 789 * An object reserved for storing plugin-specific properties. 790 * 791 * @property plugin 792 * @type {} 793 */ 794 795 /** 796 * A self reference if the body is _not_ a part of another body. 797 * Otherwise this is a reference to the body that this is a part of. 798 * See `body.parts`. 799 * 800 * @property parent 801 * @type body 802 */ 803 804 /** 805 * A `Number` specifying the angle of the body, in radians. 806 * 807 * @property angle 808 * @type number 809 * @default 0 810 */ 811 812 /** 813 * An array of `Vector` objects that specify the convex hull of the rigid body. 814 * These should be provided about the origin `(0, 0)`. E.g. 815 * 816 * [{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }] 817 * 818 * When passed via `Body.create`, the vertices are translated relative to `body.position` (i.e. world-space, and constantly updated by `Body.update` during simulation). 819 * The `Vector` objects are also augmented with additional properties required for efficient collision detection. 820 * 821 * Other properties such as `inertia` and `bounds` are automatically calculated from the passed vertices (unless provided via `options`). 822 * Concave hulls are not currently supported. The module `Matter.Vertices` contains useful methods for working with vertices. 823 * 824 * @property vertices 825 * @type vector[] 826 */ 827 828 /** 829 * A `Vector` that specifies the current world-space position of the body. 830 * 831 * @property position 832 * @type vector 833 * @default { x: 0, y: 0 } 834 */ 835 836 /** 837 * A `Vector` that specifies the force to apply in the current step. It is zeroed after every `Body.update`. See also `Body.applyForce`. 838 * 839 * @property force 840 * @type vector 841 * @default { x: 0, y: 0 } 842 */ 843 844 /** 845 * A `Number` that specifies the torque (turning force) to apply in the current step. It is zeroed after every `Body.update`. 846 * 847 * @property torque 848 * @type number 849 * @default 0 850 */ 851 852 /** 853 * A `Number` that _measures_ the current speed of the body after the last `Body.update`. It is read-only and always positive (it's the magnitude of `body.velocity`). 854 * 855 * @readOnly 856 * @property speed 857 * @type number 858 * @default 0 859 */ 860 861 /** 862 * A `Number` that _measures_ the current angular speed of the body after the last `Body.update`. It is read-only and always positive (it's the magnitude of `body.angularVelocity`). 863 * 864 * @readOnly 865 * @property angularSpeed 866 * @type number 867 * @default 0 868 */ 869 870 /** 871 * A `Vector` that _measures_ the current velocity of the body after the last `Body.update`. It is read-only. 872 * If you need to modify a body's velocity directly, you should either apply a force or simply change the body's `position` (as the engine uses position-Verlet integration). 873 * 874 * @readOnly 875 * @property velocity 876 * @type vector 877 * @default { x: 0, y: 0 } 878 */ 879 880 /** 881 * A `Number` that _measures_ the current angular velocity of the body after the last `Body.update`. It is read-only. 882 * If you need to modify a body's angular velocity directly, you should apply a torque or simply change the body's `angle` (as the engine uses position-Verlet integration). 883 * 884 * @readOnly 885 * @property angularVelocity 886 * @type number 887 * @default 0 888 */ 889 890 /** 891 * A flag that indicates whether a body is considered static. A static body can never change position or angle and is completely fixed. 892 * If you need to set a body as static after its creation, you should use `Body.setStatic` as this requires more than just setting this flag. 893 * 894 * @property isStatic 895 * @type boolean 896 * @default false 897 */ 898 899 /** 900 * A flag that indicates whether a body is a sensor. Sensor triggers collision events, but doesn't react with colliding body physically. 901 * 902 * @property isSensor 903 * @type boolean 904 * @default false 905 */ 906 907 /** 908 * A flag that indicates whether the body is considered sleeping. A sleeping body acts similar to a static body, except it is only temporary and can be awoken. 909 * If you need to set a body as sleeping, you should use `Sleeping.set` as this requires more than just setting this flag. 910 * 911 * @property isSleeping 912 * @type boolean 913 * @default false 914 */ 915 916 /** 917 * A `Number` that _measures_ the amount of movement a body currently has (a combination of `speed` and `angularSpeed`). It is read-only and always positive. 918 * It is used and updated by the `Matter.Sleeping` module during simulation to decide if a body has come to rest. 919 * 920 * @readOnly 921 * @property motion 922 * @type number 923 * @default 0 924 */ 925 926 /** 927 * A `Number` that defines the number of updates in which this body must have near-zero velocity before it is set as sleeping by the `Matter.Sleeping` module (if sleeping is enabled by the engine). 928 * 929 * @property sleepThreshold 930 * @type number 931 * @default 60 932 */ 933 934 /** 935 * A `Number` that defines the density of the body, that is its mass per unit area. 936 * If you pass the density via `Body.create` the `mass` property is automatically calculated for you based on the size (area) of the object. 937 * This is generally preferable to simply setting mass and allows for more intuitive definition of materials (e.g. rock has a higher density than wood). 938 * 939 * @property density 940 * @type number 941 * @default 0.001 942 */ 943 944 /** 945 * A `Number` that defines the mass of the body, although it may be more appropriate to specify the `density` property instead. 946 * If you modify this value, you must also modify the `body.inverseMass` property (`1 / mass`). 947 * 948 * @property mass 949 * @type number 950 */ 951 952 /** 953 * A `Number` that defines the inverse mass of the body (`1 / mass`). 954 * If you modify this value, you must also modify the `body.mass` property. 955 * 956 * @property inverseMass 957 * @type number 958 */ 959 960 /** 961 * A `Number` that defines the moment of inertia (i.e. second moment of area) of the body. 962 * It is automatically calculated from the given convex hull (`vertices` array) and density in `Body.create`. 963 * If you modify this value, you must also modify the `body.inverseInertia` property (`1 / inertia`). 964 * 965 * @property inertia 966 * @type number 967 */ 968 969 /** 970 * A `Number` that defines the inverse moment of inertia of the body (`1 / inertia`). 971 * If you modify this value, you must also modify the `body.inertia` property. 972 * 973 * @property inverseInertia 974 * @type number 975 */ 976 977 /** 978 * A `Number` that defines the restitution (elasticity) of the body. The value is always positive and is in the range `(0, 1)`. 979 * A value of `0` means collisions may be perfectly inelastic and no bouncing may occur. 980 * A value of `0.8` means the body may bounce back with approximately 80% of its kinetic energy. 981 * Note that collision response is based on _pairs_ of bodies, and that `restitution` values are _combined_ with the following formula: 982 * 983 * Math.max(bodyA.restitution, bodyB.restitution) 984 * 985 * @property restitution 986 * @type number 987 * @default 0 988 */ 989 990 /** 991 * A `Number` that defines the friction of the body. The value is always positive and is in the range `(0, 1)`.
992 * A value of `0` means that the body may slide indefinitely. 993 * A value of `1` means the body may come to a stop almost instantly after a force is applied. 994 * 995 * The effects of the value may be non-linear. 996 * High values may be unstable depending on the body. 997 * The engine uses a Coulomb friction model including static and kinetic friction. 998 * Note that collision response is based on _pairs_ of bodies, and that `friction` values are _combined_ with the following formula: 999 * 1000 * Math.min(bodyA.friction, bodyB.friction) 1001 * 1002 * @property friction 1003 * @type number 1004 * @default 0.1 1005 */ 1006 1007 /** 1008 * A `Number` that defines the static friction of the body (in the Coulomb friction model). 1009 * A value of `0` means the body will never 'stick' when it is nearly stationary and only dynamic `friction` is used. 1010 * The higher the value (e.g. `10`), the more force it will take to initially get the body moving when nearly stationary. 1011 * This value is multiplied with the `friction` property to make it easier to change `friction` and maintain an appropriate amount of static friction. 1012 * 1013 * @property frictionStatic 1014 * @type number 1015 * @default 0.5 1016 */ 1017 1018 /** 1019 * A `Number` that defines the air friction of the body (air resistance). 1020 * A value of `0` means the body will never slow as it moves through space. 1021 * The higher the value, the faster a body slows when moving through space. 1022 * The effects of the value are non-linear. 1023 * 1024 * @property frictionAir 1025 * @type number 1026 * @default 0.01 1027 */ 1028 1029 /** 1030 * An `Object` that specifies the collision filtering properties of this body. 1031 * 1032 * Collisions between two bodies will obey the following rules: 1033 * - If the two bodies have the same non-zero value of `collisionFilter.group`, 1034 * they will always collide if the value is positive, and they will never collide 1035 * if the value is negative. 1036 * - If the two bodies have different values of `collisionFilter.group` or if one 1037 * (or both) of the bodies has a value of 0, then the category/mask rules apply as follows: 1038 * 1039 * Each body belongs to a collision category, given by `collisionFilter.category`. This 1040 * value is used as a bit field and the category should have only one bit set, meaning that 1041 * the value of this property is a power of two in the range [1, 2^31]. Thus, there are 32 1042 * different collision categories available. 1043 * 1044 * Each body also defines a collision bitmask, given by `collisionFilter.mask` which specifies 1045 * the categories it collides with (the value is the bitwise AND value of all these categories). 1046 * 1047 * Using the category/mask rules, two bodies `A` and `B` collide if each includes the other's 1048 * category in its mask, i.e. `(categoryA & maskB) !== 0` and `(categoryB & maskA) !== 0` 1049 * are both true. 1050 * 1051 * @property collisionFilter 1052 * @type object 1053 */ 1054 1055 /** 1056 * An Integer `Number`, that specifies the collision group this body belongs to. 1057 * See `body.collisionFilter` for more information. 1058 * 1059 * @property collisionFilter.group 1060 * @type object 1061 * @default 0 1062 */ 1063 1064 /** 1065 * A bit field that specifies the collision category this body belongs to. 1066 * The category value should have only one bit set, for example `0x0001`. 1067 * This means there are up to 32 unique collision categories available. 1068 * See `body.collisionFilter` for more information. 1069 * 1070 * @property collisionFilter.category 1071 * @type object 1072 * @default 1 1073 */ 1074 1075 /** 1076 * A bit mask that specifies the collision categories this body may collide with. 1077 * See `body.collisionFilter` for more information. 1078 * 1079 * @property collisionFilter.mask 1080 * @type object 1081 * @default -1 1082 */ 1083 1084 /** 1085 * A `Number` that specifies a tolerance on how far a body is allowed to 'sink' or rotate into other bodies. 1086 * Avoid changing this value unless you understand the purpose of `slop` in physics engines. 1087 * The default should generally suffice, although very large bodies may require larger values for stable stacking. 1088 * 1089 * @property slop 1090 * @type number 1091 * @default 0.05 1092 */ 1093 1094 /** 1095 * A `Number` that allows per-body time scaling, e.g. a force-field where bodies inside are in slow-motion, while others are at full speed. 1096 * 1097 * @property timeScale 1098 * @type number 1099 * @default 1 1100 */ 1101 1102 /** 1103 * An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`. 1104 * 1105 * @property render 1106 * @type object 1107 */ 1108 1109 /** 1110 * A flag that indicates if the body should be rendered. 1111 * 1112 * @property render.visible 1113 * @type boolean 1114 * @default true 1115 */ 1116 1117 /** 1118 * Sets the opacity to use when rendering. 1119 * 1120 * @property render.opacity 1121 * @type number 1122 * @default 1 1123 */ 1124 1125 /** 1126 * An `Object` that defines the sprite properties to use when rendering, if any. 1127 * 1128 * @property render.sprite 1129 * @type object 1130 */ 1131 1132 /** 1133 * An `String` that defines the path to the image to use as the sprite texture, if any. 1134 * 1135 * @property render.sprite.texture 1136 * @type string 1137 */ 1138 1139 /** 1140 * A `Number` that defines the scaling in the x-axis for the sprite, if any. 1141 * 1142 * @property render.sprite.xScale 1143 * @type number 1144 * @default 1 1145 */ 1146 1147 /** 1148 * A `Number` that defines the scaling in the y-axis for the sprite, if any. 1149 * 1150 * @property render.sprite.yScale 1151 * @type number 1152 * @default 1 1153 */ 1154 1155 /** 1156 * A `Number` that defines the offset in the x-axis for the sprite (normalised by texture width). 1157 * 1158 * @property render.sprite.xOffset 1159 * @type number 1160 * @default 0 1161 */ 1162 1163 /** 1164 * A `Number` that defines the offset in the y-axis for the sprite (normalised by texture height). 1165 * 1166 * @property render.sprite.yOffset 1167 * @type number 1168 * @default 0 1169 */ 1170 1171 /** 1172 * A `Number` that defines the line width to use when rendering the body outline (if a sprite is not defined). 1173 * A value of `0` means no outline will be rendered. 1174 * 1175 * @property render.lineWidth 1176 * @type number 1177 * @default 0 1178 */ 1179 1180 /** 1181 * A `String` that defines the fill style to use when rendering the body (if a sprite is not defined). 1182 * It is the same as when using a canvas, so it accepts CSS style property values. 1183 * 1184 * @property render.fillStyle 1185 * @type string 1186 * @default a random colour 1187 */ 1188 1189 /** 1190 * A `String` that defines the stroke style to use when rendering the body outline (if a sprite is not defined). 1191 * It is the same as when using a canvas, so it accepts CSS style property values. 1192 * 1193 * @property render.strokeStyle 1194 * @type string 1195 * @default a random colour 1196 */ 1197 1198 /** 1199 * An array of unique axis vectors (edge normals) used for c
vendor: 16,384 bytes, lines 1199-1681
1199ollision detection. 1200 * These are automatically calculated from the given convex hull (`vertices` array) in `Body.create`. 1201 * They are constantly updated by `Body.update` during the simulation. 1202 * 1203 * @property axes 1204 * @type vector[] 1205 */ 1206 1207 /** 1208 * A `Number` that _measures_ the area of the body's convex hull, calculated at creation by `Body.create`. 1209 * 1210 * @property area 1211 * @type string 1212 * @default 1213 */ 1214 1215 /** 1216 * A `Bounds` object that defines the AABB region for the body. 1217 * It is automatically calculated from the given convex hull (`vertices` array) in `Body.create` and constantly updated by `Body.update` during simulation. 1218 * 1219 * @property bounds 1220 * @type bounds 1221 */ 1222 1223})(); 1224 1225},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31}],2:[function(_dereq_,module,exports){ 1226/** 1227* The `Matter.Composite` module contains methods for creating and manipulating composite bodies. 1228* A composite body is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite`, therefore composites form a tree structure. 1229* It is important to use the functions in this module to modify composites, rather than directly modifying their properties. 1230* Note that the `Matter.World` object is also a type of `Matter.Composite` and as such all composite methods here can also operate on a `Matter.World`. 1231* 1232* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 1233* 1234* @class Composite 1235*/ 1236 1237var Composite = {}; 1238 1239module.exports = Composite; 1240 1241var Events = _dereq_('../core/Events'); 1242var Common = _dereq_('../core/Common'); 1243var Bounds = _dereq_('../geometry/Bounds'); 1244var Body = _dereq_('./Body'); 1245 1246(function() { 1247 1248 /** 1249 * Creates a new composite. The options parameter is an object that specifies any properties you wish to override the defaults. 1250 * See the properites section below for detailed information on what you can pass via the `options` object. 1251 * @method create 1252 * @param {} [options] 1253 * @return {composite} A new composite 1254 */ 1255 Composite.create = function(options) { 1256 return Common.extend({ 1257 id: Common.nextId(), 1258 type: 'composite', 1259 parent: null, 1260 isModified: false, 1261 bodies: [], 1262 constraints: [], 1263 composites: [], 1264 label: 'Composite', 1265 plugin: {} 1266 }, options); 1267 }; 1268 1269 /** 1270 * Sets the composite's `isModified` flag. 1271 * If `updateParents` is true, all parents will be set (default: false). 1272 * If `updateChildren` is true, all children will be set (default: false). 1273 * @method setModified 1274 * @param {composite} composite 1275 * @param {boolean} isModified 1276 * @param {boolean} [updateParents=false] 1277 * @param {boolean} [updateChildren=false] 1278 */ 1279 Composite.setModified = function(composite, isModified, updateParents, updateChildren) { 1280 composite.isModified = isModified; 1281 1282 if (updateParents && composite.parent) { 1283 Composite.setModified(composite.parent, isModified, updateParents, updateChildren); 1284 } 1285 1286 if (updateChildren) { 1287 for(var i = 0; i < composite.composites.length; i++) { 1288 var childComposite = composite.composites[i]; 1289 Composite.setModified(childComposite, isModified, updateParents, updateChildren); 1290 } 1291 } 1292 }; 1293 1294 /** 1295 * Generic add function. Adds one or many body(s), constraint(s) or a composite(s) to the given composite. 1296 * Triggers `beforeAdd` and `afterAdd` events on the `composite`. 1297 * @method add 1298 * @param {composite} composite 1299 * @param {} object 1300 * @return {composite} The original composite with the objects added 1301 */ 1302 Composite.add = function(composite, object) { 1303 var objects = [].concat(object); 1304 1305 Events.trigger(composite, 'beforeAdd', { object: object }); 1306 1307 for (var i = 0; i < objects.length; i++) { 1308 var obj = objects[i]; 1309 1310 switch (obj.type) { 1311 1312 case 'body': 1313 // skip adding compound parts 1314 if (obj.parent !== obj) { 1315 Common.warn('Composite.add: skipped adding a compound body part (you must add its parent instead)'); 1316 break; 1317 } 1318 1319 Composite.addBody(composite, obj); 1320 break; 1321 case 'constraint': 1322 Composite.addConstraint(composite, obj); 1323 break; 1324 case 'composite': 1325 Composite.addComposite(composite, obj); 1326 break; 1327 case 'mouseConstraint': 1328 Composite.addConstraint(composite, obj.constraint); 1329 break; 1330 1331 } 1332 } 1333 1334 Events.trigger(composite, 'afterAdd', { object: object }); 1335 1336 return composite; 1337 }; 1338 1339 /** 1340 * Generic remove function. Removes one or many body(s), constraint(s) or a composite(s) to the given composite. 1341 * Optionally searching its children recursively. 1342 * Triggers `beforeRemove` and `afterRemove` events on the `composite`. 1343 * @method remove 1344 * @param {composite} composite 1345 * @param {} object 1346 * @param {boolean} [deep=false] 1347 * @return {composite} The original composite with the objects removed 1348 */ 1349 Composite.remove = function(composite, object, deep) { 1350 var objects = [].concat(object); 1351 1352 Events.trigger(composite, 'beforeRemove', { object: object }); 1353 1354 for (var i = 0; i < objects.length; i++) { 1355 var obj = objects[i]; 1356 1357 switch (obj.type) { 1358 1359 case 'body': 1360 Composite.removeBody(composite, obj, deep); 1361 break; 1362 case 'constraint': 1363 Composite.removeConstraint(composite, obj, deep); 1364 break; 1365 case 'composite': 1366 Composite.removeComposite(composite, obj, deep); 1367 break; 1368 case 'mouseConstraint': 1369 Composite.removeConstraint(composite, obj.constraint); 1370 break; 1371 1372 } 1373 } 1374 1375 Events.trigger(composite, 'afterRemove', { object: object }); 1376 1377 return composite; 1378 }; 1379 1380 /** 1381 * Adds a composite to the given composite. 1382 * @private 1383 * @method addComposite 1384 * @param {composite} compositeA 1385 * @param {composite} compositeB 1386 * @return {composite} The original compositeA with the objects from compositeB added 1387 */ 1388 Composite.addComposite = function(compositeA, compositeB) { 1389 compositeA.composites.push(compositeB); 1390 compositeB.parent = compositeA; 1391 Composite.setModified(compositeA, true, true, false); 1392 return compositeA; 1393 }; 1394 1395 /** 1396 * Removes a composite from the given composite, and optionally searching its children recursively. 1397 * @private 1398 * @method removeComposite 1399 * @param {composite} compositeA 1400 * @param {composite} compositeB 1401 * @param {boolean} [deep=false] 1402 * @return {composite} The original compositeA with the composite removed 1403 */ 1404 Composite.removeComposite = function(compositeA, compositeB, deep) { 1405 var position = Common.indexOf(compositeA.composites, compositeB); 1406 if (position !== -1) { 1407 Composite.removeCompositeAt(compositeA, position); 1408 Composite.setModified(compositeA, true, true, false); 1409 } 1410 1411 if (deep) { 1412 for (var i = 0; i < compositeA.composites.length; i++){ 1413 Composite.removeComposite(compositeA.composites[i], compositeB, true); 1414 } 1415 } 1416 1417 return compositeA; 1418 }; 1419 1420 /** 1421 * Removes a composite from the given composite. 1422 * @private 1423 * @method removeCompositeAt 1424 * @param {composite} composite 1425 * @param {number} position 1426 * @return {composite} The original composite with the composite removed 1427 */ 1428 Composite.removeCompositeAt = function(composite, position) { 1429 composite.composites.splice(position, 1); 1430 Composite.setModified(composite, true, true, false); 1431 return composite; 1432 }; 1433 1434 /** 1435 * Adds a body to the given composite. 1436 * @private 1437 * @method addBody 1438 * @param {composite} composite 1439 * @param {body} body 1440 * @return {composite} The original composite with the body added 1441 */ 1442 Composite.addBody = function(composite, body) { 1443 composite.bodies.push(body); 1444 Composite.setModified(composite, true, true, false); 1445 return composite; 1446 }; 1447 1448 /** 1449 * Removes a body from the given composite, and optionally searching its children recursively. 1450 * @private 1451 * @method removeBody 1452 * @param {composite} composite 1453 * @param {body} body 1454 * @param {boolean} [deep=false] 1455 * @return {composite} The original composite with the body removed 1456 */ 1457 Composite.removeBody = function(composite, body, deep) { 1458 var position = Common.indexOf(composite.bodies, body); 1459 if (position !== -1) { 1460 Composite.removeBodyAt(composite, position); 1461 Composite.setModified(composite, true, true, false); 1462 } 1463 1464 if (deep) { 1465 for (var i = 0; i < composite.composites.length; i++){ 1466 Composite.removeBody(composite.composites[i], body, true); 1467 } 1468 } 1469 1470 return composite; 1471 }; 1472 1473 /** 1474 * Removes a body from the given composite. 1475 * @private 1476 * @method removeBodyAt 1477 * @param {composite} composite 1478 * @param {number} position 1479 * @return {composite} The original composite with the body removed 1480 */ 1481 Composite.removeBodyAt = function(composite, position) { 1482 composite.bodies.splice(position, 1); 1483 Composite.setModified(composite, true, true, false); 1484 return composite; 1485 }; 1486 1487 /** 1488 * Adds a constraint to the given composite. 1489 * @private 1490 * @method addConstraint 1491 * @param {composite} composite 1492 * @param {constraint} constraint 1493 * @return {composite} The original composite with the constraint added 1494 */ 1495 Composite.addConstraint = function(composite, constraint) { 1496 composite.constraints.push(constraint); 1497 Composite.setModified(composite, true, true, false); 1498 return composite; 1499 }; 1500 1501 /** 1502 * Removes a constraint from the given composite, and optionally searching its children recursively. 1503 * @private 1504 * @method removeConstraint 1505 * @param {composite} composite 1506 * @param {constraint} constraint 1507 * @param {boolean} [deep=false] 1508 * @return {composite} The original composite with the constraint removed 1509 */ 1510 Composite.removeConstraint = function(composite, constraint, deep) { 1511 var position = Common.indexOf(composite.constraints, constraint); 1512 if (position !== -1) { 1513 Composite.removeConstraintAt(composite, position); 1514 } 1515 1516 if (deep) { 1517 for (var i = 0; i < composite.composites.length; i++){ 1518 Composite.removeConstraint(composite.composites[i], constraint, true); 1519 } 1520 } 1521 1522 return composite; 1523 }; 1524 1525 /** 1526 * Removes a body from the given composite. 1527 * @private 1528 * @method removeConstraintAt 1529 * @param {composite} composite 1530 * @param {number} position 1531 * @return {composite} The original composite with the constraint removed 1532 */ 1533 Composite.removeConstraintAt = function(composite, position) { 1534 composite.constraints.splice(position, 1); 1535 Composite.setModified(composite, true, true, false); 1536 return composite; 1537 }; 1538 1539 /** 1540 * Removes all bodies, constraints and composites from the given composite. 1541 * Optionally clearing its children recursively. 1542 * @method clear 1543 * @param {composite} composite 1544 * @param {boolean} keepStatic 1545 * @param {boolean} [deep=false] 1546 */ 1547 Composite.clear = function(composite, keepStatic, deep) { 1548 if (deep) { 1549 for (var i = 0; i < composite.composites.length; i++){ 1550 Composite.clear(composite.composites[i], keepStatic, true); 1551 } 1552 } 1553 1554 if (keepStatic) { 1555 composite.bodies = composite.bodies.filter(function(body) { return body.isStatic; }); 1556 } else { 1557 composite.bodies.length = 0; 1558 } 1559 1560 composite.constraints.length = 0; 1561 composite.composites.length = 0; 1562 Composite.setModified(composite, true, true, false); 1563 1564 return composite; 1565 }; 1566 1567 /** 1568 * Returns all bodies in the given composite, including all bodies in its children, recursively. 1569 * @method allBodies 1570 * @param {composite} composite 1571 * @return {body[]} All the bodies 1572 */ 1573 Composite.allBodies = function(composite) { 1574 var bodies = [].concat(composite.bodies); 1575 1576 for (var i = 0; i < composite.composites.length; i++) 1577 bodies = bodies.concat(Composite.allBodies(composite.composites[i])); 1578 1579 return bodies; 1580 }; 1581 1582 /** 1583 * Returns all constraints in the given composite, including all constraints in its children, recursively. 1584 * @method allConstraints 1585 * @param {composite} composite 1586 * @return {constraint[]} All the constraints 1587 */ 1588 Composite.allConstraints = function(composite) { 1589 var constraints = [].concat(composite.constraints); 1590 1591 for (var i = 0; i < composite.composites.length; i++) 1592 constraints = constraints.concat(Composite.allConstraints(composite.composites[i])); 1593 1594 return constraints; 1595 }; 1596 1597 /** 1598 * Returns all composites in the given composite, including all composites in its children, recursively. 1599 * @method allComposites 1600 * @param {composite} composite 1601 * @return {composite[]} All the composites 1602 */ 1603 Composite.allComposites = function(composite) { 1604 var composites = [].concat(composite.composites); 1605 1606 for (var i = 0; i < composite.composites.length; i++) 1607 composites = composites.concat(Composite.allComposites(composite.composites[i])); 1608 1609 return composites; 1610 }; 1611 1612 /** 1613 * Searches the composite recursively for an object matching the type and id supplied, null if not found. 1614 * @method get 1615 * @param {composite} composite 1616 * @param {number} id 1617 * @param {string} type 1618 * @return {object} The requested object, if found 1619 */ 1620 Composite.get = function(composite, id, type) { 1621 var objects, 1622 object; 1623 1624 switch (type) { 1625 case 'body': 1626 objects = Composite.allBodies(composite); 1627 break; 1628 case 'constraint': 1629 objects = Composite.allConstraints(composite); 1630 break; 1631 case 'composite': 1632 objects = Composite.allComposites(composite).concat(composite); 1633 break; 1634 } 1635 1636 if (!objects) 1637 return null; 1638 1639 object = objects.filter(function(object) { 1640 return object.id.toString() === id.toString(); 1641 }); 1642 1643 return object.length === 0 ? null : object[0]; 1644 }; 1645 1646 /** 1647 * Moves the given object(s) from compositeA to compositeB (equal to a remove followed by an add). 1648 * @method move 1649 * @param {compositeA} compositeA 1650 * @param {object[]} objects 1651 * @param {compositeB} compositeB 1652 * @return {composite} Returns compositeA 1653 */ 1654 Composite.move = function(compositeA, objects, compositeB) { 1655 Composite.remove(compositeA, objects); 1656 Composite.add(compositeB, objects); 1657 return compositeA; 1658 }; 1659 1660 /** 1661 * Assigns new ids for all objects in the composite, recursively. 1662 * @method rebase 1663 * @param {composite} composite 1664 * @return {composite} Returns composite 1665 */ 1666 Composite.rebase = function(composite) { 1667 var objects = Composite.allBodies(composite) 1668 .concat(Composite.allConstraints(composite)) 1669 .concat(Composite.allComposites(composite)); 1670 1671 for (var i = 0; i < objects.length; i++) { 1672 objects[i].id = Common.nextId(); 1673 } 1674 1675 Composite.setModified(composite, true, true, false); 1676 1677 return composite; 1678 }; 1679 1680 /** 1681 * Translates all children in the composite by
1681a given vector relative to their current positions, 1682 * without imparting any velocity. 1683 * @method translate 1684 * @param {composite} composite 1685 * @param {vector} translation 1686 * @param {bool} [recursive=true] 1687 */ 1688 Composite.translate = function(composite, translation, recursive) { 1689 var bodies = recursive ? Composite.allBodies(composite) : composite.bodies; 1690 1691 for (var i = 0; i < bodies.length; i++) { 1692 Body.translate(bodies[i], translation); 1693 } 1694 1695 Composite.setModified(composite, true, true, false); 1696 1697 return composite; 1698 }; 1699 1700 /** 1701 * Rotates all children in the composite by a given angle about the given point, without imparting any angular velocity. 1702 * @method rotate 1703 * @param {composite} composite 1704 * @param {number} rotation 1705 * @param {vector} point 1706 * @param {bool} [recursive=true] 1707 */ 1708 Composite.rotate = function(composite, rotation, point, recursive) { 1709 var cos = Math.cos(rotation), 1710 sin = Math.sin(rotation), 1711 bodies = recursive ? Composite.allBodies(composite) : composite.bodies; 1712 1713 for (var i = 0; i < bodies.length; i++) { 1714 var body = bodies[i], 1715 dx = body.position.x - point.x, 1716 dy = body.position.y - point.y; 1717 1718 Body.setPosition(body, { 1719 x: point.x + (dx * cos - dy * sin), 1720 y: point.y + (dx * sin + dy * cos) 1721 }); 1722 1723 Body.rotate(body, rotation); 1724 } 1725 1726 Composite.setModified(composite, true, true, false); 1727 1728 return composite; 1729 }; 1730 1731 /** 1732 * Scales all children in the composite, including updating physical properties (mass, area, axes, inertia), from a world-space point. 1733 * @method scale 1734 * @param {composite} composite 1735 * @param {number} scaleX 1736 * @param {number} scaleY 1737 * @param {vector} point 1738 * @param {bool} [recursive=true] 1739 */ 1740 Composite.scale = function(composite, scaleX, scaleY, point, recursive) { 1741 var bodies = recursive ? Composite.allBodies(composite) : composite.bodies; 1742 1743 for (var i = 0; i < bodies.length; i++) { 1744 var body = bodies[i], 1745 dx = body.position.x - point.x, 1746 dy = body.position.y - point.y; 1747 1748 Body.setPosition(body, { 1749 x: point.x + dx * scaleX, 1750 y: point.y + dy * scaleY 1751 }); 1752 1753 Body.scale(body, scaleX, scaleY); 1754 } 1755 1756 Composite.setModified(composite, true, true, false); 1757 1758 return composite; 1759 }; 1760 1761 /** 1762 * Returns the union of the bounds of all of the composite's bodies. 1763 * @method bounds 1764 * @param {composite} composite The composite. 1765 * @returns {bounds} The composite bounds. 1766 */ 1767 Composite.bounds = function(composite) { 1768 var bodies = Composite.allBodies(composite), 1769 vertices = []; 1770 1771 for (var i = 0; i < bodies.length; i += 1) { 1772 var body = bodies[i]; 1773 vertices.push(body.bounds.min, body.bounds.max); 1774 } 1775 1776 return Bounds.create(vertices); 1777 }; 1778 1779 /* 1780 * 1781 * Events Documentation 1782 * 1783 */ 1784 1785 /** 1786 * Fired when a call to `Composite.add` is made, before objects have been added. 1787 * 1788 * @event beforeAdd 1789 * @param {} event An event object 1790 * @param {} event.object The object(s) to be added (may be a single body, constraint, composite or a mixed array of these) 1791 * @param {} event.source The source object of the event 1792 * @param {} event.name The name of the event 1793 */ 1794 1795 /** 1796 * Fired when a call to `Composite.add` is made, after objects have been added. 1797 * 1798 * @event afterAdd 1799 * @param {} event An event object 1800 * @param {} event.object The object(s) that have been added (may be a single body, constraint, composite or a mixed array of these) 1801 * @param {} event.source The source object of the event 1802 * @param {} event.name The name of the event 1803 */ 1804 1805 /** 1806 * Fired when a call to `Composite.remove` is made, before objects have been removed. 1807 * 1808 * @event beforeRemove 1809 * @param {} event An event object 1810 * @param {} event.object The object(s) to be removed (may be a single body, constraint, composite or a mixed array of these) 1811 * @param {} event.source The source object of the event 1812 * @param {} event.name The name of the event 1813 */ 1814 1815 /** 1816 * Fired when a call to `Composite.remove` is made, after objects have been removed. 1817 * 1818 * @event afterRemove 1819 * @param {} event An event object 1820 * @param {} event.object The object(s) that have been removed (may be a single body, constraint, composite or a mixed array of these) 1821 * @param {} event.source The source object of the event 1822 * @param {} event.name The name of the event 1823 */ 1824 1825 /* 1826 * 1827 * Properties Documentation 1828 * 1829 */ 1830 1831 /** 1832 * An integer `Number` uniquely identifying number generated in `Composite.create` by `Common.nextId`. 1833 * 1834 * @property id 1835 * @type number 1836 */ 1837 1838 /** 1839 * A `String` denoting the type of object. 1840 * 1841 * @property type 1842 * @type string 1843 * @default "composite" 1844 * @readOnly 1845 */ 1846 1847 /** 1848 * An arbitrary `String` name to help the user identify and manage composites. 1849 * 1850 * @property label 1851 * @type string 1852 * @default "Composite" 1853 */ 1854 1855 /** 1856 * A flag that specifies whether the composite has been modified during the current step. 1857 * Most `Matter.Composite` methods will automatically set this flag to `true` to inform the engine of changes to be handled. 1858 * If you need to change it manually, you should use the `Composite.setModified` method. 1859 * 1860 * @property isModified 1861 * @type boolean 1862 * @default false 1863 */ 1864 1865 /** 1866 * The `Composite` that is the parent of this composite. It is automatically managed by the `Matter.Composite` methods. 1867 * 1868 * @property parent 1869 * @type composite 1870 * @default null 1871 */ 1872 1873 /** 1874 * An array of `Body` that are _direct_ children of this composite. 1875 * To add or remove bodies you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property. 1876 * If you wish to recursively find all descendants, you should use the `Composite.allBodies` method. 1877 * 1878 * @property bodies 1879 * @type body[] 1880 * @default [] 1881 */ 1882 1883 /** 1884 * An array of `Constraint` that are _direct_ children of this composite. 1885 * To add or remove constraints you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property. 1886 * If you wish to recursively find all descendants, you should use the `Composite.allConstraints` method. 1887 * 1888 * @property constraints 1889 * @type constraint[] 1890 * @default [] 1891 */ 1892 1893 /** 1894 * An array of `Composite` that are _direct_ children of this composite. 1895 * To add or remove composites you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property. 1896 * If you wish to recursively find all descendants, you should use the `Composite.allComposites` method. 1897 * 1898 * @property composites 1899 * @type composite[] 1900 * @default [] 1901 */ 1902 1903 /** 1904 * An object reserved for storing plugin-specific properties. 1905 * 1906 * @property plugin 1907 * @type {} 1908 */ 1909 1910})(); 1911 1912},{"../core/Common":14,"../core/Events":16,"../geometry/Bounds":26,"./Body":1}],3:[function(_dereq_,module,exports){ 1913/** 1914* The `Matter.World` module contains methods for creating and manipulating the world composite. 1915* A `Matter.World` is a `Matter.Composite` body, which is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite`. 1916* A `Matter.World` has a few additional properties including `gravity` and `bounds`. 1917* It is important to use the functions in the `Matter.Composite` module to modify the world composite, rather than directly modifying its properties. 1918* There are also a few methods here that alias those in `Matter.Composite` for easier readability. 1919* 1920* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 1921* 1922* @class World 1923* @extends Composite 1924*/ 1925 1926var World = {}; 1927 1928module.exports = World; 1929 1930var Composite = _dereq_('./Composite'); 1931var Constraint = _dereq_('../constraint/Constraint'); 1932var Common = _dereq_('../core/Common'); 1933 1934(function() { 1935 1936 /** 1937 * Creates a new world composite. The options parameter is an object that specifies any properties you wish to override the defaults. 1938 * See the properties section below for detailed information on what you can pass via the `options` object. 1939 * @method create 1940 * @constructor 1941 * @param {} options 1942 * @return {world}
1942 A new world 1943 */ 1944 World.create = function(options) { 1945 var composite = Composite.create(); 1946 1947 var defaults = { 1948 label: 'World', 1949 gravity: { 1950 x: 0, 1951 y: 1, 1952 scale: 0.001 1953 }, 1954 bounds: { 1955 min: { x: -Infinity, y: -Infinity }, 1956 max: { x: Infinity, y: Infinity } 1957 } 1958 }; 1959 1960 return Common.extend(composite, defaults, options); 1961 }; 1962 1963 /* 1964 * 1965 * Properties Documentation 1966 * 1967 */ 1968 1969 /** 1970 * The gravity to apply on the world. 1971 * 1972 * @property gravity 1973 * @type object 1974 */ 1975 1976 /** 1977 * The gravity x component. 1978 * 1979 * @property gravity.x 1980 * @type object 1981 * @default 0 1982 */ 1983 1984 /** 1985 * The gravity y component. 1986 * 1987 * @property gravity.y 1988 * @type object 1989 * @default 1 1990 */ 1991 1992 /** 1993 * The gravity scale factor. 1994 * 1995 * @property gravity.scale 1996 * @type object 1997 * @default 0.001 1998 */ 1999 2000 /** 2001 * A `Bounds` object that defines the world bounds for collision detection. 2002 * 2003 * @property bounds 2004 * @type bounds 2005 * @default { min: { x: -Infinity, y: -Infinity }, max: { x: Infinity, y: Infinity } } 2006 */ 2007 2008 // World is a Composite body 2009 // see src/module/Outro.js for these aliases: 2010 2011 /** 2012 * An alias for Composite.add 2013 * @method add 2014 * @param {world} world 2015 * @param {} object 2016 * @return {composite} The original world with the objects added 2017 */ 2018 2019 /** 2020 * An alias for Composite.remove 2021 * @method remove 2022 * @param {world} world 2023 * @param {} object 2024 * @param {boolean} [deep=false] 2025 * @return {composite} The original world with the objects removed 2026 */ 2027 2028 /** 2029 * An alias for Composite.clear 2030 * @method clear 2031 * @param {world} world 2032 * @param {boolean} keepStatic 2033 */ 2034 2035 /** 2036 * An alias for Composite.addComposite 2037 * @method addComposite 2038 * @param {world} world 2039 * @param {composite} composite 2040 * @return {world} The original world with the objects from composite added 2041 */ 2042 2043 /** 2044 * An alias for Composite.addBody 2045 * @method addBody 2046 * @param {world} world 2047 * @param {body} body 2048 * @return {world} The original world with the body added 2049 */ 2050 2051 /** 2052 * An alias for Composite.addConstraint 2053 * @method addConstraint 2054 * @param {world} world 2055 * @param {constraint} constraint 2056 * @return {world} The original world with the constraint added 2057 */ 2058 2059})(); 2060 2061},{"../constraint/Constraint":12,"../core/Common":14,"./Composite":2}],4:[function(_dereq_,module,exports){ 2062/** 2063* The `Matter.Contact` module contains methods for creating and manipulating collision contacts. 2064* 2065* @class Contact 2066*/ 2067 2068var Contact = {}; 2069 2070module.exports = Contact; 2071 2072(function() { 2073 2074 /** 2075 * Creates a new contact. 2076 * @method create 2077 * @param {vertex} vertex 2078 * @return {contact} A new contact 2079 */ 2080 Contact.create = function(vertex) { 2081 return { 2082 id: Contact.id(vertex), 2083 vertex: vertex, 2084 normalImpulse: 0, 2085 tangentImpulse: 0 2086 }; 2087 }; 2088 2089 /** 2090 * Generates a contact id. 2091 * @method id 2092 * @param {vertex} vertex 2093 * @return {string} Unique contactID 2094 */ 2095 Contact.id = function(vertex) { 2096 return vertex.body.id + '_' + vertex.index; 2097 }; 2098 2099})(); 2100 2101},{}],5:[function(_dereq_,module,exports){ 2102/** 2103* The `Matter.Detector` module contains methods for detecting collisions given a set of pairs. 2104* 2105* @class Detector 2106*/ 2107 2108// TODO: speculative contacts 2109 2110var Detector = {}; 2111 2112module.exports = Detector; 2113 2114var SAT = _dereq_('./SAT'); 2115var Pair = _dereq_('./Pair'); 2116var Bounds = _dereq_('../geometry/Bounds'); 2117 2118(function() { 2119 2120 /** 2121 * Finds all collisions given a list of pairs. 2122 * @method collisions 2123 * @param {pair[]} broadphasePairs 2124 * @param {engine} engine 2125 * @return {array} collisions 2126 */ 2127 Detector.collisions = function(broadphasePairs, engine) { 2128 var collisions = [], 2129 pairsTable = engine.pairs.table; 2130 2131 2132 for (var i = 0; i < broadphasePairs.length; i++) { 2133 var bodyA = broadphasePairs[i][0], 2134 bodyB = broadphasePairs[i][1]; 2135 2136 if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping)) 2137 continue; 2138 2139 if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) 2140 continue; 2141 2142 2143 // mid phase 2144 if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) { 2145 for (var j = bodyA.parts.length > 1 ? 1 : 0; j < bodyA.parts.length; j++) { 2146 var partA = bodyA.parts[j]; 2147 2148 for (var k = bodyB.parts.length > 1 ? 1 : 0; k < bodyB.parts.length; k++) { 2149 var partB = bodyB.parts[k]; 2150 2151 if ((partA === bodyA && partB === bodyB) || Bounds.overlaps(partA.bounds, partB.bounds)) {
2152 // find a previous collision we could reuse 2153 var pairId = Pair.id(partA, partB), 2154 pair = pairsTable[pairId], 2155 previousCollision; 2156 2157 if (pair && pair.isActive) { 2158 previousCollision = pair.collision; 2159 } else { 2160 previousCollision = null; 2161 } 2162 2163 // narrow phase 2164 var collision = SAT.collides(partA, partB, previousCollision); 2165 2166 2167 if (collision.collided) { 2168 collisions.push(collision); 2169 } 2170 } 2171 } 2172 } 2173 } 2174 } 2175 2176 return collisions; 2177 }; 2178 2179 /** 2180 * Returns `true` if both supplied collision filters will allow a collision to occur. 2181 * See `body.collisionFilter` for more information. 2182 * @method canCollide 2183 * @param {} filterA 2184 * @param {} filterB 2185 * @return {bool} `true` if collision can occur 2186 */ 2187 Detector.canCollide = function(filterA, filterB) { 2188 if (filterA.group === filterB.group && filterA.group !== 0) 2189 return filterA.group > 0; 2190 2191 return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0; 2192 }; 2193 2194})(); 2195 2196},{"../geometry/Bounds":26,"./Pair":7,"./SAT":11}],6:[function(_dereq_,module,exports){ 2197/** 2198* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures. 2199* 2200* @class Grid 2201*/ 2202 2203var Grid = {}; 2204 2205module.exports = Grid; 2206 2207var Pair = _dereq_('./Pair'); 2208var Detector = _dereq_('./Detector'); 2209var Common = _dereq_('../core/Common'); 2210 2211(function() { 2212 2213 /** 2214 * Creates a new grid. 2215 * @method create 2216 * @param {} options 2217 * @return {grid} A new grid 2218 */ 2219 Grid.create = function(options) { 2220 var defaults = { 2221 controller: Grid, 2222 detector: Detector.collisions, 2223 buckets: {}, 2224 pairs: {}, 2225 pairsList: [], 2226 bucketWidth: 48, 2227 bucketHeight: 48 2228 }; 2229 2230 return Common.extend(defaults, options); 2231 }; 2232 2233 /** 2234 * The width of a single grid bucket. 2235 * 2236 * @property bucketWidth 2237 * @type number 2238 * @default 48 2239 */ 2240 2241 /** 2242 * The height of a single grid bucket. 2243 * 2244 * @property bucketHeight 2245 * @type number 2246 * @default 48 2247 */ 2248 2249 /** 2250 * Updates the grid. 2251 * @method update 2252 * @param {grid} grid 2253 * @param {body[]} bodies 2254 * @param {engine} engine 2255 * @param {boolean} forceUpdate 2256 */ 2257 Grid.update = function(grid, bodies, engine, forceUpdate) { 2258 var i, col, row, 2259 world = engine.world, 2260 buckets = grid.buckets, 2261 bucket, 2262 bucketId, 2263 gridChanged = false; 2264 2265 2266 for (i = 0; i < bodies.length; i++) { 2267 var body = bodies[i]; 2268 2269 if (body.isSleeping && !forceUpdate) 2270 continue; 2271 2272 // don't update out of world bodies 2273 if (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x 2274 || body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y) 2275 continue; 2276 2277 var newRegion = Grid._getRegion(grid, body); 2278 2279 // if the body has changed grid region 2280 if (!body.region || newRegion.id !== body.region.id || forceUpdate) { 2281 2282
vendor: 4,380 bytes, lines 2283-2410
2283 if (!body.region || forceUpdate) 2284 body.region = newRegion; 2285 2286 var union = Grid._regionUnion(newRegion, body.region); 2287 2288 // update grid buckets affected by region change 2289 // iterate over the union of both regions 2290 for (col = union.startCol; col <= union.endCol; col++) { 2291 for (row = union.startRow; row <= union.endRow; row++) { 2292 bucketId = Grid._getBucketId(col, row); 2293 bucket = buckets[bucketId]; 2294 2295 var isInsideNewRegion = (col >= newRegion.startCol && col <= newRegion.endCol 2296 && row >= newRegion.startRow && row <= newRegion.endRow); 2297 2298 var isInsideOldRegion = (col >= body.region.startCol && col <= body.region.endCol 2299 && row >= body.region.startRow && row <= body.region.endRow); 2300 2301 // remove from old region buckets 2302 if (!isInsideNewRegion && isInsideOldRegion) { 2303 if (isInsideOldRegion) { 2304 if (bucket) 2305 Grid._bucketRemoveBody(grid, bucket, body); 2306 } 2307 } 2308 2309 // add to new region buckets 2310 if (body.region === newRegion || (isInsideNewRegion && !isInsideOldRegion) || forceUpdate) { 2311 if (!bucket) 2312 bucket = Grid._createBucket(buckets, bucketId); 2313 Grid._bucketAddBody(grid, bucket, body); 2314 } 2315 } 2316 } 2317 2318 // set the new region 2319 body.region = newRegion; 2320 2321 // flag changes so we can update pairs 2322 gridChanged = true; 2323 } 2324 } 2325 2326 // update pairs list only if pairs changed (i.e. a body changed region) 2327 if (gridChanged) 2328 grid.pairsList = Grid._createActivePairsList(grid); 2329 }; 2330 2331 /** 2332 * Clears the grid. 2333 * @method clear 2334 * @param {grid} grid 2335 */ 2336 Grid.clear = function(grid) { 2337 grid.buckets = {}; 2338 grid.pairs = {}; 2339 grid.pairsList = []; 2340 }; 2341 2342 /** 2343 * Finds the union of two regions. 2344 * @method _regionUnion 2345 * @private 2346 * @param {} regionA 2347 * @param {} regionB 2348 * @return {} region 2349 */ 2350 Grid._regionUnion = function(regionA, regionB) { 2351 var startCol = Math.min(regionA.startCol, regionB.startCol), 2352 endCol = Math.max(regionA.endCol, regionB.endCol), 2353 startRow = Math.min(regionA.startRow, regionB.startRow), 2354 endRow = Math.max(regionA.endRow, regionB.endRow); 2355 2356 return Grid._createRegion(startCol, endCol, startRow, endRow); 2357 }; 2358 2359 /** 2360 * Gets the region a given body falls in for a given grid. 2361 * @method _getRegion 2362 * @private 2363 * @param {} grid 2364 * @param {} body 2365 * @return {} region 2366 */ 2367 Grid._getRegion = function(grid, body) { 2368 var bounds = body.bounds, 2369 startCol = Math.floor(bounds.min.x / grid.bucketWidth), 2370 endCol = Math.floor(bounds.max.x / grid.bucketWidth), 2371 startRow = Math.floor(bounds.min.y / grid.bucketHeight), 2372 endRow = Math.floor(bounds.max.y / grid.bucketHeight); 2373 2374 return Grid._createRegion(startCol, endCol, startRow, endRow); 2375 }; 2376 2377 /** 2378 * Creates a region. 2379 * @method _createRegion 2380 * @private 2381 * @param {} startCol 2382 * @param {} endCol 2383 * @param {} startRow 2384 * @param {} endRow 2385 * @return {} region 2386 */ 2387 Grid._createRegion = function(startCol, endCol, startRow, endRow) { 2388 return { 2389 id: startCol + ',' + endCol + ',' + startRow + ',' + endRow, 2390 startCol: startCol, 2391 endCol: endCol, 2392 startRow: startRow, 2393 endRow: endRow 2394 }; 2395 }; 2396 2397 /** 2398 * Gets the bucket id at the given position. 2399 * @method _getBucketId 2400 * @private 2401 * @param {} column 2402 * @param {} row 2403 * @return {string} bucket id 2404 */ 2405 Grid._getBucketId = function(column, row) { 2406 return 'C' + column + 'R' + row; 2407 }; 2408 2409 /** 2410 * Creates a bucket.
2411 * @method _createBucket 2412 * @private 2413 * @param {} buckets 2414 * @param {} bucketId 2415 * @return {} bucket 2416 */ 2417 Grid._createBucket = function(buckets, bucketId) { 2418 var bucket = buckets[bucketId] = []; 2419 return bucket; 2420 }; 2421 2422 /** 2423 * Adds a body to a bucket. 2424 * @method _bucketAddBody 2425 * @private 2426 * @param {} grid 2427 * @param {} bucket 2428 * @param {} body 2429 */ 2430 Grid._bucketAddBody = function(grid, bucket, body) { 2431 // add new pairs 2432 for (var i = 0; i < bucket.length; i++) { 2433 var bodyB = bucket[i]; 2434 2435 if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic)) 2436 continue; 2437 2438 // keep track of the number of buckets the pair exists in 2439 // important for Grid.update to work 2440 var pairId = Pair.id(body, bodyB), 2441 pair = grid.pairs[pairId]; 2442 2443 if (pair) { 2444 pair[2] += 1; 2445 } else { 2446 grid.pairs[pairId] = [body, bodyB, 1]; 2447 } 2448 } 2449 2450 // add to bodies (after pairs, otherwise pairs with self) 2451 bucket.push(body); 2452 }; 2453 2454 /** 2455 * Removes a body from a bucket. 2456 * @method _bucketRemoveBody 2457 * @private 2458 * @param {} grid 2459 * @param {} bucket 2460 * @param {} body 2461 */ 2462 Grid._bucketRemoveBody = function(grid, bucket, body) { 2463 // remove from bucket 2464 bucket.splice(Common.indexOf(bucket, body), 1); 2465 2466 // update pair counts 2467 for (var i = 0; i < bucket.length; i++) { 2468 // keep track of the number of buckets the pair exists in 2469 // important for _createActivePairsList to work 2470 var bodyB = bucket[i], 2471 pairId = Pair.id(body, bodyB), 2472 pair = grid.pairs[pairId]; 2473 2474 if (pair) 2475 pair[2] -= 1; 2476 } 2477 }; 2478 2479 /** 2480 * Generates a list of the active pairs in the grid. 2481 * @method _createActivePairsList 2482 * @private 2483 * @param {} grid 2484 * @return [] pairs 2485 */ 2486 Grid._createActivePairsList = function(grid) { 2487 var pairKeys, 2488 pair, 2489 pairs = []; 2490 2491 // grid.pairs is used as a hashmap 2492 pairKeys = Common.keys(grid.pairs); 2493 2494 // iterate over grid.pairs 2495 for (var k = 0; k < pairKeys.length; k++) { 2496 pair = grid.pairs[pairKeys[k]]; 2497 2498 // if pair exists in at least one bucket 2499 // it is a pair that needs further collision testing so push it 2500 if (pair[2] > 0) { 2501 pairs.push(pair); 2502 } else { 2503 delete grid.pairs[pairKeys[k]]; 2504 } 2505 } 2506 2507 return pairs; 2508 }; 2509 2510})(); 2511 2512},{"../core/Common":14,"./Detector":5,"./Pair":7}],7:[function(_dereq_,module,exports){ 2513/** 2514* The `Matter.Pair` module contains methods for creating and manipulating collision pairs. 2515* 2516* @class Pair 2517*/ 2518 2519var Pair = {}; 2520 2521module.exports = Pair; 2522 2523var Contact = _dereq_('./Contact'); 2524 2525(function() { 2526 2527 /** 2528 * Creates a pair. 2529 * @method create 2530 * @param {collision} collision 2531 * @param {number} timestamp 2532 * @return {pair} A new pair 2533 */ 2534 Pair.create = function(collision, timestamp) { 2535 var bodyA = collision.bodyA, 2536 bodyB = collision.bodyB, 2537 parentA = collision.parentA, 2538 parentB = collision.parentB; 2539 2540 var pair = { 2541 id: Pair.id(bodyA, bodyB), 2542 bodyA: bodyA, 2543 bodyB: bodyB, 2544 contacts: {}, 2545 activeContacts: [], 2546 separation: 0, 2547 isActive: true, 2548 isSensor: bodyA.isSensor || bodyB.isSensor, 2549 timeCreated: timestamp, 2550 timeUpdated: timestamp, 2551 inverseMass: parentA.inverseMass + parentB.inverseMass, 2552 friction: Math.min(parentA.friction, parentB.friction), 2553 frictionStatic: Math.max(parentA.frictionStatic, parentB.frictionStatic), 2554 restitution: Math.max(parentA.restitution, parentB.restitution), 2555 slop: Math.max(parentA.slop, parentB.slop) 2556 }; 2557 2558 Pair.update(pair, collision, timestamp); 2559 2560 return pair; 2561 }; 2562 2563 /** 2564 * Updates a pair given a collision. 2565 * @method update 2566 * @param {pair} pair 2567 * @param {collision} collision 2568 * @param {number} timestamp 2569 */ 2570 Pair.update = function(pair, collision, timestamp) { 2571 var contacts = pair.contacts, 2572 supports = collision.supports, 2573 activeContacts = pair.activeContacts, 2574 parentA = collision.parentA, 2575 parentB = collision.parentB; 2576 2577 pair.collision = collision; 2578 pair.inverseMass = parentA.inverseMass + parentB.inverseMass; 2579 pair.friction = Math.min(parentA.friction, parentB.friction); 2580 pair.frictionStatic = Math.max(parentA.frictionStatic, parentB.frictionStatic); 2581 pair.restitution = Math.max(parentA.restitution, parentB.restitution); 2582 pair.slop = Math.max(parentA.slop, parentB.slop); 2583 activeContacts.length = 0; 2584 2585 if (collision.collided) { 2586 for (var i = 0; i < supports.length; i++) { 2587 var support = supports[i],
2588 contactId = Contact.id(support), 2589 contact = contacts[contactId]; 2590 2591 if (contact) { 2592 activeContacts.push(contact); 2593 } else { 2594 activeContacts.push(contacts[contactId] = Contact.create(support)); 2595 } 2596 } 2597 2598 pair.separation = collision.depth; 2599 Pair.setActive(pair, true, timestamp); 2600 } else { 2601 if (pair.isActive === true) 2602 Pair.setActive(pair, false, timestamp); 2603 } 2604 }; 2605 2606 /** 2607 * Set a pair as active or inactive. 2608 * @method setActive 2609 * @param {pair} pair 2610 * @param {bool} isActive 2611 * @param {number} timestamp 2612 */ 2613 Pair.setActive = function(pair, isActive, timestamp) { 2614 if (isActive) { 2615 pair.isActive = true; 2616 pair.timeUpdated = timestamp; 2617 } else { 2618 pair.isActive = false; 2619 pair.activeContacts.length = 0; 2620 } 2621 }; 2622 2623 /** 2624 * Get the id for the given pair. 2625 * @method id 2626 * @param {body} bodyA 2627 * @param {body} bodyB 2628 * @return {string} Unique pairId 2629 */ 2630 Pair.id = function(bodyA, bodyB) { 2631 if (bodyA.id < bodyB.id) { 2632 return 'A' + bodyA.id + 'B' + bodyB.id; 2633 } else { 2634 return 'A' + bodyB.id + 'B' + bodyA.id; 2635 } 2636 }; 2637 2638})(); 2639 2640},{"./Contact":4}],8:[function(_dereq_,module,exports){ 2641/** 2642* The `Matter.Pairs` module contains methods for creating and manipulating collision pair sets. 2643* 2644* @class Pairs 2645*/ 2646 2647var Pairs = {}; 2648 2649module.exports = Pairs; 2650 2651var Pair = _dereq_('./Pair'); 2652var Common = _dereq_('../core/Common'); 2653 2654(function() { 2655 2656 Pairs._pairMaxIdleLife = 1000; 2657 2658 /** 2659 * Creates a new pairs structure. 2660 * @method create 2661 * @param {object} options 2662 * @return {pairs} A new pairs structure 2663 */ 2664 Pairs.create = function(options) { 2665 return Common.extend({ 2666 table: {}, 2667 list: [], 2668 collisionStart: [], 2669 collisionActive: [], 2670 collisionEnd: [] 2671 }, options); 2672 }; 2673 2674 /** 2675 * Updates pairs given a list of collisions. 2676 * @method update 2677 * @param {object} pairs 2678 * @param {collision[]} collisions 2679 * @param {number} timestamp 2680 */ 2681 Pairs.update = function(pairs, collisions, timestamp) { 2682 var pairsList = pairs.list, 2683 pairsTable = pairs.table, 2684 collisionStart = pairs.collisionStart, 2685 collisionEnd = pairs.collisionEnd, 2686 collisionActive = pairs.collisionActive, 2687 activePairIds = [], 2688 collision, 2689 pairId, 2690 pair, 2691 i; 2692 2693 // clear collision state arrays, but maintain old reference 2694 collisionStart.length = 0; 2695 collisionEnd.length = 0; 2696 collisionActive.length = 0; 2697 2698 for (i = 0; i < collisions.length; i++) { 2699 collision = collisions[i]; 2700 2701 if (collision.collided) { 2702 pairId = Pair.id(collision.bodyA, collision.bodyB); 2703 activePairIds.push(pairId); 2704 2705 pair = pairsTable[pairId]; 2706 2707 if (pair) { 2708 // pair already exists (but may or may not be active) 2709 if (pair.isActive) { 2710 // pair exists and is active 2711 collisionActive.push(pair); 2712 } else { 2713 // pair exists but was inactive, so a collision has just started again 2714 collisionStart.push(pair); 2715 } 2716 2717 // update the pair 2718 Pair.update(pair, collision, timestamp); 2719 } else { 2720 // pair did not exist, create a new pair 2721 pair = Pair.create(collision, timestamp); 2722 pairsTable[pairId] = pair; 2723 2724 // push the new pair 2725 collisionStart.push(pair); 2726 pairsList.push(pair); 2727 } 2728 } 2729 } 2730 2731 // deactivate previously active pairs that are now inactive 2732 for (i = 0; i < pairsList.length; i++) { 2733 pair = pairsList[i]; 2734 if (pair.isActive && Common.indexOf(activePairIds, pair.id) === -1) { 2735 Pair.setActive(pair, false, timestamp); 2736 collisionEnd.push(pair); 2737 } 2738 } 2739 }; 2740 2741 /** 2742 * Finds and removes pairs that have been inactive for a set amount of time. 2743 * @method removeOld 2744 * @param {object} pairs 2745 * @param {number} timestamp 2746 */ 2747 Pairs.removeOld = function(pairs, timestamp) { 2748 var pairsList = pairs.list, 2749 pairsTable = pairs.table, 2750 indexesToRemove = [], 2751 pair, 2752 collision, 2753 pairIndex, 2754 i; 2755 2756 for (i = 0; i < pairsList.length; i++) { 2757 pair = pairsList[i]; 2758 collision = pair.collision; 2759 2760 // never remove sleeping pairs 2761 if (collision.bodyA.isSleeping || collision.bodyB.isSleeping) { 2762 pair.timeUpdated = timestamp; 2763 continue; 2764 } 2765 2766 // if pair is inactive for too long, mark it to be removed 2767 if (timestamp - pair.timeUpdated > Pairs._pairMaxIdleLife) { 2768 indexesToRemove.push(i); 2769 } 2770 } 2771 2772 // remove marked pairs 2773 for (i = 0; i < indexesToRemove.length; i++) { 2774 pairIndex = indexesToRemove[i] - i; 2775 pair = pairsList[pairIndex]; 2776 delete pairsTable[pair.id]; 2777 pairsList.splice(pairIndex, 1); 2778 } 2779 }; 2780 2781 /** 2782 * Clears the given pairs structure. 2783 * @method clear 2784 * @param {pairs} pairs 2785 * @return {pairs} pairs 2786 */ 2787 Pairs.clear = function(pairs) { 2788 pairs.table = {}; 2789 pairs.list.length = 0; 2790 pairs.collisionStart.length = 0; 2791 pairs.collisionActive.length = 0; 2792 pairs.collisionEnd.length = 0; 2793 return pairs; 2794 }; 2795 2796})(); 2797 2798},{"../core/Common":14,"./Pair":7}],9:[function(_dereq_,module,exports){ 2799/** 2800* The `Matter.Query` module contains methods for performing collision queries. 2801* 2802* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 2803* 2804* @class Query 2805*/ 2806 2807var Query = {}; 2808 2809module.exports = Query; 2810 2811var Vector = _dereq_('../geometry/Vector'); 2812var SAT = _dereq_('./SAT'); 2813var Bounds = _dereq_('../geometry/Bounds'); 2814var Bodies = _dereq_('../factory/Bodies'); 2815var Vertices = _dereq_('../geometry/Vertices'); 2816 2817(function() { 2818 2819 /** 2820 * Returns a list of collisions between `body` and `bodies`. 2821 * @method collides 2822 * @param {body} body 2823 * @param {body[]} bodies 2824 * @return {object[]} Collisions 2825 */ 2826 Query.collides = function(body, bodies) { 2827 var collisions = []; 2828 2829 for (var i = 0; i < bodies.length; i++) { 2830 var bodyA = bodies[i]; 2831 2832 if (Bounds.overlaps(bodyA.bounds, body.bounds)) { 2833 for (var j = bodyA.parts.length === 1 ? 0 : 1; j < bodyA.parts.length; j++) { 2834 var part = bodyA.parts[j]; 2835 2836 if (Bounds.overlaps(part.bounds, body.bounds)) { 2837 var collision = SAT.collides(part, body); 2838 2839 if (collision.collided) { 2840 collisions.push(collision); 2841 break; 2842 } 2843 } 2844 } 2845 } 2846 } 2847 2848 return collisions; 2849 }; 2850 2851 /** 2852 * Casts a ray segment against a set of bodies and returns all collisions, ray width is optional. Intersection points are not provided. 2853 * @method ray 2854 * @param {body[]} bodies 2855 * @param {vector} startPoint 2856 * @param {vector} endPoint 2857 * @param {number} [rayWidth] 2858 * @return {object[]} Collisions 2859 */ 2860 Query.ray = function(bodies, startPoint, endPoint, rayWidth) { 2861 rayWidth = rayWidth || 1e-100; 2862 2863 var rayAngle = Vector.angle(startPoint, endPoint), 2864 rayLength = Vector.magnitude(Vector.sub(startPoint, endPoint)), 2865 rayX = (endPoint.x + startPoint.x) * 0.5, 2866 rayY = (endPoint.y + startPoint.y) * 0.5, 2867 ray = Bodies.rectangle(rayX, rayY, rayLength, rayWidth, { angle: rayAngle }), 2868 collisions = Query.collides(ray, bodies); 2869 2870 for (var i = 0; i < collisions.length; i += 1) { 2871 var collision = collisions[i]; 2872 collision.body = collision.bodyB = collision.bodyA; 2873 } 2874 2875 return collisions; 2876 }; 2877 2878 /** 2879 * Returns all bodies whose bounds are inside (or outside if set) the given set of bounds, from the given set of bodies. 2880 * @method region 2881 * @param {body[]} bodies 2882 * @param {bounds} bounds 2883 * @param {bool} [outside=false] 2884 * @return {body[]} The bodies matching the query 2885 */ 2886 Query.region = function(bodies, bounds, outside) { 2887 var result = []; 2888 2889 for (var i = 0; i < bodies.length; i++) { 2890 var body = bodies[i], 2891 overlaps = Bounds.overlaps(body.bounds, bounds); 2892 if ((overlaps && !outside) || (!overlaps && outside)) 2893 result.push(body); 2894 } 2895 2896 return result; 2897 }; 2898 2899 /** 2900 * Returns all bodies whose vertices contain the given point, from the given set of bodies. 2901 * @method point 2902 * @param {body[]} bodies 2903 * @param {vector} point 2904 * @return {body[]} The bodies matching the query 2905 */ 2906 Query.point = function(bodies, point) { 2907 var result = []; 2908 2909 for (var i = 0; i < bodies.length; i++) { 2910 var body = bodies[i]; 2911 2912 if (Bounds.contains(body.bounds, point)) { 2913 for (var j = body.parts.length === 1 ? 0 : 1; j < body.parts.length; j++) { 2914 var part = body.parts[j]; 2915 2916 if (Bounds.contains(part.bounds, point) 2917 && Vertices.contains(part.vertices, point)) { 2918 result.push(body); 2919 break; 2920 } 2921 } 2922 } 2923 } 2924 2925 return result; 2926 }; 2927 2928})(); 2929 2930},{"../factory/Bodies":23,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29,"./SAT":11}],10:[function(_dereq_,module,exports){ 2931/** 2932* The `Matter.Resolver` module contains methods for resolving collision pairs. 2933* 2934* @class Resolver 2935*/ 2936 2937var Resolver = {}; 2938 2939module.exports = Resolver; 2940 2941var Vertices = _dereq_('../geometry/Vertices'); 2942var Vector = _dereq_('../geometry/Vector'); 2943var Common = _dereq_('../core/Common'); 2944var Bounds = _dereq_('../geometry/Bounds'); 2945 2946(function() { 2947 2948 Resolver._restingThresh = 4; 2949 Resolver._restingThreshTangent = 6; 2950 Resolver._positionDampen = 0.9; 2951 Resolver._positionWarming = 0.8; 2952 Resolver._frictionNormalMultiplier = 5; 2953 2954 /** 2955 * Prepare pairs for position solving. 2956 * @method preSolvePosition 2957 * @param {pair[]} pairs 2958 */ 2959 Resolver.preSolvePosition = function(pairs) { 2960 var i, 2961 pair, 2962 activeCount; 2963 2964 // find total contacts on each body 2965 for (i = 0; i < pairs.length; i++) { 2966 pair = pairs[i]; 2967 2968 if (!pair.isActive) 2969 continue; 2970 2971 activeCount = pair.activeContacts.length; 2972 pair.collision.parentA.totalContacts += activeCount; 2973 pair.collision.parentB.totalContacts += activeCount; 2974 } 2975 }; 2976 2977 /** 2978 * Find a solution for pair positions. 2979 * @method solvePosition 2980 * @param {pair[]} pairs 2981 * @param {number} timeScale 2982 */ 2983 Resolver.solvePosition = function(pairs, timeScale) { 2984 var i, 2985 pair, 2986 collision, 2987 bodyA, 2988 bodyB, 2989 normal, 2990 bodyBtoA, 2991 contactShare, 2992 positionImpulse, 2993 contactCount = {}, 2994 tempA = Vector._temp[0], 2995 tempB = Vector._temp[1], 2996 tempC = Vector._temp[2], 2997 tempD = Vector._temp[3]; 2998 2999 // find impulses required to resolve penetration 3000 for (i = 0; i < pairs.length; i++) { 3001 pair = pairs[i]; 3002 3003 if (!pair.isActive || pair.isSensor) 3004 continue; 3005 3006 collision = pair.collision; 3007 bodyA = collision.parentA; 3008 bodyB = collision.parentB; 3009 normal = collision.normal; 3010 3011 // get current separation between body edges involved in collision 3012 bodyBtoA = Vector.sub(Vector.add(bodyB.positionImpulse, bodyB.position, tempA), 3013 Vector.add(bodyA.positionImpulse, 3014 Vector.sub(bodyB.position, collision.penetration, tempB), tempC), tempD); 3015 3016 pair.separation = Vector.dot(normal, bodyBtoA); 3017 } 3018 3019 for (i = 0; i < pairs.length; i++) { 3020 pair = pairs[i]; 3021 3022 if (!pair.isActive || pair.isSensor) 3023 continue; 3024 3025 collision = pair.collision; 3026 bodyA = collision.parentA; 3027 bodyB = collision.parentB; 3028 normal = collision.normal; 3029 positionImpulse = (pair.separation - pair.slop) * timeScale; 3030 3031 if (bodyA.isStatic || bodyB.isStatic) 3032 positionImpulse *= 2; 3033 3034 if (!(bodyA.isStatic || bodyA.isSleeping)) { 3035 contactShare = Resolver._positionDampen / bodyA.totalContacts; 3036 bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare; 3037 bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare; 3038 } 3039 3040 if (!(bodyB.isStatic || bodyB.isSleeping)) { 3041 contactShare = Resolver._positionDampen / bodyB.totalContacts; 3042 bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare; 3043 bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare; 3044 } 3045 } 3046 }; 3047 3048 /** 3049 * Apply position resolution. 3050 * @method postSolvePosition 3051 * @param {body[]} bodies 3052 */ 3053 Resolver.postSolvePosition = function(bodies) { 3054 for (var i = 0; i < bodies.length; i++) { 3055 var body = bodies[i]; 3056 3057 // reset contact count 3058 body.totalContacts = 0; 3059 3060 if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) { 3061 // update body geometry 3062 for (var j = 0; j < body.parts.length; j++) { 3063 var part = body.parts[j]; 3064 Vertices.translate(part.vertices, body.positionImpulse); 3065 Bounds.update(part.bounds, part.vertices, body.velocity); 3066 part.position.x += body.positionImpulse.x; 3067 part.position.y += body.positionImpulse.y; 3068 } 3069 3070 // move the body without changing velocity 3071 body.positionPrev.x += body.positionImpulse.x; 3072 body.positionPrev.y += body.positionImpulse.y; 3073 3074 if (Vector.dot(body.positionImpulse, body.velocity) < 0) { 3075 // reset cached impulse if the body has velocity along it 3076 body.positionImpulse.x = 0; 3077 body.positionImpulse.y = 0; 3078 } else { 3079 // warm the next iteration 3080 body.positionImpulse.x *= Resolver._positionWarming; 3081 body.positionImpulse.y *= Resolver._positionWarming; 3082 } 3083 } 3084 } 3085 }; 3086 3087 /** 3088 * Prepare pairs for velocity solving. 3089 * @method preSolveVelocity 3090 * @param {pair[]} pairs 3091 */ 3092 Resolver.preSolveVelocity = function(pairs) { 3093 var i, 3094 j, 3095 pair, 3096 contacts, 3097 collision, 3098 bodyA, 3099 bodyB, 3100 normal, 3101 tangent, 3102 contact, 3103 contactVertex, 3104 normalImpulse, 3105 tangentImpulse, 3106 offset, 3107 impulse = Vector._temp[0], 3108 tempA = Vector._temp[1]; 3109 3110 for (i = 0; i < pairs.length; i++) { 3111 pair = pairs[i]; 3112 3113 if (!pair.isActive || pair.
3113isSensor) 3114 continue; 3115 3116 contacts = pair.activeContacts; 3117 collision = pair.collision; 3118 bodyA = collision.parentA; 3119 bodyB = collision.parentB; 3120 normal = collision.normal; 3121 tangent = collision.tangent; 3122 3123 // resolve each contact 3124 for (j = 0; j < contacts.length; j++) { 3125 contact = contacts[j]; 3126 contactVertex = contact.vertex; 3127 normalImpulse = contact.normalImpulse; 3128 tangentImpulse = contact.tangentImpulse; 3129 3130 if (normalImpulse !== 0 || tangentImpulse !== 0) { 3131 // total impulse from contact 3132 impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); 3133 impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); 3134 3135 // apply impulse from contact 3136 if (!(bodyA.isStatic || bodyA.isSleeping)) { 3137 offset = Vector.sub(contactVertex, bodyA.position, tempA); 3138 bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; 3139 bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; 3140 bodyA.anglePrev += Vector.cross(offset, impulse) * bodyA.inverseInertia; 3141 } 3142 3143 if (!(bodyB.isStatic || bodyB.isSleeping)) { 3144 offset = Vector.sub(contactVertex, bodyB.position, tempA); 3145 bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; 3146 bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; 3147 bodyB.anglePrev -= Vector.cross(offset, impulse) * bodyB.inverseInertia; 3148 } 3149 } 3150 } 3151 } 3152 }; 3153 3154 /** 3155 * Find a solution for pair velocities. 3156 * @method solveVelocity 3157 * @param {pair[]} pairs 3158 * @param {number} timeScale 3159 */ 3160 Resolver.solveVelocity = function(pairs, timeScale) { 3161 var timeScaleSquared = timeScale * timeScale, 3162 impulse = Vector._temp[0], 3163 tempA = Vector._temp[1], 3164 tempB = Vector._temp[2], 3165 tempC = Vector._temp[3], 3166 tempD = Vector._temp[4], 3167 tempE = Vector._temp[5]; 3168 3169 for (var i = 0; i < pairs.length; i++) { 3170 var pair = pairs[i]; 3171 3172 if (!pair.isActive || pair.isSensor) 3173 continue; 3174 3175 var collision = pair.collision, 3176 bodyA = collision.parentA, 3177 bodyB = collision.parentB, 3178 normal = collision.normal, 3179 tangent = collision.tangent, 3180 contacts = pair.activeContacts, 3181 contactShare = 1 / contacts.length; 3182 3183 // update body velocities 3184 bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; 3185 bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; 3186 bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; 3187 bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; 3188 bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; 3189 bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; 3190 3191 // resolve each contact 3192 for (var j = 0; j < contacts.length; j++) { 3193 var contact = contacts[j], 3194 contactVertex = contact.vertex, 3195 offsetA = Vector.sub(contactVertex, bodyA.position, tempA), 3196 offsetB = Vector.sub(contactVertex, bodyB.position, tempB), 3197 velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity), tempC), 3198 velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity), tempD), 3199 relativeVelocity = Vector.sub(velocityPointA, velocityPointB, tempE), 3200 normalVelocity = Vector.dot(normal, relativeVelocity); 3201 3202 var tangentVelocity = Vector.dot(tangent, relativeVelocity), 3203 tangentSpeed = Math.abs(tangentVelocity), 3204 tangentVelocityDirection = Common.sign(tangentVelocity); 3205 3206 // raw impulses 3207 var normalImpulse = (1 + pair.restitution) * normalVelocity, 3208 normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier; 3209 3210 // coulomb friction 3211 var tangentImpulse = tangentVelocity, 3212 maxFriction = Infinity; 3213 3214 if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScaleSquared) { 3215 maxFriction = tangentSpeed; 3216 tangentImpulse = Common.clamp( 3217 pair.friction * tangentVelocityDirection * timeScaleSquared, 3218 -maxFriction, maxFriction 3219 ); 3220 } 3221 3222 // modify impulses accounting for mass, inertia and offset 3223 var oAcN = Vector.cross(offsetA, normal), 3224 oBcN = Vector.cross(offsetB, normal), 3225 share = contactShare / (bodyA.inverseMass + bodyB.inverseMass + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN); 3226 3227 normalImpulse *= share; 3228 tangentImpulse *= share; 3229 3230 // handle high velocity and resting collisions separately 3231 if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) { 3232 // high normal velocity so clear cached contact normal impulse 3233 contact.normalImpulse = 0; 3234 } else { 3235 // solve resting collision constraints using Erin Catto's method (GDC08) 3236 // impulse constraint tends to 0 3237 var contactNormalImpulse = contact.normalImpulse; 3238 contact.normalImpulse = Math.min(contact.normalImpulse + normalImpulse, 0); 3239 normalImpulse = contact.normalImpulse - contactNormalImpulse; 3240 } 3241 3242 // handle high velocity and resting collisions separately 3243 if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScaleSquared) { 3244 // high tangent velocity so clear cached contact tangent impulse 3245 contact.tangentImpulse = 0; 3246 } else { 3247 // solve resting collision constraints using Erin Catto's method (GDC08) 3248 // tangent impulse tends to -tangentSpeed or +tangentSpeed 3249 var contactTangentImpulse = contact.tangentImpulse; 3250 contact.tangentImpulse = Common.clamp(contact.tangentImpulse + tangentImpulse, -maxFriction, maxFriction); 3251 tangentImpulse = contact.tangentImpulse - contactTangentImpulse; 3252 } 3253 3254 // total impulse from contact 3255 impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); 3256 impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); 3257 3258 // apply impulse from contact 3259 if (!(bodyA.isStatic || bodyA.isSleeping)) { 3260 bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; 3261 bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; 3262 bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia; 3263 } 3264 3265 if (!(bodyB.isStatic || bodyB.isSleeping)) { 3266 bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; 3267 bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; 3268 bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia; 3269 } 3270 } 3271 } 3272 }; 3273 3274})(); 3275 3276},{"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],11:[function(_dereq_,module,exports){ 3277/** 3278* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem. 3279* 3280* @class SAT 3281*/ 3282 3283// TODO: true circles and curves 3284 3285var SAT = {}; 3286 3287module.exports = SAT; 3288 3289var Vertices = _dereq_('../geometry/Vertices'); 3290var Vector = _dereq_('../geometry/Vector'); 3291 3292(function() { 3293 3294 /** 3295 * Detect collision between two bodies using the Separating Axis Theorem. 3296 * @method collides 3297 * @param {body} bodyA 3298 * @param {body} bodyB 3299 * @param {collision} previousCollision 3300 * @return {collision} collision 3301 */ 3302 SAT.collides = function(bodyA, bodyB, previousCollision) { 3303 var overlapAB, 3304 overlapBA, 3305 minOverlap, 3306 collision, 3307 canReusePrevCol = false;
3308 3309 if (previousCollision) { 3310 // estimate total motion 3311 var parentA = bodyA.parent, 3312 parentB = bodyB.parent, 3313 motion = parentA.speed * parentA.speed + parentA.angularSpeed * parentA.angularSpeed 3314 + parentB.speed * parentB.speed + parentB.angularSpeed * parentB.angularSpeed; 3315 3316 // we may be able to (partially) reuse collision result 3317 // but only safe if collision was resting 3318 canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2; 3319 3320 // reuse collision object 3321 collision = previousCollision; 3322 } else { 3323 collision = { collided: false, bodyA: bodyA, bodyB: bodyB }; 3324 } 3325 3326 if (previousCollision && canReusePrevCol) { 3327 // if we can reuse the collision result 3328 // we only need to test the previously found axis 3329 var axisBodyA = collision.axisBody, 3330 axisBodyB = axisBodyA === bodyA ? bodyB : bodyA, 3331 axes = [axisBodyA.axes[previousCollision.axisNumber]]; 3332 3333 minOverlap = SAT._overlapAxes(axisBodyA.vertices, axisBodyB.vertices, axes); 3334 collision.reused = true; 3335 3336 if (minOverlap.overlap <= 0) { 3337 collision.collided = false; 3338 return collision; 3339 } 3340 } else { 3341 // if we can't reuse a result, perform a full SAT test 3342 3343 overlapAB = SAT._overlapAxes(bodyA.vertices, bodyB.vertices, bodyA.axes); 3344 3345 if (overlapAB.overlap <= 0) { 3346 collision.collided = false; 3347 return collision; 3348 } 3349 3350 overlapBA = SAT._overlapAxes(bodyB.vertices, bodyA.vertices, bodyB.axes); 3351 3352 if (overlapBA.overlap <= 0) { 3353 collision.collided = false; 3354 return collision; 3355 } 3356 3357 if (overlapAB.overlap < overlapBA.overlap) { 3358 minOverlap = overlapAB; 3359 collision.axisBody = bodyA; 3360 } else { 3361 minOverlap = overlapBA; 3362 collision.axisBody = bodyB; 3363 } 3364 3365 // important for reuse later 3366 collision.axisNumber = minOverlap.axisNumber; 3367 } 3368 3369 collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB; 3370 collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA; 3371 collision.collided = true; 3372 collision.depth = minOverlap.overlap; 3373 collision.parentA = collision.bodyA.parent; 3374 collision.parentB = collision.bodyB.parent; 3375 3376 bodyA = collision.bodyA; 3377 bodyB = collision.bodyB; 3378 3379 // ensure normal is facing away from bodyA 3380 if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) { 3381 collision.normal = { 3382 x: minOverlap.axis.x, 3383 y: minOverlap.axis.y 3384 }; 3385 } else { 3386 collision.normal = { 3387 x: -minOverlap.axis.x, 3388 y: -minOverlap.axis.y 3389 }; 3390 } 3391 3392 collision.tangent = Vector.perp(collision.normal); 3393 3394 collision.penetration = collision.penetration || {}; 3395 collision.penetration.x = collision.normal.x * collision.depth; 3396 collision.penetration.y = collision.normal.y * collision.depth; 3397 3398 // find support points, there is always either exactly one or two 3399 var verticesB = SAT._findSupports(bodyA, bodyB, collision.normal), 3400 supports = []; 3401 3402 // find the supports from bodyB that are inside bodyA 3403 if (Vertices.contains(bodyA.vertices, verticesB[0])) 3404 supports.push(verticesB[0]); 3405 3406 if (Vertices.contains(bodyA.vertices, verticesB[1])) 3407 supports.push(verticesB[1]); 3408 3409 // find the supports from bodyA that are inside bodyB 3410 if (supports.length < 2) { 3411 var verticesA = SAT._findSupports(bodyB, bodyA, Vector.neg(collision.normal)); 3412 3413 if (Vertices.contains(bodyB.vertices, verticesA[0])) 3414 supports.push(verticesA[0]); 3415 3416 if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1])) 3417 supports.push(verticesA[1]); 3418 } 3419 3420 // account for the edge case of overlapping but no vertex containment 3421 if (supports.length < 1) 3422 supports = [verticesB[0]]; 3423 3424 collision.supports = supports; 3425 3426 return collision; 3427 }; 3428 3429 /** 3430 * Find the overlap between two sets of vertices.
3431 * @method _overlapAxes 3432 * @private 3433 * @param {} verticesA 3434 * @param {} verticesB 3435 * @param {} axes 3436 * @return result 3437 */ 3438 SAT._overlapAxes = function(verticesA, verticesB, axes) { 3439 var projectionA = Vector._temp[0], 3440 projectionB = Vector._temp[1], 3441 result = { overlap: Number.MAX_VALUE }, 3442 overlap, 3443 axis; 3444 3445 for (var i = 0; i < axes.length; i++) { 3446 axis = axes[i]; 3447 3448 SAT._projectToAxis(projectionA, verticesA, axis); 3449 SAT._projectToAxis(projectionB, verticesB, axis); 3450 3451 overlap = Math.min(projectionA.max - projectionB.min, projectionB.max - projectionA.min); 3452 3453 if (overlap <= 0) { 3454 result.overlap = overlap; 3455 return result; 3456 } 3457 3458 if (overlap < result.overlap) { 3459 result.overlap = overlap; 3460 result.axis = axis; 3461 result.axisNumber = i; 3462 } 3463 } 3464 3465 return result; 3466 }; 3467 3468 /** 3469 * Projects vertices on an axis and returns an interval. 3470 * @method _projectToAxis 3471 * @private 3472 * @param {} projection 3473 * @param {} vertices 3474 * @param {} axis 3475 */ 3476 SAT._projectToAxis = function(projection, vertices, axis) { 3477 var min = Vector.dot(vertices[0], axis), 3478 max = min; 3479 3480 for (var i = 1; i < vertices.length; i += 1) { 3481 var dot = Vector.dot(vertices[i], axis); 3482 3483 if (dot > max) { 3484 max = dot; 3485 } else if (dot < min) { 3486 min = dot; 3487 } 3488 } 3489 3490 projection.min = min; 3491 projection.max = max; 3492 }; 3493 3494 /** 3495 * Finds supporting vertices given two bodies along a given direction using hill-climbing. 3496 * @method _findSupports 3497 * @private 3498 * @param {} bodyA 3499 * @param {} bodyB 3500 * @param {} normal 3501 * @return [vector] 3502 */ 3503 SAT._findSupports = function(bodyA, bodyB, normal) { 3504 var nearestDistance = Number.MAX_VALUE, 3505 vertexToBody = Vector._temp[0], 3506 vertices = bodyB.vertices, 3507 bodyAPosition = bodyA.position, 3508 distance, 3509 vertex, 3510 vertexA, 3511 vertexB; 3512 3513 // find closest vertex on bodyB 3514 for (var i = 0; i < vertices.length; i++) { 3515 vertex = vertices[i]; 3516 vertexToBody.x = vertex.x - bodyAPosition.x; 3517 vertexToBody.y = vertex.y - bodyAPosition.y; 3518 distance = -Vector.dot(normal, vertexToBody); 3519 3520 if (distance < nearestDistance) { 3521 nearestDistance = distance; 3522 vertexA = vertex; 3523 } 3524 } 3525 3526 // find next closest vertex using the two connected to it 3527 var prevIndex = vertexA.index - 1 >= 0 ? vertexA.index - 1 : vertices.length - 1; 3528 vertex = vertices[prevIndex]; 3529 vertexToBody.x = vertex.x - bodyAPosition.x; 3530 vertexToBody.y = vertex.y - bodyAPosition.y; 3531 nearestDistance = -Vector.dot(normal, vertexToBody); 3532 vertexB = vertex; 3533 3534 var nextIndex = (vertexA.index + 1) % vertices.length; 3535 vertex = vertices[nextIndex]; 3536 vertexToBody.x = vertex.x - bodyAPosition.x; 3537 vertexToBody.y = vertex.y - bodyAPosition.y; 3538 distance = -Vector.dot(normal, vertexToBody); 3539 if (distance < nearestDistance) { 3540 vertexB = vertex; 3541 } 3542 3543 return [vertexA, vertexB]; 3544 }; 3545 3546})(); 3547 3548},{"../geometry/Vector":28,"../geometry/Vertices":29}],12:[function(_dereq_,module,exports){ 3549/** 3550* The `Matter.Constraint` module contains methods for creating and manipulating constraints. 3551* Constraints are used for specifying that a fixed distance must be maintained between two bodies (or a body and a fixed world-space position). 3552* The stiffness of constraints can be modified to create springs or elastic. 3553* 3554* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 3555* 3556* @class Constraint 3557*/ 3558 3559var Constraint = {}; 3560 3561module.exports = Constraint; 3562 3563var Vertices = _dereq_('../geometry/Vertices'); 3564var Vector = _dereq_('../geometry/Vector'); 3565var Sleeping = _dereq_('../core/Sleeping'); 3566var Bounds = _dereq_('../geometry/Bounds'); 3567var Axes = _dereq_('../geometry/Axes'); 3568var Common = _dereq_('../core/Common'); 3569 3570(function() { 3571 3572 Constraint._warming = 0.4; 3573 Constraint._torqueDampen = 1; 3574 Constraint._minLength = 0.000001; 3575 3576 /** 3577 * Creates a new constraint. 3578 * All properties have default values, and many are pre-calculated automatically based on other properties. 3579 * To simulate a revolute constraint (or pin joint) set `length: 0` and a high `stiffness` value (e.g. `0.7` or above). 3580 * If the constraint is unstable, try lowering the `stiffness` value and / or increasing `engine.constraintIterations`. 3581 * For compound bodies, constraints must be applied to the parent body (not one of its parts). 3582 * See the properties section below for detailed information on what you can pass via the `options` object. 3583 * @method create 3584 * @param {} options 3585 * @return {constraint} constraint 3586 */ 3587 Constraint.create = function(options) { 3588 var constraint = options; 3589 3590 // if bodies defined but no points, use body centre 3591 if (constraint.bodyA && !constraint.pointA) 3592 constraint.pointA = { x: 0, y: 0 }; 3593 if (constraint.bodyB && !constraint.pointB) 3594 constraint.pointB = { x: 0, y: 0 }; 3595 3596 // calculate static length using initial world space points 3597 var initialPointA = constraint.bodyA ? Vector.add(constraint.bodyA.position, constraint.pointA) : constraint.pointA, 3598 initialPointB = constraint.bodyB ? Vector.add(constraint.bodyB.position, constraint.pointB) : constraint.pointB, 3599 length = Vector.magnitude(Vector.sub(initialPointA, initialPointB)); 3600 3601 constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length; 3602 3603 // option defaults 3604 constraint.id = constraint.id || Common.nextId(); 3605 constraint.label = constraint.label || 'Constraint'; 3606 constraint.type = 'constraint'; 3607 constraint.stiffness = constraint.stiffness || (constraint.length > 0 ? 1 : 0.7); 3608 constraint.damping = constraint.damping || 0; 3609 constraint.angularStiffness = constraint.angularStiffness || 0; 3610 constraint.angleA = constraint.bodyA ? constraint.bodyA.angle : constraint.angleA; 3611 constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB; 3612 constraint.plugin = {}; 3613 3614 // render 3615 var render = { 3616 visible: true, 3617 lineWidth: 2, 3618 strokeStyle: '#ffffff', 3619 type: 'line', 3620 anchors: true 3621 }; 3622 3623 if (constraint.length === 0 && constraint.stiffness > 0.1) { 3624 render.type = 'pin'; 3625 render.anchors = false;
vendor: 34,448 bytes, lines 3626-4718
3626 } else if (constraint.stiffness < 0.9) { 3627 render.type = 'spring'; 3628 } 3629 3630 constraint.render = Common.extend(render, constraint.render); 3631 3632 return constraint; 3633 }; 3634 3635 /** 3636 * Prepares for solving by constraint warming. 3637 * @private 3638 * @method preSolveAll 3639 * @param {body[]} bodies 3640 */ 3641 Constraint.preSolveAll = function(bodies) { 3642 for (var i = 0; i < bodies.length; i += 1) { 3643 var body = bodies[i], 3644 impulse = body.constraintImpulse; 3645 3646 if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { 3647 continue; 3648 } 3649 3650 body.position.x += impulse.x; 3651 body.position.y += impulse.y; 3652 body.angle += impulse.angle; 3653 } 3654 }; 3655 3656 /** 3657 * Solves all constraints in a list of collisions. 3658 * @private 3659 * @method solveAll 3660 * @param {constraint[]} constraints 3661 * @param {number} timeScale 3662 */ 3663 Constraint.solveAll = function(constraints, timeScale) { 3664 // Solve fixed constraints first. 3665 for (var i = 0; i < constraints.length; i += 1) { 3666 var constraint = constraints[i], 3667 fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic), 3668 fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); 3669 3670 if (fixedA || fixedB) { 3671 Constraint.solve(constraints[i], timeScale); 3672 } 3673 } 3674 3675 // Solve free constraints last. 3676 for (i = 0; i < constraints.length; i += 1) { 3677 constraint = constraints[i]; 3678 fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic); 3679 fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic); 3680 3681 if (!fixedA && !fixedB) { 3682 Constraint.solve(constraints[i], timeScale); 3683 } 3684 } 3685 }; 3686 3687 /** 3688 * Solves a distance constraint with Gauss-Siedel method. 3689 * @private 3690 * @method solve 3691 * @param {constraint} constraint 3692 * @param {number} timeScale 3693 */ 3694 Constraint.solve = function(constraint, timeScale) { 3695 var bodyA = constraint.bodyA, 3696 bodyB = constraint.bodyB, 3697 pointA = constraint.pointA, 3698 pointB = constraint.pointB; 3699 3700 if (!bodyA && !bodyB) 3701 return; 3702 3703 // update reference angle 3704 if (bodyA && !bodyA.isStatic) { 3705 Vector.rotate(pointA, bodyA.angle - constraint.angleA, pointA); 3706 constraint.angleA = bodyA.angle; 3707 } 3708 3709 // update reference angle 3710 if (bodyB && !bodyB.isStatic) { 3711 Vector.rotate(pointB, bodyB.angle - constraint.angleB, pointB); 3712 constraint.angleB = bodyB.angle; 3713 } 3714 3715 var pointAWorld = pointA, 3716 pointBWorld = pointB; 3717 3718 if (bodyA) pointAWorld = Vector.add(bodyA.position, pointA); 3719 if (bodyB) pointBWorld = Vector.add(bodyB.position, pointB); 3720 3721 if (!pointAWorld || !pointBWorld) 3722 return; 3723 3724 var delta = Vector.sub(pointAWorld, pointBWorld), 3725 currentLength = Vector.magnitude(delta); 3726 3727 // prevent singularity 3728 if (currentLength < Constraint._minLength) { 3729 currentLength = Constraint._minLength; 3730 } 3731 3732 // solve distance constraint with Gauss-Siedel method 3733 var difference = (currentLength - constraint.length) / currentLength, 3734 stiffness = constraint.stiffness < 1 ? constraint.stiffness * timeScale : constraint.stiffness, 3735 force = Vector.mult(delta, difference * stiffness), 3736 massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0), 3737 inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0), 3738 resistanceTotal = massTotal + inertiaTotal, 3739 torque, 3740 share, 3741 normal, 3742 normalVelocity, 3743 relativeVelocity; 3744 3745 if (constraint.damping) { 3746 var zero = Vector.create(); 3747 normal = Vector.div(delta, currentLength); 3748 3749 relativeVelocity = Vector.sub( 3750 bodyB && Vector.sub(bodyB.position, bodyB.positionPrev) || zero, 3751 bodyA && Vector.sub(bodyA.position, bodyA.positionPrev) || zero 3752 ); 3753 3754 normalVelocity = Vector.dot(normal, relativeVelocity); 3755 } 3756 3757 if (bodyA && !bodyA.isStatic) { 3758 share = bodyA.inverseMass / massTotal; 3759 3760 // keep track of applied impulses for post solving 3761 bodyA.constraintImpulse.x -= force.x * share; 3762 bodyA.constraintImpulse.y -= force.y * share; 3763 3764 // apply forces 3765 bodyA.position.x -= force.x * share; 3766 bodyA.position.y -= force.y * share; 3767 3768 // apply damping 3769 if (constraint.damping) { 3770 bodyA.positionPrev.x -= constraint.damping * normal.x * normalVelocity * share; 3771 bodyA.positionPrev.y -= constraint.damping * normal.y * normalVelocity * share; 3772 } 3773 3774 // apply torque 3775 torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness); 3776 bodyA.constraintImpulse.angle -= torque; 3777 bodyA.angle -= torque; 3778 } 3779 3780 if (bodyB && !bodyB.isStatic) { 3781 share = bodyB.inverseMass / massTotal; 3782 3783 // keep track of applied impulses for post solving 3784 bodyB.constraintImpulse.x += force.x * share; 3785 bodyB.constraintImpulse.y += force.y * share; 3786 3787 // apply forces 3788 bodyB.position.x += force.x * share; 3789 bodyB.position.y += force.y * share; 3790 3791 // apply damping 3792 if (constraint.damping) { 3793 bodyB.positionPrev.x += constraint.damping * normal.x * normalVelocity * share; 3794 bodyB.positionPrev.y += constraint.damping * normal.y * normalVelocity * share; 3795 } 3796 3797 // apply torque 3798 torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness); 3799 bodyB.constraintImpulse.angle += torque; 3800 bodyB.angle += torque; 3801 } 3802 3803 }; 3804 3805 /** 3806 * Performs body updates required after solving constraints. 3807 * @private 3808 * @method postSolveAll 3809 * @param {body[]} bodies 3810 */ 3811 Constraint.postSolveAll = function(bodies) { 3812 for (var i = 0; i < bodies.length; i++) { 3813 var body = bodies[i], 3814 impulse = body.constraintImpulse; 3815 3816 if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) { 3817 continue; 3818 } 3819 3820 Sleeping.set(body, false); 3821 3822 // update geometry and reset 3823 for (var j = 0; j < body.parts.length; j++) { 3824 var part = body.parts[j]; 3825 3826 Vertices.translate(part.vertices, impulse); 3827 3828 if (j > 0) { 3829 part.position.x += impulse.x; 3830 part.position.y += impulse.y; 3831 } 3832 3833 if (impulse.angle !== 0) { 3834 Vertices.rotate(part.vertices, impulse.angle, body.position); 3835 Axes.rotate(part.axes, impulse.angle); 3836 if (j > 0) { 3837 Vector.rotateAbout(part.position, impulse.angle, body.position, part.position); 3838 } 3839 } 3840 3841 Bounds.update(part.bounds, part.vertices, body.velocity); 3842 } 3843 3844 // dampen the cached impulse for warming next step 3845 impulse.angle *= Constraint._warming; 3846 impulse.x *= Constraint._warming; 3847 impulse.y *= Constraint._warming; 3848 } 3849 }; 3850 3851 /* 3852 * 3853 * Properties Documentation 3854 * 3855 */ 3856 3857 /** 3858 * An integer `Number` uniquely identifying number generated in `Composite.create` by `Common.nextId`. 3859 * 3860 * @property id 3861 * @type number 3862 */ 3863 3864 /** 3865 * A `String` denoting the type of object. 3866 * 3867 * @property type 3868 * @type string 3869 * @default "constraint" 3870 * @readOnly 3871 */ 3872 3873 /** 3874 * An arbitrary `String` name to help the user identify and manage bodies. 3875 * 3876 * @property label 3877 * @type string 3878 * @default "Constraint" 3879 */ 3880 3881 /** 3882 * An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`. 3883 * 3884 * @property render 3885 * @type object 3886 */ 3887 3888 /** 3889 * A flag that indicates if the constraint should be rendered. 3890 * 3891 * @property render.visible 3892 * @type boolean 3893 * @default true 3894 */ 3895 3896 /** 3897 * A `Number` that defines the line width to use when rendering the constraint outline. 3898 * A value of `0` means no outline will be rendered. 3899 * 3900 * @property render.lineWidth 3901 * @type number 3902 * @default 2 3903 */ 3904 3905 /** 3906 * A `String` that defines the stroke style to use when rendering the constraint outline. 3907 * It is the same as when using a canvas, so it accepts CSS style property values. 3908 * 3909 * @property render.strokeStyle 3910 * @type string 3911 * @default a random colour 3912 */ 3913 3914 /** 3915 * A `String` that defines the constraint rendering type. 3916 * The possible values are 'line', 'pin', 'spring'. 3917 * An appropriate render type will be automatically chosen unless one is given in options. 3918 * 3919 * @property render.type 3920 * @type string 3921 * @default 'line' 3922 */ 3923 3924 /** 3925 * A `Boolean` that defines if the constraint's anchor points should be rendered. 3926 * 3927 * @property render.anchors 3928 * @type boolean 3929 * @default true 3930 */ 3931 3932 /** 3933 * The first possible `Body` that this constraint is attached to. 3934 * 3935 * @property bodyA 3936 * @type body 3937 * @default null 3938 */ 3939 3940 /** 3941 * The second possible `Body` that this constraint is attached to. 3942 * 3943 * @property bodyB 3944 * @type body 3945 * @default null 3946 */ 3947 3948 /** 3949 * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyA` if defined, otherwise a world-space position. 3950 * 3951 * @property pointA 3952 * @type vector 3953 * @default { x: 0, y: 0 } 3954 */ 3955 3956 /** 3957 * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyB` if defined, otherwise a world-space position. 3958 * 3959 * @property pointB 3960 * @type vector 3961 * @default { x: 0, y: 0 } 3962 */ 3963 3964 /** 3965 * A `Number` that specifies the stiffness of the constraint, i.e. the rate at which it returns to its resting `constraint.length`. 3966 * A value of `1` means the constraint should be very stiff. 3967 * A value of `0.2` means the constraint acts like a soft spring. 3968 * 3969 * @property stiffness 3970 * @type number 3971 * @default 1 3972 */ 3973 3974 /** 3975 * A `Number` that specifies the damping of the constraint, 3976 * i.e. the amount of resistance applied to each body based on their velocities to limit the amount of oscillation. 3977 * Damping will only be apparent when the constraint also has a very low `stiffness`. 3978 * A value of `0.1` means the constraint will apply heavy damping, resulting in little to no oscillation. 3979 * A value of `0` means the constraint will apply no damping. 3980 * 3981 * @property damping 3982 * @type number 3983 * @default 0 3984 */ 3985 3986 /** 3987 * A `Number` that specifies the target resting length of the constraint. 3988 * It is calculated automatically in `Constraint.create` from initial positions of the `constraint.bodyA` and `constraint.bodyB`. 3989 * 3990 * @property length 3991 * @type number 3992 */ 3993 3994 /** 3995 * An object reserved for storing plugin-specific properties. 3996 * 3997 * @property plugin 3998 * @type {} 3999 */ 4000 4001})(); 4002 4003},{"../core/Common":14,"../core/Sleeping":22,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],13:[function(_dereq_,module,exports){ 4004/** 4005* The `Matter.MouseConstraint` module contains methods for creating mouse constraints. 4006* Mouse constraints are used for allowing user interaction, providing the ability to move bodies via the mouse or touch. 4007* 4008* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 4009* 4010* @class MouseConstraint 4011*/ 4012 4013var MouseConstraint = {}; 4014 4015module.exports = MouseConstraint; 4016 4017var Vertices = _dereq_('../geometry/Vertices'); 4018var Sleeping = _dereq_('../core/Sleeping'); 4019var Mouse = _dereq_('../core/Mouse'); 4020var Events = _dereq_('../core/Events'); 4021var Detector = _dereq_('../collision/Detector'); 4022var Constraint = _dereq_('./Constraint'); 4023var Composite = _dereq_('../body/Composite'); 4024var Common = _dereq_('../core/Common'); 4025var Bounds = _dereq_('../geometry/Bounds'); 4026 4027(function() { 4028 4029 /** 4030 * Creates a new mouse constraint. 4031 * All properties have default values, and many are pre-calculated automatically based on other properties. 4032 * See the properties section below for detailed information on what you can pass via the `options` object. 4033 * @method create 4034 * @param {engine} engine 4035 * @param {} options 4036 * @return {MouseConstraint} A new MouseConstraint 4037 */ 4038 MouseConstraint.create = function(engine, options) { 4039 var mouse = (engine ? engine.mouse : null) || (options ? options.mouse : null); 4040 4041 if (!mouse) { 4042 if (engine && engine.render && engine.render.canvas) { 4043 mouse = Mouse.create(engine.render.canvas); 4044 } else if (options && options.element) { 4045 mouse = Mouse.create(options.element); 4046 } else { 4047 mouse = Mouse.create(); 4048 Common.warn('MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected'); 4049 } 4050 } 4051 4052 var constraint = Constraint.create({ 4053 label: 'Mouse Constraint', 4054 pointA: mouse.position, 4055 pointB: { x: 0, y: 0 }, 4056 length: 0.01, 4057 stiffness: 0.1, 4058 angularStiffness: 1, 4059 render: { 4060 strokeStyle: '#90EE90', 4061 lineWidth: 3 4062 } 4063 }); 4064 4065 var defaults = { 4066 type: 'mouseConstraint', 4067 mouse: mouse, 4068 element: null, 4069 body: null, 4070 constraint: constraint, 4071 collisionFilter: { 4072 category: 0x0001, 4073 mask: 0xFFFFFFFF, 4074 group: 0 4075 } 4076 }; 4077 4078 var mouseConstraint = Common.extend(defaults, options); 4079 4080 Events.on(engine, 'beforeUpdate', function() { 4081 var allBodies = Composite.allBodies(engine.world); 4082 MouseConstraint.update(mouseConstraint, allBodies); 4083 MouseConstraint._triggerEvents(mouseConstraint); 4084 }); 4085 4086 return mouseConstraint; 4087 }; 4088 4089 /** 4090 * Updates the given mouse constraint. 4091 * @private 4092 * @method update 4093 * @param {MouseConstraint} mouseConstraint 4094 * @param {body[]} bodies 4095 */ 4096 MouseConstraint.update = function(mouseConstraint, bodies) { 4097 var mouse = mouseConstraint.mouse, 4098 constraint = mouseConstraint.constraint, 4099 body = mouseConstraint.body; 4100 4101 if (mouse.button === 0) { 4102 if (!constraint.bodyB) { 4103 for (var i = 0; i < bodies.length; i++) { 4104 body = bodies[i]; 4105 if (Bounds.contains(body.bounds, mouse.position) 4106 && Detector.canCollide(body.collisionFilter, mouseConstraint.collisionFilter)) { 4107 for (var j = body.parts.length > 1 ? 1 : 0; j < body.parts.length; j++) { 4108 var part = body.parts[j]; 4109 if (Vertices.contains(part.vertices, mouse.position)) { 4110 constraint.pointA = mouse.position; 4111 constraint.bodyB = mouseConstraint.body = body; 4112 constraint.pointB = { x: mouse.position.x - body.position.x, y: mouse.position.y - body.position.y }; 4113 constraint.angleB = body.angle; 4114 4115 Sleeping.set(body, false); 4116 Events.trigger(mouseConstraint, 'startdrag', { mouse: mouse, body: body }); 4117 4118 break; 4119 } 4120 } 4121 } 4122 } 4123 } else { 4124 Sleeping.set(constraint.bodyB, false); 4125 constraint.pointA = mouse.position; 4126 } 4127 } else { 4128 constraint.bodyB = mouseConstraint.body = null; 4129 constraint.pointB = null; 4130 4131 if (body) 4132 Events.trigger(mouseConstraint, 'enddrag', { mouse: mouse, body: body }); 4133 } 4134 }; 4135 4136 /** 4137 * Triggers mouse constraint events. 4138 * @method _triggerEvents 4139 * @private 4140 * @param {mouse} mouseConstraint 4141 */ 4142 MouseConstraint._triggerEvents = function(mouseConstraint) { 4143 var mouse = mouseConstraint.mouse, 4144 mouseEvents = mouse.sourceEvents; 4145 4146 if (mouseEvents.mousemove) 4147 Events.trigger(mouseConstraint, 'mousemove', { mouse: mouse }); 4148 4149 if (mouseEvents.mousedown) 4150 Events.trigger(mouseConstraint, 'mousedown', { mouse: mouse }); 4151 4152 if (mouseEvents.mouseup) 4153 Events.trigger(mouseConstraint, 'mouseup', { mouse: mouse }); 4154 4155 // reset the mouse state ready for the next step 4156 Mouse.clearSourceEvents(mouse); 4157 }; 4158 4159 /* 4160 * 4161 * Events Documentation 4162 * 4163 */ 4164 4165 /** 4166 * Fired when the mouse has moved (or a touch moves) during the last step 4167 * 4168 * @event mousemove 4169 * @param {} event An event object 4170 * @param {mouse} event.mouse The engine's mouse instance 4171 * @param {} event.source The source object of the event 4172 * @param {} event.name The name of the event 4173 */ 4174 4175 /** 4176 * Fired when the mouse is down (or a touch has started) during the last step 4177 * 4178 * @event mousedown 4179 * @param {} event An event object 4180 * @param {mouse} event.mouse The engine's mouse instance 4181 * @param {} event.source The source object of the event 4182 * @param {} event.name The name of the event 4183 */ 4184 4185 /** 4186 * Fired when the mouse is up (or a touch has ended) during the last step 4187 * 4188 * @event mouseup 4189 * @param {} event An event object 4190 * @param {mouse} event.mouse The engine's mouse instance 4191 * @param {} event.source The source object of the event 4192 * @param {} event.name The name of the event 4193 */ 4194 4195 /** 4196 * Fired when the user starts dragging a body 4197 * 4198 * @event startdrag 4199 * @param {} event An event object 4200 * @param {mouse} event.mouse The engine's mouse instance 4201 * @param {body} event.body The body being dragged 4202 * @param {} event.source The source object of the event 4203 * @param {} event.name The name of the event 4204 */ 4205 4206 /** 4207 * Fired when the user ends dragging a body 4208 * 4209 * @event enddrag 4210 * @param {} event An event object 4211 * @param {mouse} event.mouse The engine's mouse instance 4212 * @param {body} event.body The body that has stopped being dragged 4213 * @param {} event.source The source object of the event 4214 * @param {} event.name The name of the event 4215 */ 4216 4217 /* 4218 * 4219 * Properties Documentation 4220 * 4221 */ 4222 4223 /** 4224 * A `String` denoting the type of object. 4225 * 4226 * @property type 4227 * @type string 4228 * @default "constraint" 4229 * @readOnly 4230 */ 4231 4232 /** 4233 * The `Mouse` instance in use. If not supplied in `MouseConstraint.create`, one will be created. 4234 * 4235 * @property mouse 4236 * @type mouse 4237 * @default mouse 4238 */ 4239 4240 /** 4241 * The `Body` that is currently being moved by the user, or `null` if no body. 4242 * 4243 * @property body 4244 * @type body 4245 * @default null 4246 */ 4247 4248 /** 4249 * The `Constraint` object that is used to move the body during interaction. 4250 * 4251 * @property constraint 4252 * @type constraint 4253 */ 4254 4255 /** 4256 * An `Object` that specifies the collision filter properties. 4257 * The collision filter allows the user to define which types of body this mouse constraint can interact with. 4258 * See `body.collisionFilter` for more information. 4259 * 4260 * @property collisionFilter 4261 * @type object 4262 */ 4263 4264})(); 4265 4266},{"../body/Composite":2,"../collision/Detector":5,"../core/Common":14,"../core/Events":16,"../core/Mouse":19,"../core/Sleeping":22,"../geometry/Bounds":26,"../geometry/Vertices":29,"./Constraint":12}],14:[function(_dereq_,module,exports){ 4267(function (global){ 4268/** 4269* The `Matter.Common` module contains utility functions that are common to all modules. 4270* 4271* @class Common 4272*/ 4273 4274var Common = {}; 4275 4276module.exports = Common; 4277 4278(function() { 4279 4280 Common._nextId = 0; 4281 Common._seed = 0; 4282 Common._nowStartTime = +(new Date()); 4283 4284 /** 4285 * Extends the object in the first argument using the object in the second argument. 4286 * @method extend 4287 * @param {} obj 4288 * @param {boolean} deep 4289 * @return {} obj extended 4290 */ 4291 Common.extend = function(obj, deep) { 4292 var argsStart, 4293 args, 4294 deepClone; 4295 4296 if (typeof deep === 'boolean') { 4297 argsStart = 2; 4298 deepClone = deep; 4299 } else { 4300 argsStart = 1; 4301 deepClone = true; 4302 } 4303 4304 for (var i = argsStart; i < arguments.length; i++) { 4305 var source = arguments[i]; 4306 4307 if (source) { 4308 for (var prop in source) { 4309 if (deepClone && source[prop] && source[prop].constructor === Object) { 4310 if (!obj[prop] || obj[prop].constructor === Object) { 4311 obj[prop] = obj[prop] || {}; 4312 Common.extend(obj[prop], deepClone, source[prop]); 4313 } else { 4314 obj[prop] = source[prop]; 4315 } 4316 } else { 4317 obj[prop] = source[prop]; 4318 } 4319 } 4320 } 4321 } 4322 4323 return obj; 4324 }; 4325 4326 /** 4327 * Creates a new clone of the object, if deep is true references will also be cloned. 4328 * @method clone 4329 * @param {} obj 4330 * @param {bool} deep 4331 * @return {} obj cloned 4332 */ 4333 Common.clone = function(obj, deep) { 4334 return Common.extend({}, deep, obj); 4335 }; 4336 4337 /** 4338 * Returns the list of keys for the given object. 4339 * @method keys 4340 * @param {} obj 4341 * @return {string[]} keys 4342 */ 4343 Common.keys = function(obj) { 4344 if (Object.keys) 4345 return Object.keys(obj); 4346 4347 // avoid hasOwnProperty for performance 4348 var keys = []; 4349 for (var key in obj) 4350 keys.push(key); 4351 return keys; 4352 }; 4353 4354 /** 4355 * Returns the list of values for the given object. 4356 * @method values 4357 * @param {} obj 4358 * @return {array} Array of the objects property values 4359 */ 4360 Common.values = function(obj) { 4361 var values = []; 4362 4363 if (Object.keys) { 4364 var keys = Object.keys(obj); 4365 for (var i = 0; i < keys.length; i++) { 4366 values.push(obj[keys[i]]); 4367 } 4368 return values; 4369 } 4370 4371 // avoid hasOwnProperty for performance 4372 for (var key in obj) 4373 values.push(obj[key]); 4374 return values; 4375 }; 4376 4377 /** 4378 * Gets a value from `base` relative to the `path` string. 4379 * @method get 4380 * @param {} obj The base object 4381 * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz' 4382 * @param {number} [begin] Path slice begin 4383 * @param {number} [end] Path slice end 4384 * @return {} The object at the given path 4385 */ 4386 Common.get = function(obj, path, begin, end) { 4387 path = path.split('.').slice(begin, end); 4388 4389 for (var i = 0; i < path.length; i += 1) { 4390 obj = obj[path[i]]; 4391 } 4392 4393 return obj; 4394 }; 4395 4396 /** 4397 * Sets a value on `base` relative to the given `path` string. 4398 * @method set 4399 * @param {} obj The base object 4400 * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz' 4401 * @param {} val The value to set 4402 * @param {number} [begin] Path slice begin 4403 * @param {number} [end] Path slice end 4404 * @return {} Pass through `val` for chaining 4405 */ 4406 Common.set = function(obj, path, val, begin, end) { 4407 var parts = path.split('.').slice(begin, end); 4408 Common.get(obj, path, 0, -1)[parts[parts.length - 1]] = val; 4409 return val; 4410 }; 4411 4412 /** 4413 * Shuffles the given array in-place. 4414 * The function uses a seeded random generator. 4415 * @method shuffle 4416 * @param {array} array 4417 * @return {array} array shuffled randomly 4418 */ 4419 Common.shuffle = function(array) { 4420 for (var i = array.length - 1; i > 0; i--) { 4421 var j = Math.floor(Common.random() * (i + 1)); 4422 var temp = array[i]; 4423 array[i] = array[j]; 4424 array[j] = temp; 4425 } 4426 return array; 4427 }; 4428 4429 /** 4430 * Randomly chooses a value from a list with equal probability. 4431 * The function uses a seeded random generator. 4432 * @method choose 4433 * @param {array} choices 4434 * @return {object} A random choice object from the array 4435 */ 4436 Common.choose = function(choices) { 4437 return choices[Math.floor(Common.random() * choices.length)]; 4438 }; 4439 4440 /** 4441 * Returns true if the object is a HTMLElement, otherwise false. 4442 * @method isElement 4443 * @param {object} obj 4444 * @return {boolean} True if the object is a HTMLElement, otherwise false 4445 */ 4446 Common.isElement = function(obj) { 4447 if (typeof HTMLElement !== 'undefined') { 4448 return obj instanceof HTMLElement; 4449 } 4450 4451 return !!(obj && obj.nodeType && obj.nodeName); 4452 }; 4453 4454 /** 4455 * Returns true if the object is an array. 4456 * @method isArray 4457 * @param {object} obj 4458 * @return {boolean} True if the object is an array, otherwise false 4459 */ 4460 Common.isArray = function(obj) { 4461 return Object.prototype.toString.call(obj) === '[object Array]'; 4462 }; 4463 4464 /** 4465 * Returns true if the object is a function. 4466 * @method isFunction 4467 * @param {object} obj 4468 * @return {boolean} True if the object is a function, otherwise false 4469 */ 4470 Common.isFunction = function(obj) { 4471 return typeof obj === "function"; 4472 }; 4473 4474 /** 4475 * Returns true if the object is a plain object. 4476 * @method isPlainObject 4477 * @param {object} obj 4478 * @return {boolean} True if the object is a plain object, otherwise false 4479 */ 4480 Common.isPlainObject = function(obj) { 4481 return typeof obj === 'object' && obj.constructor === Object; 4482 }; 4483 4484 /** 4485 * Returns true if the object is a string. 4486 * @method isString 4487 * @param {object} obj 4488 * @return {boolean} True if the object is a string, otherwise false 4489 */ 4490 Common.isString = function(obj) { 4491 return toString.call(obj) === '[object String]'; 4492 }; 4493 4494 /** 4495 * Returns the given value clamped between a minimum and maximum value. 4496 * @method clamp 4497 * @param {number} value 4498 * @param {number} min 4499 * @param {number} max 4500 * @return {number} The value clamped between min and max inclusive 4501 */ 4502 Common.clamp = function(value, min, max) { 4503 if (value < min) 4504 return min; 4505 if (value > max) 4506 return max; 4507 return value; 4508 }; 4509 4510 /** 4511 * Returns the sign of the given value. 4512 * @method sign 4513 * @param {number} value 4514 * @return {number} -1 if negative, +1 if 0 or positive 4515 */ 4516 Common.sign = function(value) { 4517 return value < 0 ? -1 : 1; 4518 }; 4519 4520 /** 4521 * Returns the current timestamp since the time origin (e.g. from page load). 4522 * The result will be high-resolution including decimal places if available. 4523 * @method now 4524 * @return {number} the current timestamp 4525 */ 4526 Common.now = function() { 4527 if (window.performance) { 4528 if (window.performance.now) { 4529 return window.performance.now(); 4530 } else if (window.performance.webkitNow) { 4531 return window.performance.webkitNow(); 4532 } 4533 } 4534 4535 return (new Date()) - Common._nowStartTime; 4536 }; 4537 4538 /** 4539 * Returns a random value between a minimum and a maximum value inclusive. 4540 * The function uses a seeded random generator. 4541 * @method random 4542 * @param {number} min 4543 * @param {number} max 4544 * @return {number} A random number between min and max inclusive 4545 */ 4546 Common.random = function(min, max) { 4547 min = (typeof min !== "undefined") ? min : 0; 4548 max = (typeof max !== "undefined") ? max : 1; 4549 return min + _seededRandom() * (max - min); 4550 }; 4551 4552 var _seededRandom = function() { 4553 // https://en.wikipedia.org/wiki/Linear_congruential_generator 4554 Common._seed = (Common._seed * 9301 + 49297) % 233280; 4555 return Common._seed / 233280; 4556 }; 4557 4558 /** 4559 * Converts a CSS hex colour string into an integer. 4560 * @method colorToNumber 4561 * @param {string} colorString 4562 * @return {number} An integer representing the CSS hex string 4563 */ 4564 Common.colorToNumber = function(colorString) { 4565 colorString = colorString.replace('#',''); 4566 4567 if (colorString.length == 3) { 4568 colorString = colorString.charAt(0) + colorString.charAt(0) 4569 + colorString.charAt(1) + colorString.charAt(1) 4570 + colorString.charAt(2) + colorString.charAt(2); 4571 } 4572 4573 return parseInt(colorString, 16); 4574 }; 4575 4576 /** 4577 * The console logging level to use, where each level includes all levels above and excludes the levels below. 4578 * The default level is 'debug' which shows all console messages. 4579 * 4580 * Possible level values are: 4581 * - 0 = None 4582 * - 1 = Debug 4583 * - 2 = Info 4584 * - 3 = Warn 4585 * - 4 = Error 4586 * @property Common.logLevel 4587 * @type {Number} 4588 * @default 1 4589 */ 4590 Common.logLevel = 1; 4591 4592 /** 4593 * Shows a `console.log` message only if the current `Common.logLevel` allows it. 4594 * The message will be prefixed with 'matter-js' to make it easily identifiable. 4595 * @method log 4596 * @param ...objs {} The objects to log. 4597 */ 4598 Common.log = function() { 4599 if (console && Common.logLevel > 0 && Common.logLevel <= 3) { 4600 console.log.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments))); 4601 } 4602 }; 4603 4604 /** 4605 * Shows a `console.info` message only if the current `Common.logLevel` allows it. 4606 * The message will be prefixed with 'matter-js' to make it easily identifiable. 4607 * @method info 4608 * @param ...objs {} The objects to log. 4609 */ 4610 Common.info = function() { 4611 if (console && Common.logLevel > 0 && Common.logLevel <= 2) { 4612 console.info.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments))); 4613 } 4614 }; 4615 4616 /** 4617 * Shows a `console.warn` message only if the current `Common.logLevel` allows it. 4618 * The message will be prefixed with 'matter-js' to make it easily identifiable. 4619 * @method warn 4620 * @param ...objs {} The objects to log. 4621 */ 4622 Common.warn = function() { 4623 if (console && Common.logLevel > 0 && Common.logLevel <= 3) { 4624 console.warn.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments))); 4625 } 4626 }; 4627 4628 /** 4629 * Returns the next unique sequential ID. 4630 * @method nextId 4631 * @return {Number} Unique sequential ID 4632 */ 4633 Common.nextId = function() { 4634 return Common._nextId++; 4635 }; 4636 4637 /** 4638 * A cross browser compatible indexOf implementation. 4639 * @method indexOf 4640 * @param {array} haystack 4641 * @param {object} needle 4642 * @return {number} The position of needle in haystack, otherwise -1. 4643 */ 4644 Common.indexOf = function(haystack, needle) { 4645 if (haystack.indexOf) 4646 return haystack.indexOf(needle); 4647 4648 for (var i = 0; i < haystack.length; i++) { 4649 if (haystack[i] === needle) 4650 return i; 4651 } 4652 4653 return -1; 4654 }; 4655 4656 /** 4657 * A cross browser compatible array map implementation. 4658 * @method map 4659 * @param {array} list 4660 * @param {function} func 4661 * @return {array} Values from list transformed by func. 4662 */ 4663 Common.map = function(list, func) { 4664 if (list.map) { 4665 return list.map(func); 4666 } 4667 4668 var mapped = []; 4669 4670 for (var i = 0; i < list.length; i += 1) { 4671 mapped.push(func(list[i])); 4672 } 4673 4674 return mapped; 4675 }; 4676 4677 /** 4678 * Takes a directed graph and returns the partially ordered set of vertices in topological order. 4679 * Circular dependencies are allowed. 4680 * @method topologicalSort 4681 * @param {object} graph 4682 * @return {array} Partially ordered set of vertices in topological order. 4683 */ 4684 Common.topologicalSort = function(graph) { 4685 // https://github.com/mgechev/javascript-algorithms 4686 // Copyright (c) Minko Gechev (MIT license) 4687 // Modifications: tidy formatting and naming 4688 var result = [], 4689 visited = [], 4690 temp = []; 4691 4692 for (var node in graph) { 4693 if (!visited[node] && !temp[node]) { 4694 Common._topologicalSort(node, visited, temp, graph, result); 4695 } 4696 } 4697 4698 return result; 4699 }; 4700 4701 Common._topologicalSort = function(node, visited, temp, graph, result) { 4702 var neighbors = graph[node] || []; 4703 temp[node] = true; 4704 4705 for (var i = 0; i < neighbors.length; i += 1) { 4706 var neighbor = neighbors[i]; 4707 4708 if (temp[neighbor]) { 4709 // skip circular dependencies 4710 continue; 4711 } 4712 4713 if (!visited[neighbor]) { 4714 Common._topologicalSort(neighbor, visited, temp, graph, result); 4715 } 4716 } 4717 4718 temp[node] = false;
4719 visited[node] = true; 4720 4721 result.push(node); 4722 }; 4723 4724 /** 4725 * Takes _n_ functions as arguments and returns a new function that calls them in order. 4726 * The arguments applied when calling the new function will also be applied to every function passed. 4727 * The value of `this` refers to the last value returned in the chain that was not `undefined`. 4728 * Therefore if a passed function does not return a value, the previously returned value is maintained. 4729 * After all passed functions have been called the new function returns the last returned value (if any). 4730 * If any of the passed functions are a chain, then the chain will be flattened. 4731 * @method chain 4732 * @param ...funcs {function} The functions to chain. 4733 * @return {function} A new function that calls the passed functions in order. 4734 */ 4735 Common.chain = function() { 4736 var funcs = []; 4737 4738 for (var i = 0; i < arguments.length; i += 1) { 4739 var func = arguments[i]; 4740 4741 if (func._chained) { 4742 // flatten already chained functions 4743 funcs.push.apply(funcs, func._chained); 4744 } else { 4745 funcs.push(func); 4746 } 4747 } 4748 4749 var chain = function() { 4750 // https://github.com/GoogleChrome/devtools-docs/issues/53#issuecomment-51941358 4751 var lastResult, 4752 args = new Array(arguments.length); 4753 4754 for (var i = 0, l = arguments.length; i < l; i++) { 4755 args[i] = arguments[i]; 4756 } 4757 4758 for (i = 0; i < funcs.length; i += 1) { 4759 var result = funcs[i].apply(lastResult, args); 4760 4761 if (typeof result !== 'undefined') { 4762 lastResult = result; 4763 } 4764 } 4765 4766 return lastResult; 4767 }; 4768 4769 chain._chained = funcs; 4770 4771 return chain; 4772 }; 4773 4774 /** 4775 * Chains a function to excute before the original function on the given `path` relative to `base`. 4776 * See also docs for `Common.chain`. 4777 * @method chainPathBefore 4778 * @param {} base The base object 4779 * @param {string} path The path relative to `base` 4780 * @param {function} func The function to chain before the original 4781 * @return {function} The chained function that replaced the original 4782 */ 4783 Common.chainPathBefore = function(base, path, func) { 4784 return Common.set(base, path, Common.chain( 4785 func, 4786 Common.get(base, path) 4787 )); 4788 }; 4789 4790 /** 4791 * Chains a function to excute after the original function on the given `path` relative to `base`. 4792 * See also docs for `Common.chain`. 4793 * @method chainPathAfter 4794 * @param {} base The base object 4795 * @param {string} path The path relative to `base` 4796 * @param {function} func The function to chain after the original 4797 * @return {function} The chained function that replaced the original 4798 */ 4799 Common.chainPathAfter = function(base, path, func) { 4800 return Common.set(base, path, Common.chain( 4801 Common.get(base, path), 4802 func 4803 )); 4804 }; 4805 4806 /** 4807 * Used to require external libraries outside of the bundle. 4808 * It first looks for the `globalName` on the environment's global namespace. 4809 * If the global is not found, it will fall back to using the standard `require` using the `moduleName`. 4810 * @private 4811 * @method _requireGlobal 4812 * @param {string} globalName The global module name 4813 * @param {string} moduleName The fallback CommonJS module name 4814 * @return {} The loaded module 4815 */ 4816 Common._requireGlobal = function(globalName, moduleName) { 4817 var obj = (typeof window !== 'undefined' ? window[globalName] : typeof global !== 'undefined' ? global[globalName] : null); 4818 return obj || _dereq_(moduleName); 4819 }; 4820})(); 4821 4822}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 4823},{}],15:[function(_dereq_,module,exports){ 4824/** 4825* The `Matter.Engine` module contains methods for creating and manipulating engines. 4826* An engine is a controller that manages updating the simulation of the world. 4827* See `Matter.Runner` for an optional game loop utility. 4828* 4829* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 4830* 4831* @class Engine 4832*/ 4833 4834var Engine = {}; 4835 4836module.exports = Engine; 4837 4838var World = _dereq_('../body/World'); 4839var Sleeping = _dereq_('./Sleeping'); 4840var Resolver = _dereq_('../collision/Resolver'); 4841var Render = _dereq_('../render/Render'); 4842var Pairs = _dereq_('../collision/Pairs'); 4843var Metrics = _dereq_('./Metrics'); 4844var Grid = _dereq_('../collision/Grid'); 4845var Events = _dereq_('./Events'); 4846var Composite = _dereq_('../body/Composite'); 4847var Constraint = _dereq_('../constraint/Constraint'); 4848var Common = _dereq_('./Common'); 4849var Body = _dereq_('../body/Body'); 4850 4851(function() { 4852 4853 /** 4854 * Creates a new engine. The options parameter is an object that specifies any properties you wish to override the defaults. 4855 * All properties have default values, and many are pre-calculated automatically based on other properties. 4856 * See the properties section below for detailed information on what you can pass via the `options` object. 4857 * @method create 4858 * @param {object} [options] 4859 * @return {engine} engine 4860 */ 4861 Engine.create = function(element, options) { 4862 // options may be passed as the first (and only) argument 4863 options = Common.isElement(element) ? options : element; 4864 element = Common.isElement(element) ? element : null; 4865 options = options || {}; 4866 4867 if (element || options.render) { 4868 Common.warn('Engine.create: engine.render is deprecated (see docs)'); 4869 } 4870 4871 var defaults = { 4872 positionIterations: 6, 4873 velocityIterations: 4, 4874 constraintIterations: 2, 4875 enableSleeping: false, 4876 events: [], 4877 plugin: {}, 4878 timing: { 4879 timestamp: 0, 4880 timeScale: 1 4881 }, 4882 broadphase: { 4883 controller: Grid 4884 } 4885 }; 4886 4887 var engine = Common.extend(defaults, options); 4888 4889 // @deprecated 4890 if (element || engine.render) { 4891 var renderDefaults = { 4892 element: element, 4893 controller: Render 4894 }; 4895 4896 engine.render = Common.extend(renderDefaults, engine.render); 4897 } 4898 4899 // @deprecated 4900 if (engine.render && engine.render.controller) { 4901 engine.render = engine.render.controller.create(engine.render); 4902 } 4903 4904 // @deprecated 4905 if (engine.render) { 4906 engine.render.engine = engine; 4907 } 4908 4909 engine.world = options.world || World.create(engine.world); 4910 engine.pairs = Pairs.create(); 4911 engine.broadphase = engine.broadphase.controller.create(engine.broadphase); 4912 engine.metrics = engine.metrics || { extended: false }; 4913 4914 4915 return engine; 4916 }; 4917 4918 /** 4919 * Moves the simulation forward in time by `delta` ms. 4920 * The `correction` argument is an optional `Number` that specifies the time correction factor to apply to the update. 4921 * This can help improve the accuracy of the simulation in cases where `delta` is changing between updates. 4922 * The value of `correction` is defined as `delta / lastDelta`, i.e. the percentage change of `delta` over the last step. 4923 * Therefore the value is always `1` (no correction) when `delta` constant (or when no correction is desired, which is the default). 4924 * See the paper on <a href="http://lonesock.net/article/verlet.html">
4924Time Corrected Verlet</a> for more information. 4925 * 4926 * Triggers `beforeUpdate` and `afterUpdate` events. 4927 * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events. 4928 * @method update 4929 * @param {engine} engine 4930 * @param {number} [delta=16.666] 4931 * @param {number} [correction=1] 4932 */ 4933 Engine.update = function(engine, delta, correction) { 4934 delta = delta || 1000 / 60; 4935 correction = correction || 1; 4936 4937 var world = engine.world, 4938 timing = engine.timing, 4939 broadphase = engine.broadphase, 4940 broadphasePairs = [], 4941 i; 4942 4943 // increment timestamp 4944 timing.timestamp += delta * timing.timeScale; 4945 4946 // create an event object 4947 var event = { 4948 timestamp: timing.timestamp 4949 }; 4950 4951 Events.trigger(engine, 'beforeUpdate', event); 4952 4953 // get lists of all bodies and constraints, no matter what composites they are in 4954 var allBodies = Composite.allBodies(world), 4955 allConstraints = Composite.allConstraints(world); 4956 4957 4958 // if sleeping enabled, call the sleeping controller 4959 if (engine.enableSleeping) 4960 Sleeping.update(allBodies, timing.timeScale); 4961 4962 // applies gravity to all bodies 4963 Engine._bodiesApplyGravity(allBodies, world.gravity); 4964 4965 // update all body position and rotation by integration 4966 Engine._bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds); 4967 4968 // update all constraints (first pass) 4969 Constraint.preSolveAll(allBodies); 4970 for (i = 0; i < engine.constraintIterations; i++) { 4971 Constraint.solveAll(allConstraints, timing.timeScale); 4972 } 4973 Constraint.postSolveAll(allBodies); 4974 4975 // broadphase pass: find potential collision pairs 4976 if (broadphase.controller) { 4977 // if world is dirty, we must flush the whole grid 4978 if (world.isModified) 4979 broadphase.controller.clear(broadphase); 4980 4981 // update the grid buckets based on current bodies 4982 broadphase.controller.update(broadphase, allBodies, engine, world.isModified); 4983 broadphasePairs = broadphase.pairsList; 4984 } else { 4985 // if no broadphase set, we just pass all bodies 4986 broadphasePairs = allBodies; 4987 } 4988 4989 // clear all composite modified flags 4990 if (world.isModified) { 4991 Composite.setModified(world, false, false, true); 4992 } 4993 4994 // narrowphase pass: find actual collisions, then create or update collision pairs 4995 var collisions = broadphase.detector(broadphasePairs, engine); 4996 4997 // update collision pairs 4998 var pairs = engine.pairs, 4999 timestamp = timing.timestamp; 5000 Pairs.update(pairs, collisions, timestamp); 5001 Pairs.removeOld(pairs, timestamp); 5002 5003 // wake up bodies involved in collisions 5004 if (engine.enableSleeping) 5005 Sleeping.afterCollisions(pairs.list, timing.timeScale); 5006 5007 // trigger collision events 5008 if (pairs.collisionStart.length > 0) 5009 Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart }); 5010 5011 // iteratively resolve position between collisions 5012 Resolver.preSolvePosition(pairs.list); 5013 for (i = 0; i < engine.positionIterations; i++) { 5014 Resolver.solvePosition(pairs.list, timing.timeScale); 5015 } 5016 Resolver.postSolvePosition(allBodies); 5017 5018 // update all constraints (second pass) 5019 Constraint.preSolveAll(allBodies); 5020 for (i = 0; i < engine.constraintIterations; i++) { 5021 Constraint.solveAll(allConstraints, timing.timeScale); 5022 } 5023 Constraint.postSolveAll(allBodies); 5024 5025 // iteratively resolve velocity between collisions 5026 Resolver.preSolveVelocity(pairs.list); 5027 for (i = 0; i < engine.velocityIterations; i++) { 5028 Resolver.solveVelocity(pairs.list, timing.timeScale); 5029 } 5030 5031 // trigger collision events 5032 if (pairs.collisionActive.length > 0) 5033 Events.trigger(engine, 'collisionActive', { pairs: pairs.c
5033ollisionActive }); 5034 5035 if (pairs.collisionEnd.length > 0) 5036 Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd }); 5037 5038 5039 // clear force buffers 5040 Engine._bodiesClearForces(allBodies); 5041 5042 Events.trigger(engine, 'afterUpdate', event); 5043 5044 return engine; 5045 }; 5046 5047 /** 5048 * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`. 5049 * @method merge 5050 * @param {engine} engineA 5051 * @param {engine} engineB 5052 */ 5053 Engine.merge = function(engineA, engineB) { 5054 Common.extend(engineA, engineB); 5055 5056 if (engineB.world) { 5057 engineA.world = engineB.world; 5058 5059 Engine.clear(engineA); 5060 5061 var bodies = Composite.allBodies(engineA.world); 5062 5063 for (var i = 0; i < bodies.length; i++) { 5064 var body = bodies[i]; 5065 Sleeping.set(body, false); 5066 body.id = Common.nextId(); 5067 } 5068 } 5069 }; 5070 5071 /** 5072 * Clears the engine including the world, pairs and broadphase. 5073 * @method clear 5074 * @param {engine} engine 5075 */ 5076 Engine.clear = function(engine) { 5077 var world = engine.world; 5078 5079 Pairs.clear(engine.pairs); 5080 5081 var broadphase = engine.broadphase; 5082 if (broadphase.controller) { 5083 var bodies = Composite.allBodies(world); 5084 broadphase.controller.clear(broadphase); 5085 broadphase.controller.update(broadphase, bodies, engine, true); 5086 } 5087 }; 5088 5089 /** 5090 * Zeroes the `body.force` and `body.torque` force buffers. 5091 * @method _bodiesClearForces 5092 * @private 5093 * @param {body[]} bodies 5094 */ 5095 Engine._bodiesClearForces = function(bodies) { 5096 for (var i = 0; i < bodies.length; i++) { 5097 var body = bodies[i]; 5098 5099 // reset force buffers 5100 body.force.x = 0; 5101 body.force.y = 0; 5102 body.torque = 0; 5103 } 5104 }; 5105 5106 /** 5107 * Applys a mass dependant force to all given bodies. 5108 * @method _bodiesApplyGravity 5109 * @private 5110 * @param {body[]} bodies 5111 * @param {vector} gravity 5112 */ 5113 Engine._bodiesApplyGravity = function(bodies, gravity) { 5114 var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001; 5115 5116 if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) { 5117 return; 5118 } 5119 5120 for (var i = 0; i < bodies.length; i++) { 5121 var body = bodies[i]; 5122 5123 if (body.isStatic || body.isSleeping) 5124 continue; 5125 5126 // apply gravity 5127 body.force.y += body.mass * gravity.y * gravityScale; 5128 body.force.x += body.mass * gravity.x * gravityScale; 5129 } 5130 }; 5131 5132 /** 5133 * Applys `Body.update` to all given `bodies`. 5134 * @method _bodiesUpdate 5135 * @private 5136 * @param {body[]} bodies 5137 * @param {number} deltaTime 5138 * The amount of time elapsed between updates 5139 * @param {number} timeScale 5140 * @param {number} correction 5141 * The Verlet correction factor (deltaTime / lastDeltaTime) 5142 * @param {bounds} worldBounds 5143 */ 5144 Engine._bodiesUpdate = function(bodies, deltaTime, timeScale, correction, worldBounds) { 5145 for (var i = 0; i < bodies.length; i++) { 5146 var body = bodies[i]; 5147 5148 if (body.isStatic || body.isSleeping) 5149 continue; 5150 5151 Body.update(body, deltaTime, timeScale, correction); 5152 } 5153 }; 5154 5155 /** 5156 * An alias for `Runner.run`, see `Matter.Runner` for more information. 5157 * @method run 5158 * @param {engine} engine 5159 */ 5160 5161 /** 5162 * Fired just before an update 5163 * 5164 * @event beforeUpdate 5165 * @param {} event An event object 5166 * @param {number} event.timestamp The engine.timing.timestamp of the event 5167 * @param {} event.source The source object of the event 5168 * @param {} event.name The name of the event 5169 */ 5170 5171 /** 5172 * Fired after engine update and all collision events 5173 * 5174 * @event afterUpdate 5175 * @param {} event An event object 5176 * @param {number} event.timestamp The engine.timing.timestamp of the event 5177 * @param {} event.source The source object of the event 5178 * @param {} event.name The name of the event 5179 */ 5180 5181 /** 5182 * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any) 5183 * 5184 * @event collisionStart 5185 * @param {} event An event object 5186 * @param {} event.pairs List of affected pairs 5187 * @param {number} event.timestamp The engine.timing.timestamp of the event 5188 * @param {} event.source The source object of the event 5189 * @param {} event.name The name of the event 5190 */ 5191 5192 /** 5193 * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any) 5194 * 5195 * @event collisionActive 5196 * @param {} event An event object 5197 * @param {} event.pairs List of affected pairs 5198 * @param {number} event.timestamp The engine.timing.timestamp of the event 5199 * @param {} event.source The source object of the event 5200 * @param {} event.name The name of the event 5201 */ 5202 5203 /** 5204 * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any) 5205 * 5206 * @event collisionEnd 5207 * @param {} event An event object 5208 * @param {} event.pairs List of affected pairs 5209 * @param {number} event.timestamp The engine.timing.timestamp of the event 5210 * @param {} event.source The source object of the event 5211 * @param {} event.name The name of the event 5212 */ 5213 5214 /* 5215 * 5216 * Properties Documentation 5217 * 5218 */ 5219 5220 /** 5221 * An integer `Number` that specifies the number of position iterations to perform each update. 5222 * The higher the value, the higher quality the simulation will be at the expense of performance. 5223 * 5224 * @property positionIterations 5225 * @type number 5226 * @default 6 5227 */ 5228 5229 /** 5230 * An integer `Number` that specifies the number of velocity iterations to perform each update. 5231 * The higher the value, the higher quality the simulation will be at the expense of performance. 5232 * 5233 * @property velocityIterations 5234 * @type number 5235 * @default 4 5236 */ 5237 5238 /** 5239 * An integer `Number` that specifies the number of constraint iterations to perform each update. 5240 * The higher the value, the higher quality the simulation will be at the expense of performance. 5241 * The default value of `2` is usually very adequate. 5242 * 5243 * @property constraintIterations 5244 * @type number 5245 * @default 2 5246 */ 5247 5248 /** 5249 * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module. 5250 * Sleeping can improve stability and performance, but often at the expense of accuracy. 5251 * 5252 * @property enableSleeping 5253 * @type boolean 5254 * @default false 5255 */ 5256 5257 /** 5258 * An `Object` containing properties regarding the timing systems of the engine. 5259 * 5260 * @property timing 5261 * @type object 5262 */ 5263 5264 /** 5265 * A `Number` that specifies the global scaling factor of time for all bodies. 5266 * A value of `0` freezes the simulation. 5267 * A value of `0.1` gives a slow-motion effect. 5268 * A value of `1.2` gives a speed-up effect. 5269 * 5270 * @property timing.timeScale 5271 * @type number 5272 * @default 1 5273 */ 5274 5275 /** 5276 * A `Number` that specifies the current simulation-time in milliseconds starting from `0`. 5277 * It is incremented on every `Engine.update` by the given `delta` argument. 5278 * 5279 * @property timing.timestamp 5280 * @type number 5281 * @default 0 5282 */ 5283 5284 /**
5285 * An instance of a `Render` controller. The default value is a `Matter.Render` instance created by `Engine.create`. 5286 * One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`. 5287 * 5288 * A minimal custom renderer object must define at least three functions: `create`, `clear` and `world` (see `Matter.Render`). 5289 * It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you. 5290 * 5291 * @property render 5292 * @type render 5293 * @deprecated see Demo.js for an example of creating a renderer 5294 * @default a Matter.Render instance 5295 */ 5296 5297 /** 5298 * An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`. 5299 * 5300 * @property broadphase 5301 * @type grid 5302 * @default a Matter.Grid instance 5303 */ 5304 5305 /** 5306 * A `World` composite object that will contain all simulated bodies and constraints. 5307 * 5308 * @property world 5309 * @type world 5310 * @default a Matter.World instance 5311 */ 5312 5313 /** 5314 * An object reserved for storing plugin-specific properties. 5315 * 5316 * @property plugin 5317 * @type {} 5318 */ 5319 5320})(); 5321 5322},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Grid":6,"../collision/Pairs":8,"../collision/Resolver":10,"../constraint/Constraint":12,"../render/Render":31,"./Common":14,"./Events":16,"./Metrics":18,"./Sleeping":22}],16:[function(_dereq_,module,exports){ 5323/** 5324* The `Matter.Events` module contains methods to fire and listen to events on other objects. 5325* 5326* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 5327* 5328* @class Events 5329*/ 5330 5331var Events = {}; 5332 5333module.exports = Events; 5334 5335var Common = _dereq_('./Common'); 5336 5337(function() { 5338 5339 /** 5340 * Subscribes a callback function to the given object's `eventName`. 5341 * @method on 5342 * @param {} object 5343 * @param {string} eventNames 5344 * @param {function} callback 5345 */ 5346 Events.on = function(object, eventNames, callback) { 5347 var names = eventNames.split(' '), 5348 name; 5349 5350 for (var i = 0; i < names.length; i++) { 5351 name = names[i]; 5352 object.events = object.events || {}; 5353 object.events[name] = object.events[name] || []; 5354 object.events[name].push(callback); 5355 } 5356 5357 return callback; 5358 }; 5359 5360 /** 5361 * Removes the given event callback. If no callback, clears all callbacks in `eventNames`. If no `eventNames`, clears all events. 5362 * @method off 5363 * @param {} object 5364 * @param {string} eventNames 5365 * @param {function} callback 5366 */ 5367 Events.off = function(object, eventNames, callback) { 5368 if (!eventNames) { 5369 object.events = {}; 5370 return; 5371 } 5372 5373 // handle Events.off(object, callback) 5374 if (typeof eventNames === 'function') { 5375 callback = eventNames; 5376 eventNames = Common.keys(object.events).join(' '); 5377 } 5378 5379 var names = eventNames.split(' '); 5380 5381 for (var i = 0; i < names.length; i++) { 5382 var callbacks = object.events[names[i]], 5383 newCallbacks = []; 5384 5385 if (callback && callbacks) { 5386 for (var j = 0; j < callbacks.length; j++) { 5387 if (callbacks[j] !== callback) 5388 newCallbacks.push(callbacks[j]); 5389 } 5390 } 5391 5392 object.events[names[i]] = newCallbacks; 5393 } 5394 }; 5395 5396 /** 5397 * Fires all the callbacks subscribed to the given object's `eventName`, in the order they subscribed, if any. 5398 * @method trigger 5399 * @param {} object 5400 * @param {string} eventNames 5401 * @param {} event 5402 */ 5403 Events.trigger = function(object, eventNames, event) { 5404 var names, 5405 name, 5406 callbacks, 5407 eventClone; 5408 5409 if (object.events) { 5410 if (!event) 5411 event = {}; 5412 5413 names = eventNames.split(' '); 5414 5415 for (var i = 0; i < names.length; i++) { 5416 name = names[i]; 5417 callbacks = object.events[name]; 5418 5419 if (callbacks) { 5420 eventClone = Common.clone(event, false); 5421 eventClone.name = name; 5422 eventClone.source = object; 5423 5424 for (var j = 0; j < callbacks.length; j++) { 5425 callbacks[j].apply(object, [eventClone]); 5426 } 5427 } 5428 } 5429 } 5430 }; 5431 5432})(); 5433 5434},{"./Common":14}],17:[function(_dereq_,module,exports){ 5435/** 5436* The `Matter` module is the top level namespace. It also includes a function for installing plugins on top of the library. 5437* 5438* @class Matter 5439*/ 5440 5441var Matter = {}; 5442 5443module.exports = Matter; 5444 5445var Plugin = _dereq_('./Plugin'); 5446var Common = _dereq_('./Common'); 5447 5448(function() { 5449 5450 /** 5451 * The library name. 5452 * @property name 5453 * @readOnly 5454 * @type {String} 5455 */ 5456 Matter.name = 'matter-js'; 5457 5458 /** 5459 * The library version. 5460 * @property version 5461 * @readOnly 5462 * @type {String} 5463 */ 5464 Matter.version = '0.14.2'; 5465 5466 /** 5467 * A list of plugin dependencies to be installed. These are normally set and installed through `Matter.use`. 5468 * Alternatively you may set `Matter.uses` manually and install them by calling `Plugin.use(Matter)`. 5469 * @property uses 5470 * @type {Array} 5471 */ 5472 Matter.uses = []; 5473 5474 /** 5475 * The plugins that have been installed through `Matter.Plugin.install`. Read only. 5476 * @property used 5477 * @readOnly 5478 * @type {Array} 5479 */ 5480 Matter.used = []; 5481 5482 /** 5483 * Installs the given plugins on the `Matter` namespace. 5484 * This is a short-hand for `Plugin.use`, see it for more information.
5485 * Call this function once at the start of your code, with all of the plugins you wish to install as arguments. 5486 * Avoid calling this function multiple times unless you intend to manually control installation order. 5487 * @method use 5488 * @param ...plugin {Function} The plugin(s) to install on `base` (multi-argument). 5489 */ 5490 Matter.use = function() { 5491 Plugin.use(Matter, Array.prototype.slice.call(arguments)); 5492 }; 5493 5494 /** 5495 * Chains a function to excute before the original function on the given `path` relative to `Matter`. 5496 * See also docs for `Common.chain`. 5497 * @method before 5498 * @param {string} path The path relative to `Matter` 5499 * @param {function} func The function to chain before the original 5500 * @return {function} The chained function that replaced the original 5501 */ 5502 Matter.before = function(path, func) { 5503 path = path.replace(/^Matter./, ''); 5504 return Common.chainPathBefore(Matter, path, func); 5505 }; 5506 5507 /** 5508 * Chains a function to excute after the original function on the given `path` relative to `Matter`. 5509 * See also docs for `Common.chain`. 5510 * @method after 5511 * @param {string} path The path relative to `Matter` 5512 * @param {function} func The function to chain after the original 5513 * @return {function} The chained function that replaced the original 5514 */ 5515 Matter.after = function(path, func) { 5516 path = path.replace(/^Matter./, ''); 5517 return Common.chainPathAfter(Matter, path, func); 5518 }; 5519 5520})(); 5521 5522},{"./Common":14,"./Plugin":20}],18:[function(_dereq_,module,exports){ 5523 5524},{"../body/Composite":2,"./Common":14}],19:[function(_dereq_,module,exports){ 5525/** 5526* The `Matter.Mouse` module contains methods for creating and manipulating mouse inputs. 5527* 5528* @class Mouse 5529*/ 5530 5531var Mouse = {}; 5532 5533module.exports = Mouse; 5534 5535var Common = _dereq_('../core/Common'); 5536 5537(function() { 5538 5539 /** 5540 * Creates a mouse input. 5541 * @method create 5542 * @param {HTMLElement} element 5543 * @return {mouse} A new mouse 5544 */ 5545 Mouse.create = function(element) { 5546 var mouse = {}; 5547 5548 if (!element) { 5549 Common.log('Mouse.create: element was undefined, defaulting to document.body', 'warn'); 5550 } 5551 5552 mouse.element = element || document.body; 5553 mouse.absolute = { x: 0, y: 0 }; 5554 mouse.position = { x: 0, y: 0 }; 5555 mouse.mousedownPosition = { x: 0, y: 0 }; 5556 mouse.mouseupPosition = { x: 0, y: 0 }; 5557 mouse.offset = { x: 0, y: 0 }; 5558 mouse.scale = { x: 1, y: 1 }; 5559 mouse.wheelDelta = 0; 5560 mouse.button = -1; 5561 mouse.pixelRatio = mouse.element.getAttribute('data-pixel-ratio') || 1; 5562 5563 mouse.sourceEvents = { 5564 mousemove: null, 5565 mousedown: null, 5566 mouseup: null, 5567 mousewheel: null 5568 }; 5569 5570 mouse.mousemove = function(event) { 5571 var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio), 5572 touches = event.changedTouches; 5573 5574 if (touches) { 5575 mouse.button = 0; 5576 event.preventDefault(); 5577 } 5578 5579 mouse.absolute.x = position.x; 5580 mouse.absolute.y = position.y; 5581 mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; 5582 mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; 5583 mouse.sourceEvents.mousemove = event; 5584 }; 5585 5586 mouse.mousedown = function(event) { 5587 var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio), 5588 touches = event.changedTouches; 5589 5590 if (touches) { 5591 mouse.button = 0; 5592 event.preventDefault(); 5593 } else { 5594 mouse.button = event.button; 5595 } 5596 5597 mouse.absolute.x = position.x; 5598 mouse.absolute.y = position.y; 5599 mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; 5600 mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; 5601 mouse.mousedownPosition.x = mouse.position.x; 5602 mouse.mousedownPosition.y = mouse.position.y; 5603 mouse.sourceEvents.mousedown = event; 5604 }; 5605 5606 mouse.mouseup = function(event) { 5607 var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio), 5608 touches = event.changedTouches; 5609 5610 if (touches) { 5611 event.preventDefault(); 5612 } 5613 5614 mouse.button = -1; 5615 mouse.absolute.x = position.x; 5616 mouse.absolute.y = position.y; 5617 mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; 5618 mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; 5619 mouse.mouseupPosition.x = mouse.position.x; 5620 mouse.mouseupPosition.y = mouse.position.y; 5621 mouse.sourceEvents.mouseup = event; 5622 }; 5623 5624 mouse.mousewheel = function(event) { 5625 mouse.wheelDelta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail)); 5626 event.preventDefault(); 5627 }; 5628 5629 Mouse.setElement(mouse, mouse.element); 5630 5631 return mouse; 5632 }; 5633 5634 /** 5635 * Sets the element the mouse is bound to (and relative to). 5636 * @method setElement 5637 * @param {mouse} mouse 5638 * @param {HTMLElement} element 5639 */ 5640 Mouse.setElement = function(mouse, element) { 5641 mouse.element = element; 5642 5643 element.addEventListener('mousemove', mouse.mousemove); 5644 element.addEventListener('mousedown', mouse.mousedown); 5645 element.addEventListener('mouseup', mouse.mouseup); 5646 5647 element.addEventListener('mousewheel', mouse.mousewheel); 5648 element.addEventListener('DOMMouseScroll', mouse.mousewheel); 5649 5650 element.addEventListener('touchmove', mouse.mousemove);
vendor: 2,914 bytes, lines 5651-5738
5651 element.addEventListener('touchstart', mouse.mousedown); 5652 element.addEventListener('touchend', mouse.mouseup); 5653 }; 5654 5655 /** 5656 * Clears all captured source events. 5657 * @method clearSourceEvents 5658 * @param {mouse} mouse 5659 */ 5660 Mouse.clearSourceEvents = function(mouse) { 5661 mouse.sourceEvents.mousemove = null; 5662 mouse.sourceEvents.mousedown = null; 5663 mouse.sourceEvents.mouseup = null; 5664 mouse.sourceEvents.mousewheel = null; 5665 mouse.wheelDelta = 0; 5666 }; 5667 5668 /** 5669 * Sets the mouse position offset. 5670 * @method setOffset 5671 * @param {mouse} mouse 5672 * @param {vector} offset 5673 */ 5674 Mouse.setOffset = function(mouse, offset) { 5675 mouse.offset.x = offset.x; 5676 mouse.offset.y = offset.y; 5677 mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; 5678 mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; 5679 }; 5680 5681 /** 5682 * Sets the mouse position scale. 5683 * @method setScale 5684 * @param {mouse} mouse 5685 * @param {vector} scale 5686 */ 5687 Mouse.setScale = function(mouse, scale) { 5688 mouse.scale.x = scale.x; 5689 mouse.scale.y = scale.y; 5690 mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; 5691 mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; 5692 }; 5693 5694 /** 5695 * Gets the mouse position relative to an element given a screen pixel ratio. 5696 * @method _getRelativeMousePosition 5697 * @private 5698 * @param {} event 5699 * @param {} element 5700 * @param {number} pixelRatio 5701 * @return {} 5702 */ 5703 Mouse._getRelativeMousePosition = function(event, element, pixelRatio) { 5704 var elementBounds = element.getBoundingClientRect(), 5705 rootNode = (document.documentElement || document.body.parentNode || document.body), 5706 scrollX = (window.pageXOffset !== undefined) ? window.pageXOffset : rootNode.scrollLeft, 5707 scrollY = (window.pageYOffset !== undefined) ? window.pageYOffset : rootNode.scrollTop, 5708 touches = event.changedTouches, 5709 x, y; 5710 5711 if (touches) { 5712 x = touches[0].pageX - elementBounds.left - scrollX; 5713 y = touches[0].pageY - elementBounds.top - scrollY; 5714 } else { 5715 x = event.pageX - elementBounds.left - scrollX; 5716 y = event.pageY - elementBounds.top - scrollY; 5717 } 5718 5719 return { 5720 x: x / (element.clientWidth / (element.width || element.clientWidth) * pixelRatio), 5721 y: y / (element.clientHeight / (element.height || element.clientHeight) * pixelRatio) 5722 }; 5723 }; 5724 5725})(); 5726 5727},{"../core/Common":14}],20:[function(_dereq_,module,exports){ 5728/** 5729* The `Matter.Plugin` module contains functions for registering and installing plugins on modules. 5730* 5731* @class Plugin 5732*/ 5733 5734var Plugin = {}; 5735 5736module.exports = Plugin; 5737 5738var Common = _dereq_('./Common'
vendor: 9,483 bytes, lines 5738-5970
5738); 5739 5740(function() { 5741 5742 Plugin._registry = {}; 5743 5744 /** 5745 * Registers a plugin object so it can be resolved later by name. 5746 * @method register 5747 * @param plugin {} The plugin to register. 5748 * @return {object} The plugin. 5749 */ 5750 Plugin.register = function(plugin) { 5751 if (!Plugin.isPlugin(plugin)) { 5752 Common.warn('Plugin.register:', Plugin.toString(plugin), 'does not implement all required fields.'); 5753 } 5754 5755 if (plugin.name in Plugin._registry) { 5756 var registered = Plugin._registry[plugin.name], 5757 pluginVersion = Plugin.versionParse(plugin.version).number, 5758 registeredVersion = Plugin.versionParse(registered.version).number; 5759 5760 if (pluginVersion > registeredVersion) { 5761 Common.warn('Plugin.register:', Plugin.toString(registered), 'was upgraded to', Plugin.toString(plugin)); 5762 Plugin._registry[plugin.name] = plugin; 5763 } else if (pluginVersion < registeredVersion) { 5764 Common.warn('Plugin.register:', Plugin.toString(registered), 'can not be downgraded to', Plugin.toString(plugin)); 5765 } else if (plugin !== registered) { 5766 Common.warn('Plugin.register:', Plugin.toString(plugin), 'is already registered to different plugin object'); 5767 } 5768 } else { 5769 Plugin._registry[plugin.name] = plugin; 5770 } 5771 5772 return plugin; 5773 }; 5774 5775 /** 5776 * Resolves a dependency to a plugin object from the registry if it exists. 5777 * The `dependency` may contain a version, but only the name matters when resolving. 5778 * @method resolve 5779 * @param dependency {string} The dependency. 5780 * @return {object} The plugin if resolved, otherwise `undefined`. 5781 */ 5782 Plugin.resolve = function(dependency) { 5783 return Plugin._registry[Plugin.dependencyParse(dependency).name]; 5784 }; 5785 5786 /** 5787 * Returns a pretty printed plugin name and version. 5788 * @method toString 5789 * @param plugin {} The plugin. 5790 * @return {string} Pretty printed plugin name and version. 5791 */ 5792 Plugin.toString = function(plugin) { 5793 return typeof plugin === 'string' ? plugin : (plugin.name || 'anonymous') + '@' + (plugin.version || plugin.range || '0.0.0'); 5794 }; 5795 5796 /** 5797 * Returns `true` if the object meets the minimum standard to be considered a plugin. 5798 * This means it must define the following properties: 5799 * - `name` 5800 * - `version` 5801 * - `install` 5802 * @method isPlugin 5803 * @param obj {} The obj to test. 5804 * @return {boolean} `true` if the object can be considered a plugin otherwise `false`. 5805 */ 5806 Plugin.isPlugin = function(obj) { 5807 return obj && obj.name && obj.version && obj.install; 5808 }; 5809 5810 /** 5811 * Returns `true` if a plugin with the given `name` been installed on `module`. 5812 * @method isUsed 5813 * @param module {} The module. 5814 * @param name {string} The plugin name. 5815 * @return {boolean} `true` if a plugin with the given `name` been installed on `module`, otherwise `false`. 5816 */ 5817 Plugin.isUsed = function(module, name) { 5818 return module.used.indexOf(name) > -1; 5819 }; 5820 5821 /** 5822 * Returns `true` if `plugin.for` is applicable to `module` by comparing against `module.name` and `module.version`. 5823 * If `plugin.for` is not specified then it is assumed to be applicable. 5824 * The value of `plugin.for` is a string of the format `'module-name'` or `'module-name@version'`. 5825 * @method isFor 5826 * @param plugin {} The plugin. 5827 * @param module {} The module. 5828 * @return {boolean} `true` if `plugin.for` is applicable to `module`, otherwise `false`. 5829 */ 5830 Plugin.isFor = function(plugin, module) { 5831 var parsed = plugin.for && Plugin.dependencyParse(plugin.for); 5832 return !plugin.for || (module.name === parsed.name && Plugin.versionSatisfies(module.version, parsed.range)); 5833 }; 5834 5835 /** 5836 * Installs the plugins by calling `plugin.install` on each plugin specified in `plugins` if passed, otherwise `module.uses`. 5837 * For installing plugins on `Matter` see the convenience function `Matter.use`. 5838 * Plugins may be specified either by their name or a reference to the plugin object. 5839 * Plugins themselves may specify further dependencies, but each plugin is installed only once. 5840 * Order is important, a topological sort is performed to find the best resulting order of installation. 5841 * This sorting attempts to satisfy every dependency's requested ordering, but may not be exact in all cases. 5842 * This function logs the resulting status of each dependency in the console, along with any warnings. 5843 * - A green tick â indicates a dependency was resolved and installed. 5844 * - An orange diamond ð¶ indicates a dependency was resolved but a warning was thrown for it or one if its dependencies. 5845 * - A red cross â indicates a dependency could not be resolved. 5846 * Avoid calling this function multiple times on the same module unless you intend to manually control installation order. 5847 * @method use 5848 * @param module {} The module install plugins on. 5849 * @param [plugins=module.uses] {} The plugins to install on module (optional, defaults to `module.uses`). 5850 */ 5851 Plugin.use = function(module, plugins) { 5852 module.uses = (module.uses || []).concat(plugins || []); 5853 5854 if (module.uses.length === 0) { 5855 Common.warn('Plugin.use:', Plugin.toString(module), 'does not specify any dependencies to install.'); 5856 return; 5857 } 5858 5859 var dependencies = Plugin.dependencies(module), 5860 sortedDependencies = Common.topologicalSort(dependencies), 5861 status = []; 5862 5863 for (var i = 0; i < sortedDependencies.length; i += 1) { 5864 if (sortedDependencies[i] === module.name) { 5865 continue; 5866 } 5867 5868 var plugin = Plugin.resolve(sortedDependencies[i]); 5869 5870 if (!plugin) { 5871 status.push('â ' + sortedDependencies[i]); 5872 continue; 5873 } 5874 5875 if (Plugin.isUsed(module, plugin.name)) { 5876 continue; 5877 } 5878 5879 if (!Plugin.isFor(plugin, module)) { 5880 Common.warn('Plugin.use:', Plugin.toString(plugin), 'is for', plugin.for, 'but installed on', Plugin.toString(module) + '.'); 5881 plugin._warned = true; 5882 } 5883 5884 if (plugin.install) { 5885 plugin.install(module); 5886 } else { 5887 Common.warn('Plugin.use:', Plugin.toString(plugin), 'does not specify an install function.'); 5888 plugin._warned = true; 5889 } 5890 5891 if (plugin._warned) { 5892 status.push('ð¶ ' + Plugin.toString(plugin)); 5893 delete plugin._warned; 5894 } else { 5895 status.push('â ' + Plugin.toString(plugin)); 5896 } 5897 5898 module.used.push(plugin.name); 5899 } 5900 5901 if (status.length > 0) { 5902 Common.info(status.join(' ')); 5903 } 5904 }; 5905 5906 /** 5907 * Recursively finds all of a module's dependencies and returns a flat dependency graph. 5908 * @method dependencies 5909 * @param module {} The module. 5910 * @return {object} A dependency graph. 5911 */ 5912 Plugin.dependencies = function(module, tracked) { 5913 var parsedBase = Plugin.dependencyParse(module), 5914 name = parsedBase.name; 5915 5916 tracked = tracked || {}; 5917 5918 if (name in tracked) { 5919 return; 5920 } 5921 5922 module = Plugin.resolve(module) || module; 5923 5924 tracked[name] = Common.map(module.uses || [], function(dependency) { 5925 if (Plugin.isPlugin(dependency)) { 5926 Plugin.register(dependency); 5927 } 5928 5929 var parsed = Plugin.dependencyParse(dependency), 5930 resolved = Plugin.resolve(dependency); 5931 5932 if (resolved && !Plugin.versionSatisfies(resolved.version, parsed.range)) { 5933 Common.warn( 5934 'Plugin.dependencies:', Plugin.toString(resolved), 'does not satisfy', 5935 Plugin.toString(parsed), 'used by', Plugin.toString(parsedBase) + '.' 5936 ); 5937 5938 resolved._warned = true; 5939 module._warned = true; 5940 } else if (!resolved) { 5941 Common.warn( 5942 'Plugin.dependencies:', Plugin.toString(dependency), 'used by', 5943 Plugin.toString(parsedBase), 'could not be resolved.' 5944 ); 5945 5946 module._warned = true; 5947 } 5948 5949 return parsed.name; 5950 }); 5951 5952 for (var i = 0; i < tracked[name].length; i += 1) { 5953 Plugin.dependencies(tracked[name][i], tracked); 5954 } 5955 5956 return tracked; 5957 }; 5958 5959 /** 5960 * Parses a dependency string into its components. 5961 * The `dependency` is a string of the format `'module-name'` or `'module-name@version'`. 5962 * See documentation for `Plugin.versionParse` for a description of the format. 5963 * This function can also handle dependencies that are already resolved (e.g. a module object). 5964 * @method dependencyParse 5965 * @param dependency {string} The dependency of the format `'module-name'` or `'module-name@version'`. 5966 * @return {object} The dependency parsed into its components. 5967 */ 5968 Plugin.dependencyParse = function(dependency) { 5969 if (Common.isString(dependency)) { 5970 var pattern = /^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-
5970]+)?))?$/; 5971 5972 if (!pattern.test(dependency)) { 5973 Common.warn('Plugin.dependencyParse:', dependency, 'is not a valid dependency string.'); 5974 } 5975 5976 return { 5977 name: dependency.split('@')[0], 5978 range: dependency.split('@')[1] || '*' 5979 }; 5980 } 5981 5982 return { 5983 name: dependency.name, 5984 range: dependency.range || dependency.version 5985 }; 5986 }; 5987 5988 /** 5989 * Parses a version string into its components. 5990 * Versions are strictly of the format `x.y.z` (as in [semver](http://semver.org/)). 5991 * Versions may optionally have a prerelease tag in the format `x.y.z-alpha`. 5992 * Ranges are a strict subset of [npm ranges](https://docs.npmjs.com/misc/semver#advanced-range-syntax). 5993 * Only the following range types are supported: 5994 * - Tilde ranges e.g. `~1.2.3` 5995 * - Caret ranges e.g. `^1.2.3` 5996 * - Exact version e.g. `1.2.3` 5997 * - Any version `*` 5998 * @method versionParse 5999 * @param range {string} The version string. 6000 * @return {object} The version range parsed into its components. 6001 */ 6002 Plugin.versionParse = function(range) { 6003 var pattern = /^\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-]+)?$/; 6004 6005 if (!pattern.test(range)) { 6006 Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.'); 6007 } 6008 6009 var identifiers = range.split('-'); 6010 range = identifiers[0]; 6011 6012 var isRange = isNaN(Number(range[0])), 6013 version = isRange ? range.substr(1) : range, 6014 parts = Common.map(version.split('.'), function(part) { 6015 return Number(part); 6016 }); 6017 6018 return { 6019 isRange: isRange, 6020 version: version, 6021 range: range, 6022 operator: isRange ? range[0] : '', 6023 parts: parts, 6024 prerelease: identifiers[1], 6025 number: parts[0] * 1e8 + parts[1] * 1e4 + parts[2] 6026 }; 6027 }; 6028 6029 /** 6030 * Returns `true` if `version` satisfies the given `range`. 6031 * See documentation for `Plugin.versionParse` for a description of the format. 6032 * If a version or range is not specified, then any version (`*`) is assumed to satisfy. 6033 * @method versionSatisfies 6034 * @param version {string} The version string. 6035 * @param range {string} The range string. 6036 * @return {boolean} `true` if `version` satisfies `range`, otherwise `false`. 6037 */ 6038 Plugin.versionSatisfies = function(version, range) { 6039 range = range || '*'; 6040 6041 var rangeParsed = Plugin.versionParse(range), 6042 rangeParts = rangeParsed.parts, 6043 versionParsed = Plugin.versionParse(version), 6044 versionParts = versionParsed.parts; 6045 6046 if (rangeParsed.isRange) { 6047 if (rangeParsed.operator === '*' || version === '*') { 6048 return true; 6049 } 6050 6051 if (rangeParsed.operator === '~') { 6052 return versionParts[0] === rangeParts[0] && versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2]; 6053 } 6054 6055 if (rangeParsed.operator === '^') { 6056 if (rangeParts[0] > 0) { 6057 return versionParts[0] === rangeParts[0] && versionParsed.number >= rangeParsed.number; 6058 } 6059 6060 if (rangeParts[1] > 0) { 6061 return versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2]; 6062 } 6063 6064 return versionParts[2] === rangeParts[2]; 6065 } 6066 } 6067 6068 return version === range || version === '*'; 6069 }; 6070 6071})(); 6072 6073},{"./Common":14}],21:[function(_dereq_,module,exports){ 6074/** 6075* The `Matter.Runner` module is an optional utility which provides a game loop, 6076* that handles continuously updating a `Matter.Engine` for you within a browser. 6077* It is intended for development and debugging purposes, but may also be suitable for simple games. 6078* If you are using your own game loop instead, then you do not need the `Matter.Runner` module. 6079* Instead just call `Engine.update(engine, delta)` in your own loop. 6080* 6081* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 6082* 6083* @class Runner 6084*/ 6085 6086var Runner = {}; 6087 6088module.exports = Runner; 6089 6090var Events = _dereq_('./Events'); 6091var Engine = _dereq_('./Engine'); 6092var Common = _dereq_('./Common'); 6093 6094(function() { 6095 6096 var _requestAnimationFrame, 6097 _cancelAnimationFrame; 6098 6099 if (typeof window !== 'undefined') { 6100 _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame 6101 || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; 6102 6103 _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame 6104 || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; 6105 } 6106 6107 if (!_requestAnimationFrame) { 6108 var _frameTimeout; 6109 6110 _requestAnimationFrame = function(callback){ 6111 _frameTimeout = setTimeout(function() { 6112 callback(Common.now()); 6113 }, 1000 / 60); 6114 }; 6115 6116 _cancelAnimationFrame = function() { 6117 clearTimeout(_frameTimeout); 6118 }; 6119 } 6120 6121 /** 6122 * Creates a new Runner. The options parameter is an object that specifies any properties you wish to override the defaults. 6123 * @method create 6124 * @param {} options 6125 */ 6126 Runner.create = function(options) { 6127 var defaults = { 6128 fps: 60, 6129 correction: 1, 6130 deltaSampleSize: 60, 6131 counterTimestamp: 0, 6132 frameCounter: 0, 6133 deltaHistory: [], 6134 timePrev: null, 6135 timeScalePrev: 1, 6136 frameRequestId: null, 6137 isFixed: false, 6138 enabled: true 6139 }; 6140 6141 var runner = Common.extend(defaults, options); 6142 6143 runner.delta = runner.delta || 1000 / runner.fps; 6144 runner.deltaMin = runner.deltaMin || 1000 / runner.fps; 6145 runner.deltaMax = runner.deltaMax || 1000 / (runner.fps * 0.5); 6146 runner.fps = 1000 / runner.delta; 6147 6148 return runner; 6149 }; 6150 6151 /** 6152 * Continuously ticks a `Matter.Engine` by calling `Runner.tick` on the `requestAnimationFrame` event. 6153 * @method run 6154 * @param {engine} engine 6155 */ 6156 Runner.run = function(runner, engine) { 6157 // create runner if engine is first argument 6158 if (typeof runner.positionIterations !== 'undefined') { 6159 engine = runner; 6160 runner = Runner.create(); 6161 } 6162 6163 (function render(time){ 6164 runner.frameRequestId = _requestAnimationFrame(render); 6165 6166 if (time && runner.enabled) { 6167 Runner.tick(runner, engine, time); 6168 } 6169 })(); 6170 6171 return runner; 6172 }; 6173 6174 /** 6175 * A game loop utility that updates the engine and renderer by one step (a 'tick'). 6176 * Features delta smoothing, time correction and fixed or dynamic timing. 6177 * Triggers `beforeTick`, `tick` and `afterTick` events on the engine. 6178 * Consider just `Engine.update(engine, delta)` if you're using your own loop. 6179 * @method tick 6180 * @param {runner} runner 6181 * @param {engine} engine 6182 * @param {number} time 6183 */ 6184 Runner.tick = function(runner, engine, time) { 6185 var timing = engine.timing, 6186 correction = 1, 6187 delta; 6188 6189 // create an event object 6190 var event = { 6191 timestamp: timing.timestamp 6192 }; 6193 6194 Events.trigger(runner, 'beforeTick', event); 6195 Events.trigger(engine, 'beforeTick', event); // @deprecated 6196 6197 if (runner.isFixed) { 6198 // fixed timestep 6199 delta = runner.delta; 6200 } else { 6201 // dynamic timestep based on wall clock between calls 6202 delta = (time - runner.timePrev) || runner.delta; 6203 runner.timePrev = time; 6204 6205 // optimistically filter delta over a few frames, to improve stability 6206 runner.deltaHistory.push(delta); 6207 runner.deltaHistory = runner.deltaHistory.slice(-runner.deltaSampleSize); 6208 delta = Math.min.apply(null, runner.deltaHistory); 6209 6210 // limit delta 6211 delta = delta < runner.deltaMin ? runner.deltaMin : delta; 6212 delta = delta > runner.deltaMax ? runner.deltaMax : delta; 6213 6214 // correction for delta 6215 correction = delta / runner.delta; 6216 6217 // update engine timing object 6218 runner.delta = delta; 6219 } 6220 6221 // time correction for time scaling 6222 if (runner.timeScalePrev !== 0) 6223 correction *= timing.timeScale / runner.timeScalePrev; 6224 6225 if (timing.timeScale === 0) 6226 correction = 0; 6227 6228 runner.timeScalePrev = timing.timeScale; 6229 runner.correction = correction; 6230 6231 // fps counter 6232 runner.frameCounter += 1; 6233 if (time - runner.counterTimestamp >= 1000) { 6234 runner.fps = runner.frameCounter * ((time - runner.counterTimestamp) / 1000); 6235 runner.counterTimestamp = time; 6236 runner.frameCounter = 0; 6237 } 6238 6239 Events.trigger(runner, 'tick', event); 6240 Events.trigger(engine, 'tick', event); // @deprecated 6241 6242 // if world has been modified, clear the render scene graph 6243 if (engine.world.isModified 6244 && engine.render 6245 && engine.render.controller 6246 && engine.render.controller.clear) { 6247 engine.render.controller.clear(engine.render); // @deprecated 6248 } 6249 6250 // update 6251 Events.trigger(runner, 'beforeUpdate', event); 6252 Engine.update(engine, delta, correction); 6253 Events.trigger(runner, 'afterUpdate', event); 6254 6255 // render 6256 // @deprecated 6257 if (engine.render && engine.render.controller) { 6258 Events.trigger(runner, 'beforeRender', event); 6259 Events.trigger(engine, 'beforeRender', event); // @deprecated 6260 6261 engine.render.controller.world(engine.render); 6262
6263 Events.trigger(runner, 'afterRender', event); 6264 Events.trigger(engine, 'afterRender', event); // @deprecated 6265 } 6266 6267 Events.trigger(runner, 'afterTick', event); 6268 Events.trigger(engine, 'afterTick', event); // @deprecated 6269 }; 6270 6271 /** 6272 * Ends execution of `Runner.run` on the given `runner`, by canceling the animation frame request event loop. 6273 * If you wish to only temporarily pause the engine, see `engine.enabled` instead. 6274 * @method stop 6275 * @param {runner} runner 6276 */ 6277 Runner.stop = function(runner) { 6278 _cancelAnimationFrame(runner.frameRequestId); 6279 }; 6280 6281 /** 6282 * Alias for `Runner.run`. 6283 * @method start 6284 * @param {runner} runner 6285 * @param {engine} engine 6286 */ 6287 Runner.start = function(runner, engine) { 6288 Runner.run(runner, engine); 6289 }; 6290 6291 /* 6292 * 6293 * Events Documentation 6294 * 6295 */ 6296 6297 /** 6298 * Fired at the start of a tick, before any updates to the engine or timing 6299 * 6300 * @event beforeTick 6301 * @param {} event An event object 6302 * @param {number} event.timestamp The engine.timing.timestamp of the event 6303 * @param {} event.source The source object of the event 6304 * @param {} event.name The name of the event 6305 */ 6306 6307 /** 6308 * Fired after engine timing updated, but just before update 6309 * 6310 * @event tick 6311 * @param {} event An event object 6312 * @param {number} event.timestamp The engine.timing.timestamp of the event 6313 * @param {} event.source The source object of the event 6314 * @param {} event.name The name of the event 6315 */ 6316 6317 /** 6318 * Fired at the end of a tick, after engine update and after rendering 6319 * 6320 * @event afterTick 6321 * @param {} event An event object 6322 * @param {number} event.timestamp The engine.timing.timestamp of the event 6323 * @param {} event.source The source object of the event 6324 * @param {} event.name The name of the event 6325 */ 6326 6327 /** 6328 * Fired before update 6329 * 6330 * @event beforeUpdate 6331 * @param {} event An event object 6332 * @param {number} event.timestamp The engine.timing.timestamp of the event 6333 * @param {} event.source The source object of the event 6334 * @param {} event.name The name of the event 6335 */ 6336 6337 /** 6338 * Fired after update 6339 * 6340 * @event afterUpdate 6341 * @param {} event An event object 6342 * @param {number} event.timestamp The engine.timing.timestamp of the event 6343 * @param {} event.source The source object of the event 6344 * @param {} event.name The name of the event 6345 */ 6346 6347 /** 6348 * Fired before rendering 6349 * 6350 * @event beforeRender 6351 * @param {} event An event object 6352 * @param {number} event.timestamp The engine.timing.timestamp of the event 6353 * @param {} event.source The source object of the event 6354 * @param {} event.name The name of the event 6355 * @deprecated 6356 */ 6357 6358 /** 6359 * Fired after rendering 6360 * 6361 * @event afterRender 6362 * @param {} event An event object 6363 * @param {number} event.timestamp The engine.timing.timestamp of the event 6364 * @param {} event.source The source object of the event 6365 * @param {} event.name The name of the event 6366 * @deprecated 6367 */ 6368 6369 /* 6370 * 6371 * Properties Documentation 6372 * 6373 */ 6374 6375 /** 6376 * A flag that specifies whether the runner is running or not. 6377 * 6378 * @property enabled 6379 * @type boolean 6380 * @default true 6381 */ 6382 6383 /** 6384 * A `Boolean` that specifies if the runner should use a fixed timestep (otherwise it is variable). 6385 * If timing is fixed, then the apparent simulation speed will change depending on the frame rate (but behaviour will be deterministic). 6386 * If the timing is variable, then the apparent simulation speed will be constant (approximately, but at the cost of determininism). 6387 * 6388 * @property isFixed 6389 * @type boolean 6390 * @default false 6391 */ 6392 6393 /** 6394 * A `Number` that specifies the time step between updates in milliseconds. 6395 * If `engine.timing.isFixed` is set to `true`, then `delta` is fixed. 6396 * If it is `false`, then `delta` can dynamically change to maintain the correct apparent simulation speed. 6397 * 6398 * @property delta 6399 * @type number 6400 * @default 1000 / 60 6401 */ 6402 6403})(); 6404 6405},{"./Common":14,"./Engine":15,"./Events":16}],22:[function(_dereq_,module,exports){ 6406/** 6407* The `Matter.Sleeping` module contains methods to manage the sleeping state of bodies. 6408* 6409* @class Sleeping 6410*/ 6411 6412var Sleeping = {}; 6413 6414module.exports = Sleeping; 6415 6416var Events = _dereq_('./Events'); 6417 6418(function() { 6419 6420 Sleeping._motionWakeThreshold = 0.18; 6421 Sleeping._motionSleepThreshold = 0.08; 6422 Sleeping._minBias = 0.9; 6423 6424 /**
6425 * Puts bodies to sleep or wakes them up depending on their motion. 6426 * @method update 6427 * @param {body[]} bodies 6428 * @param {number} timeScale 6429 */ 6430 Sleeping.update = function(bodies, timeScale) { 6431 var timeFactor = timeScale * timeScale * timeScale; 6432 6433 // update bodies sleeping status 6434 for (var i = 0; i < bodies.length; i++) { 6435 var body = bodies[i], 6436 motion = body.speed * body.speed + body.angularSpeed * body.angularSpeed; 6437 6438 // wake up bodies if they have a force applied 6439 if (body.force.x !== 0 || body.force.y !== 0) { 6440 Sleeping.set(body, false); 6441 continue; 6442 } 6443 6444 var minMotion = Math.min(body.motion, motion), 6445 maxMotion = Math.max(body.motion, motion); 6446 6447 // biased average motion estimation between frames 6448 body.motion = Sleeping._minBias * minMotion + (1 - Sleeping._minBias) * maxMotion; 6449 6450 if (body.sleepThreshold > 0 && body.motion < Sleeping._motionSleepThreshold * timeFactor) { 6451 body.sleepCounter += 1; 6452 6453 if (body.sleepCounter >= body.sleepThreshold) 6454 Sleeping.set(body, true); 6455 } else if (body.sleepCounter > 0) { 6456 body.sleepCounter -= 1; 6457 } 6458 } 6459 }; 6460 6461 /** 6462 * Given a set of colliding pairs, wakes the sleeping bodies involved. 6463 * @method afterCollisions 6464 * @param {pair[]} pairs 6465 * @param {number} timeScale 6466 */ 6467 Sleeping.afterCollisions = function(pairs, timeScale) { 6468 var timeFactor = timeScale * timeScale * timeScale; 6469 6470 // wake up bodies involved in collisions 6471 for (var i = 0; i < pairs.length; i++) { 6472 var pair = pairs[i]; 6473 6474 // don't wake inactive pairs 6475 if (!pair.isActive) 6476 continue; 6477 6478 var collision = pair.collision, 6479 bodyA = collision.bodyA.parent, 6480 bodyB = collision.bodyB.parent; 6481 6482 // don't wake if at least one body is static 6483 if ((bodyA.isSleeping && bodyB.isSleeping) || bodyA.isStatic || bodyB.isStatic) 6484 continue; 6485 6486 if (bodyA.isSleeping || bodyB.isSleeping) { 6487 var sleepingBody = (bodyA.isSleeping && !bodyA.isStatic) ? bodyA : bodyB, 6488 movingBody = sleepingBody === bodyA ? bodyB : bodyA; 6489 6490 if (!sleepingBody.isStatic && movingBody.motion > Sleeping._motionWakeThreshold * timeFactor) { 6491 Sleeping.set(sleepingBody, false); 6492 } 6493 } 6494 } 6495 }; 6496 6497 /** 6498 * Set a body as sleeping or awake. 6499 * @method set 6500 * @param {body} body 6501 * @param {boolean} isSleeping 6502 */ 6503 Sleeping.set = function(body, isSleeping) { 6504 var wasSleeping = body.isSleeping; 6505 6506 if (isSleeping) { 6507 body.isSleeping = true; 6508 body.sleepCounter = body.sleepThreshold; 6509 6510 body.positionImpulse.x = 0; 6511 body.positionImpulse.y = 0; 6512 6513 body.positionPrev.x = body.position.x; 6514 body.positionPrev.y = body.position.y; 6515 6516 body.anglePrev = body.angle; 6517 body.speed = 0; 6518 body.angularSpeed = 0; 6519 body.motion = 0; 6520 6521 if (!wasSleeping) { 6522 Events.trigger(body, 'sleepStart'); 6523 } 6524 } else { 6525 body.isSleeping = false; 6526 body.sleepCounter = 0; 6527 6528 if (wasSleeping) { 6529 Events.trigger(body, 'sleepEnd'); 6530 } 6531 } 6532 }; 6533 6534})(); 6535 6536},{"./Events":16}],23:[function(_dereq_,module,exports){ 6537/** 6538* The `Matter.Bodies` module contains factory methods for creating rigid body models 6539* with commonly used body configurations (such as rectangles, circles and other polygons). 6540* 6541* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 6542* 6543* @class Bodies 6544*/ 6545 6546// TODO: true circle bodies 6547 6548var Bodies = {}; 6549 6550module.exports = Bodies; 6551 6552var Vertices = _dereq_('../geometry/Vertices'); 6553var Common = _dereq_('../core/Common'); 6554var Body = _dereq_('../body/Body'); 6555var Bounds = _dereq_('../geometry/Bounds'); 6556var Vector = _dereq_('../geometry/Vector'); 6557var decomp; 6558 6559(function() { 6560 6561 /** 6562 * Creates a new rigid body model with a rectangle hull. 6563 * The options parameter is an object that specifies any properties you wish to override the defaults. 6564 * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. 6565 * @method rectangle 6566 * @param {number} x 6567 * @param {number} y 6568 * @param {number} width 6569 * @param {number} height 6570 * @param {object} [options] 6571 * @return {body} A new rectangle body 6572 */ 6573 Bodies.rectangle = function(x, y, width, height, options) { 6574 options = options || {}; 6575 6576 var rectangle = { 6577 label: 'Rectangle Body', 6578 position: { x: x, y: y }, 6579 vertices: Vertices.fromPath('L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height) 6580 }; 6581 6582 if (options.chamfer) { 6583 var chamfer = options.chamfer; 6584 rectangle.vertices = Vertices.chamfer(rectangle.vertices, chamfer.radius, 6585 chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); 6586 delete options.chamfer; 6587 } 6588 6589 return Body.create(Common.extend({}, rectangle, options)); 6590 }; 6591 6592 /** 6593 * Creates a new rigid body model with a trapezoid hull. 6594 * The options parameter is an object that specifies any properties you wish to override the defaults. 6595 * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. 6596 * @method trapezoid 6597 * @param {number} x 6598 * @param {number} y 6599 * @param {number} width 6600 * @param {number} height 6601 * @param {number} slope 6602 * @param {object} [options] 6603 * @return {body} A new trapezoid body 6604 */ 6605 Bodies.trapezoid = function(x, y, width, height, slope, options) { 6606 options = options || {}; 6607 6608 slope *= 0.5; 6609 var roof = (1 - (slope * 2)) * width; 6610 6611 var x1 = width * slope, 6612 x2 = x1 + roof, 6613 x3 = x2 + x1, 6614 verticesPath; 6615 6616 if (slope < 0.5) { 6617 verticesPath = 'L 0 0 L ' + x1 + ' ' + (-height) + ' L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0'; 6618 } else { 6619 verticesPath = 'L 0 0 L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0'; 6620 } 6621 6622 var trapezoid = { 6623 label: 'Trapezoid Body', 6624 position: { x: x, y: y }, 6625 vertices: Vertices.fromPath(verticesPath) 6626 }; 6627 6628 if (options.chamfer) { 6629 var chamfer = options.chamfer; 6630 trapezoid.vertices = Vertices.chamfer(trapezoid.vertices, chamfer.radius, 6631 chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); 6632 delete options.chamfer; 6633 } 6634 6635 return Body.create(Common.extend({}, trapezoid, options)); 6636 }; 6637 6638 /** 6639 * Creates a new rigid body model with a circle hull. 6640 * The options parameter is an object that specifies any properties you wish to override the defaults. 6641 * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. 6642 * @method circle 6643 * @param {number} x 6644 * @param {number} y 6645 * @param {number} radius 6646 * @param {object} [options] 6647 * @param {number} [maxSides] 6648 * @return {body} A new circle body 6649 */ 6650 Bodies.circle = function(x, y, radius, options, maxSides) { 6651 options = options || {}; 6652 6653 var circle = { 6654 label: 'Circle Body', 6655 circleRadius: radius 6656 }; 6657 6658 // approximate circles with polygons until true circles implemented in SAT 6659 maxSides = maxSides || 25; 6660 var sides = Math.ceil(Math.max(10, Math.min(maxSides, radius))); 6661 6662 // optimisation: always use even number of sides (half the number of unique axes) 6663 if (sides % 2 === 1) 6664 sides += 1; 6665
vendor: 42,691 bytes, lines 6666-7939
6666 return Bodies.polygon(x, y, sides, radius, Common.extend({}, circle, options)); 6667 }; 6668 6669 /** 6670 * Creates a new rigid body model with a regular polygon hull with the given number of sides. 6671 * The options parameter is an object that specifies any properties you wish to override the defaults. 6672 * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. 6673 * @method polygon 6674 * @param {number} x 6675 * @param {number} y 6676 * @param {number} sides 6677 * @param {number} radius 6678 * @param {object} [options] 6679 * @return {body} A new regular polygon body 6680 */ 6681 Bodies.polygon = function(x, y, sides, radius, options) { 6682 options = options || {}; 6683 6684 if (sides < 3) 6685 return Bodies.circle(x, y, radius, options); 6686 6687 var theta = 2 * Math.PI / sides, 6688 path = '', 6689 offset = theta * 0.5; 6690 6691 for (var i = 0; i < sides; i += 1) { 6692 var angle = offset + (i * theta), 6693 xx = Math.cos(angle) * radius, 6694 yy = Math.sin(angle) * radius; 6695 6696 path += 'L ' + xx.toFixed(3) + ' ' + yy.toFixed(3) + ' '; 6697 } 6698 6699 var polygon = { 6700 label: 'Polygon Body', 6701 position: { x: x, y: y }, 6702 vertices: Vertices.fromPath(path) 6703 }; 6704 6705 if (options.chamfer) { 6706 var chamfer = options.chamfer; 6707 polygon.vertices = Vertices.chamfer(polygon.vertices, chamfer.radius, 6708 chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); 6709 delete options.chamfer; 6710 } 6711 6712 return Body.create(Common.extend({}, polygon, options)); 6713 }; 6714 6715 /** 6716 * Creates a body using the supplied vertices (or an array containing multiple sets of vertices). 6717 * If the vertices are convex, they will pass through as supplied. 6718 * Otherwise if the vertices are concave, they will be decomposed if [poly-decomp.js](https://github.com/schteppe/poly-decomp.js) is available. 6719 * Note that this process is not guaranteed to support complex sets of vertices (e.g. those with holes may fail). 6720 * By default the decomposition will discard collinear edges (to improve performance). 6721 * It can also optionally discard any parts that have an area less than `minimumArea`. 6722 * If the vertices can not be decomposed, the result will fall back to using the convex hull. 6723 * The options parameter is an object that specifies any `Matter.Body` properties you wish to override the defaults. 6724 * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object. 6725 * @method fromVertices 6726 * @param {number} x 6727 * @param {number} y 6728 * @param [[vector]] vertexSets 6729 * @param {object} [options] 6730 * @param {bool} [flagInternal=false] 6731 * @param {number} [removeCollinear=0.01] 6732 * @param {number} [minimumArea=10] 6733 * @return {body} 6734 */ 6735 Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) { 6736 if (!decomp) { 6737 decomp = Common._requireGlobal('decomp', 'poly-decomp'); 6738 } 6739 6740 var body, 6741 parts, 6742 isConvex, 6743 vertices, 6744 i, 6745 j, 6746 k, 6747 v, 6748 z; 6749 6750 options = options || {}; 6751 parts = []; 6752 6753 flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false; 6754 removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01; 6755 minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10; 6756 6757 if (!decomp) { 6758 Common.warn('Bodies.fromVertices: poly-decomp.js required. Could not decompose vertices. Fallback to convex hull.'); 6759 } 6760 6761 // ensure vertexSets is an array of arrays 6762 if (!Common.isArray(vertexSets[0])) { 6763 vertexSets = [vertexSets]; 6764 } 6765 6766 for (v = 0; v < vertexSets.length; v += 1) { 6767 vertices = vertexSets[v]; 6768 isConvex = Vertices.isConvex(vertices); 6769 6770 if (isConvex || !decomp) { 6771 if (isConvex) { 6772 vertices = Vertices.clockwiseSort(vertices); 6773 } else { 6774 // fallback to convex hull when decomposition is not possible 6775 vertices = Vertices.hull(vertices); 6776 } 6777 6778 parts.push({ 6779 position: { x: x, y: y }, 6780 vertices: vertices 6781 }); 6782 } else { 6783 // initialise a decomposition 6784 var concave = vertices.map(function(vertex) { 6785 return [vertex.x, vertex.y]; 6786 }); 6787 6788 // vertices are concave and simple, we can decompose into parts 6789 decomp.makeCCW(concave); 6790 if (removeCollinear !== false) 6791 decomp.removeCollinearPoints(concave, removeCollinear); 6792 6793 // use the quick decomposition algorithm (Bayazit) 6794 var decomposed = decomp.quickDecomp(concave); 6795 6796 // for each decomposed chunk 6797 for (i = 0; i < decomposed.length; i++) { 6798 var chunk = decomposed[i]; 6799 6800 // convert vertices into the correct structure 6801 var chunkVertices = chunk.map(function(vertices) { 6802 return { 6803 x: vertices[0], 6804 y: vertices[1] 6805 }; 6806 }); 6807 6808 // skip small chunks 6809 if (minimumArea > 0 && Vertices.area(chunkVertices) < minimumArea) 6810 continue; 6811 6812 // create a compound part 6813 parts.push({ 6814 position: Vertices.centre(chunkVertices), 6815 vertices: chunkVertices 6816 }); 6817 } 6818 } 6819 } 6820 6821 // create body parts 6822 for (i = 0; i < parts.length; i++) { 6823 parts[i] = Body.create(Common.extend(parts[i], options)); 6824 } 6825 6826 // flag internal edges (coincident part edges) 6827 if (flagInternal) { 6828 var coincident_max_dist = 5; 6829 6830 for (i = 0; i < parts.length; i++) { 6831 var partA = parts[i]; 6832 6833 for (j = i + 1; j < parts.length; j++) { 6834 var partB = parts[j]; 6835 6836 if (Bounds.overlaps(partA.bounds, partB.bounds)) { 6837 var pav = partA.vertices, 6838 pbv = partB.vertices; 6839 6840 // iterate vertices of both parts 6841 for (k = 0; k < partA.vertices.length; k++) { 6842 for (z = 0; z < partB.vertices.length; z++) { 6843 // find distances between the vertices 6844 var da = Vector.magnitudeSquared(Vector.sub(pav[(k + 1) % pav.length], pbv[z])), 6845 db = Vector.magnitudeSquared(Vector.sub(pav[k], pbv[(z + 1) % pbv.length])); 6846 6847 // if both vertices are very close, consider the edge concident (internal) 6848 if (da < coincident_max_dist && db < coincident_max_dist) { 6849 pav[k].isInternal = true; 6850 pbv[z].isInternal = true; 6851 } 6852 } 6853 } 6854 6855 } 6856 } 6857 } 6858 } 6859 6860 if (parts.length > 1) { 6861 // create the parent body to be returned, that contains generated compound parts 6862 body = Body.create(Common.extend({ parts: parts.slice(0) }, options)); 6863 Body.setPosition(body, { x: x, y: y }); 6864 6865 return body; 6866 } else { 6867 return parts[0]; 6868 } 6869 }; 6870 6871})(); 6872 6873},{"../body/Body":1,"../core/Common":14,"../geometry/Bounds":26,"../geometry/Vector":28,"../geometry/Vertices":29}],24:[function(_dereq_,module,exports){ 6874/** 6875* The `Matter.Composites` module contains factory methods for creating composite bodies 6876* with commonly used configurations (such as stacks and chains). 6877* 6878* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 6879* 6880* @class Composites 6881*/ 6882 6883var Composites = {}; 6884 6885module.exports = Composites; 6886 6887var Composite = _dereq_('../body/Composite'); 6888var Constraint = _dereq_('../constraint/Constraint'); 6889var Common = _dereq_('../core/Common'); 6890var Body = _dereq_('../body/Body'); 6891var Bodies = _dereq_('./Bodies'); 6892 6893(function() { 6894 6895 /** 6896 * Create a new composite containing bodies created in the callback in a grid arrangement. 6897 * This function uses the body's bounds to prevent overlaps. 6898 * @method stack 6899 * @param {number} xx 6900 * @param {number} yy 6901 * @param {number} columns 6902 * @param {number} rows 6903 * @param {number} columnGap 6904 * @param {number} rowGap 6905 * @param {function} callback 6906 * @return {composite} A new composite containing objects created in the callback 6907 */ 6908 Composites.stack = function(xx, yy, columns, rows, columnGap, rowGap, callback) { 6909 var stack = Composite.create({ label: 'Stack' }), 6910 x = xx, 6911 y = yy, 6912 lastBody, 6913 i = 0; 6914 6915 for (var row = 0; row < rows; row++) { 6916 var maxHeight = 0; 6917 6918 for (var column = 0; column < columns; column++) { 6919 var body = callback(x, y, column, row, lastBody, i); 6920 6921 if (body) { 6922 var bodyHeight = body.bounds.max.y - body.bounds.min.y, 6923 bodyWidth = body.bounds.max.x - body.bounds.min.x; 6924 6925 if (bodyHeight > maxHeight) 6926 maxHeight = bodyHeight; 6927 6928 Body.translate(body, { x: bodyWidth * 0.5, y: bodyHeight * 0.5 }); 6929 6930 x = body.bounds.max.x + columnGap; 6931 6932 Composite.addBody(stack, body); 6933 6934 lastBody = body; 6935 i += 1; 6936 } else { 6937 x += columnGap; 6938 } 6939 } 6940 6941 y += maxHeight + rowGap; 6942 x = xx; 6943 } 6944 6945 return stack; 6946 }; 6947 6948 /** 6949 * Chains all bodies in the given composite together using constraints. 6950 * @method chain 6951 * @param {composite} composite 6952 * @param {number} xOffsetA 6953 * @param {number} yOffsetA 6954 * @param {number} xOffsetB 6955 * @param {number} yOffsetB 6956 * @param {object} options 6957 * @return {composite} A new composite containing objects chained together with constraints 6958 */ 6959 Composites.chain = function(composite, xOffsetA, yOffsetA, xOffsetB, yOffsetB, options) { 6960 var bodies = composite.bodies; 6961 6962 for (var i = 1; i < bodies.length; i++) { 6963 var bodyA = bodies[i - 1], 6964 bodyB = bodies[i], 6965 bodyAHeight = bodyA.bounds.max.y - bodyA.bounds.min.y, 6966 bodyAWidth = bodyA.bounds.max.x - bodyA.bounds.min.x, 6967 bodyBHeight = bodyB.bounds.max.y - bodyB.bounds.min.y, 6968 bodyBWidth = bodyB.bounds.max.x - bodyB.bounds.min.x; 6969 6970 var defaults = { 6971 bodyA: bodyA, 6972 pointA: { x: bodyAWidth * xOffsetA, y: bodyAHeight * yOffsetA }, 6973 bodyB: bodyB, 6974 pointB: { x: bodyBWidth * xOffsetB, y: bodyBHeight * yOffsetB } 6975 }; 6976 6977 var constraint = Common.extend(defaults, options); 6978 6979 Composite.addConstraint(composite, Constraint.create(constraint)); 6980 } 6981 6982 composite.label += ' Chain'; 6983 6984 return composite; 6985 }; 6986 6987 /** 6988 * Connects bodies in the composite with constraints in a grid pattern, with optional cross braces. 6989 * @method mesh 6990 * @param {composite} composite 6991 * @param {number} columns 6992 * @param {number} rows 6993 * @param {boolean} crossBrace 6994 * @param {object} options 6995 * @return {composite} The composite containing objects meshed together with constraints 6996 */ 6997 Composites.mesh = function(composite, columns, rows, crossBrace, options) { 6998 var bodies = composite.bodies, 6999 row, 7000 col, 7001 bodyA, 7002 bodyB, 7003 bodyC; 7004 7005 for (row = 0; row < rows; row++) { 7006 for (col = 1; col < columns; col++) { 7007 bodyA = bodies[(col - 1) + (row * columns)]; 7008 bodyB = bodies[col + (row * columns)]; 7009 Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options))); 7010 } 7011 7012 if (row > 0) { 7013 for (col = 0; col < columns; col++) { 7014 bodyA = bodies[col + ((row - 1) * columns)]; 7015 bodyB = bodies[col + (row * columns)]; 7016 Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options))); 7017 7018 if (crossBrace && col > 0) { 7019 bodyC = bodies[(col - 1) + ((row - 1) * columns)]; 7020 Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options))); 7021 } 7022 7023 if (crossBrace && col < columns - 1) { 7024 bodyC = bodies[(col + 1) + ((row - 1) * columns)]; 7025 Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options))); 7026 } 7027 } 7028 } 7029 } 7030 7031 composite.label += ' Mesh'; 7032 7033 return composite; 7034 }; 7035 7036 /** 7037 * Create a new composite containing bodies created in the callback in a pyramid arrangement. 7038 * This function uses the body's bounds to prevent overlaps. 7039 * @method pyramid 7040 * @param {number} xx 7041 * @param {number} yy 7042 * @param {number} columns 7043 * @param {number} rows 7044 * @param {number} columnGap 7045 * @param {number} rowGap 7046 * @param {function} callback 7047 * @return {composite} A new composite containing objects created in the callback 7048 */ 7049 Composites.pyramid = function(xx, yy, columns, rows, columnGap, rowGap, callback) { 7050 return Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y, column, row, lastBody, i) { 7051 var actualRows = Math.min(rows, Math.ceil(columns / 2)), 7052 lastBodyWidth = lastBody ? lastBody.bounds.max.x - lastBody.bounds.min.x : 0; 7053 7054 if (row > actualRows) 7055 return; 7056 7057 // reverse row order 7058 row = actualRows - row; 7059 7060 var start = row, 7061 end = columns - 1 - row; 7062 7063 if (column < start || column > end) 7064 return; 7065 7066 // retroactively fix the first body's position, since width was unknown 7067 if (i === 1) { 7068 Body.translate(lastBody, { x: (column + (columns % 2 === 1 ? 1 : -1)) * lastBodyWidth, y: 0 }); 7069 } 7070 7071 var xOffset = lastBody ? column * lastBodyWidth : 0; 7072 7073 return callback(xx + xOffset + column * columnGap, y, column, row, lastBody, i); 7074 }); 7075 }; 7076 7077 /** 7078 * Creates a composite with a Newton's Cradle setup of bodies and constraints. 7079 * @method newtonsCradle 7080 * @param {number} xx 7081 * @param {number} yy 7082 * @param {number} number 7083 * @param {number} size 7084 * @param {number} length 7085 * @return {composite} A new composite newtonsCradle body 7086 */ 7087 Composites.newtonsCradle = function(xx, yy, number, size, length) { 7088 var newtonsCradle = Composite.create({ label: 'Newtons Cradle' }); 7089 7090 for (var i = 0; i < number; i++) { 7091 var separation = 1.9, 7092 circle = Bodies.circle(xx + i * (size * separation), yy + length, size, 7093 { inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 1 }), 7094 constraint = Constraint.create({ pointA: { x: xx + i * (size * separation), y: yy }, bodyB: circle }); 7095 7096 Composite.addBody(newtonsCradle, circle); 7097 Composite.addConstraint(newtonsCradle, constraint); 7098 } 7099 7100 return newtonsCradle; 7101 }; 7102 7103 /** 7104 * Creates a composite with simple car setup of bodies and constraints. 7105 * @method car 7106 * @param {number} xx 7107 * @param {number} yy 7108 * @param {number} width 7109 * @param {number} height 7110 * @param {number} wheelSize 7111 * @return {composite} A new composite car body 7112 */ 7113 Composites.car = function(xx, yy, width, height, wheelSize) { 7114 var group = Body.nextGroup(true), 7115 wheelBase = 20, 7116 wheelAOffset = -width * 0.5 + wheelBase, 7117 wheelBOffset = width * 0.5 - wheelBase, 7118 wheelYOffset = 0; 7119 7120 var car = Composite.create({ label: 'Car' }), 7121 body = Bodies.rectangle(xx, yy, width, height, { 7122 collisionFilter: { 7123 group: group 7124 }, 7125 chamfer: { 7126 radius: height * 0.5 7127 }, 7128 density: 0.0002 7129 }); 7130 7131 var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { 7132 collisionFilter: { 7133 group: group 7134 }, 7135 friction: 0.8 7136 }); 7137 7138 var wheelB = Bodies.circle(xx + wheelBOffset, yy + wheelYOffset, wheelSize, { 7139 collisionFilter: { 7140 group: group 7141 }, 7142 friction: 0.8 7143 }); 7144 7145 var axelA = Constraint.create({ 7146 bodyB: body, 7147 pointB: { x: wheelAOffset, y: wheelYOffset }, 7148 bodyA: wheelA, 7149 stiffness: 1, 7150 length: 0 7151 }); 7152 7153 var axelB = Constraint.create({ 7154 bodyB: body, 7155 pointB: { x: wheelBOffset, y: wheelYOffset }, 7156 bodyA: wheelB, 7157 stiffness: 1, 7158 length: 0 7159 }); 7160 7161 Composite.addBody(car, body); 7162 Composite.addBody(car, wheelA); 7163 Composite.addBody(car, wheelB); 7164 Composite.addConstraint(car, axelA); 7165 Composite.addConstraint(car, axelB); 7166 7167 return car; 7168 }; 7169 7170 /** 7171 * Creates a simple soft body like object. 7172 * @method softBody 7173 * @param {number} xx 7174 * @param {number} yy 7175 * @param {number} columns 7176 * @param {number} rows 7177 * @param {number} columnGap 7178 * @param {number} rowGap 7179 * @param {boolean} crossBrace 7180 * @param {number} particleRadius 7181 * @param {} particleOptions 7182 * @param {} constraintOptions 7183 * @return {composite} A new composite softBody 7184 */ 7185 Composites.softBody = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) { 7186 particleOptions = Common.extend({ inertia: Infinity }, particleOptions); 7187 constraintOptions = Common.extend({ stiffness: 0.2, render: { type: 'line', anchors: false } }, constraintOptions); 7188 7189 var softBody = Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y) { 7190 return Bodies.circle(x, y, particleRadius, particleOptions); 7191 }); 7192 7193 Composites.mesh(softBody, columns, rows, crossBrace, constraintOptions); 7194 7195 softBody.label = 'Soft Body'; 7196 7197 return softBody; 7198 }; 7199 7200})(); 7201 7202},{"../body/Body":1,"../body/Composite":2,"../constraint/Constraint":12,"../core/Common":14,"./Bodies":23}],25:[function(_dereq_,module,exports){ 7203/** 7204* The `Matter.Axes` module contains methods for creating and manipulating sets of axes. 7205* 7206* @class Axes 7207*/ 7208 7209var Axes = {}; 7210 7211module.exports = Axes; 7212 7213var Vector = _dereq_('../geometry/Vector'); 7214var Common = _dereq_('../core/Common'); 7215 7216(function() { 7217 7218 /** 7219 * Creates a new set of axes from the given vertices. 7220 * @method fromVertices 7221 * @param {vertices} vertices 7222 * @return {axes} A new axes from the given vertices 7223 */ 7224 Axes.fromVertices = function(vertices) { 7225 var axes = {}; 7226 7227 // find the unique axes, using edge normal gradients 7228 for (var i = 0; i < vertices.length; i++) { 7229 var j = (i + 1) % vertices.length, 7230 normal = Vector.normalise({ 7231 x: vertices[j].y - vertices[i].y, 7232 y: vertices[i].x - vertices[j].x 7233 }), 7234 gradient = (normal.y === 0) ? Infinity : (normal.x / normal.y); 7235 7236 // limit precision 7237 gradient = gradient.toFixed(3).toString(); 7238 axes[gradient] = normal; 7239 } 7240 7241 return Common.values(axes); 7242 }; 7243 7244 /** 7245 * Rotates a set of axes by the given angle. 7246 * @method rotate 7247 * @param {axes} axes 7248 * @param {number} angle 7249 */ 7250 Axes.rotate = function(axes, angle) { 7251 if (angle === 0) 7252 return; 7253 7254 var cos = Math.cos(angle), 7255 sin = Math.sin(angle); 7256 7257 for (var i = 0; i < axes.length; i++) { 7258 var axis = axes[i], 7259 xx; 7260 xx = axis.x * cos - axis.y * sin; 7261 axis.y = axis.x * sin + axis.y * cos; 7262 axis.x = xx; 7263 } 7264 }; 7265 7266})(); 7267 7268},{"../core/Common":14,"../geometry/Vector":28}],26:[function(_dereq_,module,exports){ 7269/** 7270* The `Matter.Bounds` module contains methods for creating and manipulating axis-aligned bounding boxes (AABB). 7271* 7272* @class Bounds 7273*/ 7274 7275var Bounds = {}; 7276 7277module.exports = Bounds; 7278 7279(function() { 7280 7281 /** 7282 * Creates a new axis-aligned bounding box (AABB) for the given vertices. 7283 * @method create 7284 * @param {vertices} vertices 7285 * @return {bounds} A new bounds object 7286 */ 7287 Bounds.create = function(vertices) { 7288 var bounds = { 7289 min: { x: 0, y: 0 }, 7290 max: { x: 0, y: 0 } 7291 }; 7292 7293 if (vertices) 7294 Bounds.update(bounds, vertices); 7295 7296 return bounds; 7297 }; 7298 7299 /** 7300 * Updates bounds using the given vertices and extends the bounds given a velocity. 7301 * @method update 7302 * @param {bounds} bounds 7303 * @param {vertices} vertices 7304 * @param {vector} velocity 7305 */ 7306 Bounds.update = function(bounds, vertices, velocity) { 7307 bounds.min.x = Infinity; 7308 bounds.max.x = -Infinity; 7309 bounds.min.y = Infinity; 7310 bounds.max.y = -Infinity; 7311 7312 for (var i = 0; i < vertices.length; i++) { 7313 var vertex = vertices[i]; 7314 if (vertex.x > bounds.max.x) bounds.max.x = vertex.x; 7315 if (vertex.x < bounds.min.x) bounds.min.x = vertex.x; 7316 if (vertex.y > bounds.max.y) bounds.max.y = vertex.y; 7317 if (vertex.y < bounds.min.y) bounds.min.y = vertex.y; 7318 } 7319 7320 if (velocity) { 7321 if (velocity.x > 0) { 7322 bounds.max.x += velocity.x; 7323 } else { 7324 bounds.min.x += velocity.x; 7325 } 7326 7327 if (velocity.y > 0) { 7328 bounds.max.y += velocity.y; 7329 } else { 7330 bounds.min.y += velocity.y; 7331 } 7332 } 7333 }; 7334 7335 /** 7336 * Returns true if the bounds contains the given point. 7337 * @method contains 7338 * @param {bounds} bounds 7339 * @param {vector} point 7340 * @return {boolean} True if the bounds contain the point, otherwise false 7341 */ 7342 Bounds.contains = function(bounds, point) { 7343 return point.x >= bounds.min.x && point.x <= bounds.max.x 7344 && point.y >= bounds.min.y && point.y <= bounds.max.y; 7345 }; 7346 7347 /** 7348 * Returns true if the two bounds intersect. 7349 * @method overlaps 7350 * @param {bounds} boundsA 7351 * @param {bounds} boundsB 7352 * @return {boolean} True if the bounds overlap, otherwise false 7353 */ 7354 Bounds.overlaps = function(boundsA, boundsB) { 7355 return (boundsA.min.x <= boundsB.max.x && boundsA.max.x >= boundsB.min.x 7356 && boundsA.max.y >= boundsB.min.y && boundsA.min.y <= boundsB.max.y); 7357 }; 7358 7359 /** 7360 * Translates the bounds by the given vector. 7361 * @method translate 7362 * @param {bounds} bounds 7363 * @param {vector} vector 7364 */ 7365 Bounds.translate = function(bounds, vector) { 7366 bounds.min.x += vector.x; 7367 bounds.max.x += vector.x; 7368 bounds.min.y += vector.y; 7369 bounds.max.y += vector.y; 7370 }; 7371 7372 /** 7373 * Shifts the bounds to the given position. 7374 * @method shift 7375 * @param {bounds} bounds 7376 * @param {vector} position 7377 */ 7378 Bounds.shift = function(bounds, position) { 7379 var deltaX = bounds.max.x - bounds.min.x, 7380 deltaY = bounds.max.y - bounds.min.y; 7381 7382 bounds.min.x = position.x; 7383 bounds.max.x = position.x + deltaX; 7384 bounds.min.y = position.y; 7385 bounds.max.y = position.y + deltaY; 7386 }; 7387 7388})(); 7389 7390},{}],27:[function(_dereq_,module,exports){ 7391/** 7392* The `Matter.Svg` module contains methods for converting SVG images into an array of vector points. 7393* 7394* To use this module you also need the SVGPathSeg polyfill: https://github.com/progers/pathseg 7395* 7396* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 7397* 7398* @class Svg 7399*/ 7400 7401var Svg = {}; 7402 7403module.exports = Svg; 7404 7405var Bounds = _dereq_('../geometry/Bounds'); 7406var Common = _dereq_('../core/Common'); 7407 7408(function() { 7409 7410 /** 7411 * Converts an SVG path into an array of vector points. 7412 * If the input path forms a concave shape, you must decompose the result into convex parts before use. 7413 * See `Bodies.fromVertices` which provides support for this. 7414 * Note that this function is not guaranteed to support complex paths (such as those with holes). 7415 * You must load the `pathseg.js` polyfill on newer browsers. 7416 * @method pathToVertices 7417 * @param {SVGPathElement} path 7418 * @param {Number} [sampleLength=15] 7419 * @return {Vector[]} points 7420 */ 7421 Svg.pathToVertices = function(path, sampleLength) { 7422 if (typeof window !== 'undefined' && !('SVGPathSeg' in window)) { 7423 Common.warn('Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required.'); 7424 } 7425 7426 // https://github.com/wout/svg.topoly.js/blob/master/svg.topoly.js 7427 var i, il, total, point, segment, segments, 7428 segmentsQueue, lastSegment, 7429 lastPoint, segmentIndex, points = [], 7430 lx, ly, length = 0, x = 0, y = 0; 7431 7432 sampleLength = sampleLength || 15; 7433 7434 var addPoint = function(px, py, pathSegType) { 7435 // all odd-numbered path types are relative except PATHSEG_CLOSEPATH (1) 7436 var isRelative = pathSegType % 2 === 1 && pathSegType > 1; 7437 7438 // when the last point doesn't equal the current point add the current point 7439 if (!lastPoint || px != lastPoint.x || py != lastPoint.y) { 7440 if (lastPoint && isRelative) { 7441 lx = lastPoint.x; 7442 ly = lastPoint.y; 7443 } else { 7444 lx = 0; 7445 ly = 0; 7446 } 7447 7448 var point = { 7449 x: lx + px, 7450 y: ly + py 7451 }; 7452 7453 // set last point 7454 if (isRelative || !lastPoint) { 7455 lastPoint = point; 7456 } 7457 7458 points.push(point); 7459 7460 x = lx + px; 7461 y = ly + py; 7462 } 7463 }; 7464 7465 var addSegmentPoint = function(segment) { 7466 var segType = segment.pathSegTypeAsLetter.toUpperCase(); 7467 7468 // skip path ends 7469 if (segType === 'Z') 7470 return; 7471 7472 // map segment to x and y 7473 switch (segType) { 7474 7475 case 'M': 7476 case 'L': 7477 case 'T': 7478 case 'C': 7479 case 'S': 7480 case 'Q': 7481 x = segment.x; 7482 y = segment.y; 7483 break; 7484 case 'H': 7485 x = segment.x; 7486 break; 7487 case 'V': 7488 y = segment.y; 7489 break; 7490 } 7491 7492 addPoint(x, y, segment.pathSegType); 7493 }; 7494 7495 // ensure path is absolute 7496 Svg._svgPathToAbsolute(path); 7497 7498 // get total length 7499 total = path.getTotalLength(); 7500 7501 // queue segments 7502 segments = []; 7503 for (i = 0; i < path.pathSegList.numberOfItems; i += 1) 7504 segments.push(path.pathSegList.getItem(i)); 7505 7506 segmentsQueue = segments.concat(); 7507 7508 // sample through path 7509 while (length < total) { 7510 // get segment at position 7511 segmentIndex = path.getPathSegAtLength(length); 7512 segment = segments[segmentIndex]; 7513 7514 // new segment 7515 if (segment != lastSegment) { 7516 while (segmentsQueue.length && segmentsQueue[0] != segment) 7517 addSegmentPoint(segmentsQueue.shift()); 7518 7519 lastSegment = segment; 7520 } 7521 7522 // add points in between when curving 7523 // TODO: adaptive sampling 7524 switch (segment.pathSegTypeAsLetter.toUpperCase()) { 7525 7526 case 'C': 7527 case 'T': 7528 case 'S': 7529 case 'Q': 7530 case 'A': 7531 point = path.getPointAtLength(length); 7532 addPoint(point.x, point.y, 0); 7533 break; 7534 7535 } 7536 7537 // increment by sample value 7538 length += sampleLength; 7539 } 7540 7541 // add remaining segments not passed by sampling 7542 for (i = 0, il = segmentsQueue.length; i < il; ++i) 7543 addSegmentPoint(segmentsQueue[i]); 7544 7545 return points; 7546 }; 7547 7548 Svg._svgPathToAbsolute = function(path) { 7549 // http://phrogz.net/convert-svg-path-to-all-absolute-commands 7550 // Copyright (c) Gavin Kistner 7551 // http://phrogz.net/js/_ReuseLicense.txt 7552 // Modifications: tidy formatting and naming 7553 var x0, y0, x1, y1, x2, y2, segs = path.pathSegList, 7554 x = 0, y = 0, len = segs.numberOfItems; 7555 7556 for (var i = 0; i < len; ++i) { 7557 var seg = segs.getItem(i), 7558 segType = seg.pathSegTypeAsLetter; 7559 7560 if (/[MLHVCSQTA]/.test(segType)) { 7561 if ('x' in seg) x = seg.x; 7562 if ('y' in seg) y = seg.y; 7563 } else { 7564 if ('x1' in seg) x1 = x + seg.x1; 7565 if ('x2' in seg) x2 = x + seg.x2; 7566 if ('y1' in seg) y1 = y + seg.y1; 7567 if ('y2' in seg) y2 = y + seg.y2; 7568 if ('x' in seg) x += seg.x; 7569 if ('y' in seg) y += seg.y; 7570 7571 switch (segType) { 7572 7573 case 'm': 7574 segs.replaceItem(path.createSVGPathSegMovetoAbs(x, y), i); 7575 break; 7576 case 'l': 7577 segs.replaceItem(path.createSVGPathSegLinetoAbs(x, y), i); 7578 break; 7579 case 'h': 7580 segs.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x), i); 7581 break; 7582 case 'v': 7583 segs.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y), i); 7584 break; 7585 case 'c': 7586 segs.replaceItem(path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i); 7587 break; 7588 case 's': 7589 segs.replaceItem(path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i); 7590 break; 7591 case 'q': 7592 segs.replaceItem(path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i); 7593 break; 7594 case 't': 7595 segs.replaceItem(path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i); 7596 break; 7597 case 'a': 7598 segs.replaceItem(path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i); 7599 break; 7600 case 'z': 7601 case 'Z': 7602 x = x0; 7603 y = y0; 7604 break; 7605 7606 } 7607 } 7608 7609 if (segType == 'M' || segType == 'm') { 7610 x0 = x; 7611 y0 = y; 7612 } 7613 } 7614 }; 7615 7616})(); 7617},{"../core/Common":14,"../geometry/Bounds":26}],28:[function(_dereq_,module,exports){ 7618/** 7619* The `Matter.Vector` module contains methods for creating and manipulating vectors. 7620* Vectors are the basis of all the geometry related operations in the engine. 7621* A `Matter.Vector` object is of the form `{ x: 0, y: 0 }`. 7622* 7623* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 7624* 7625* @class Vector 7626*/ 7627 7628// TODO: consider params for reusing vector objects 7629 7630var Vector = {}; 7631 7632module.exports = Vector; 7633 7634(function() { 7635 7636 /** 7637 * Creates a new vector. 7638 * @method create 7639 * @param {number} x 7640 * @param {number} y 7641 * @return {vector} A new vector 7642 */ 7643 Vector.create = function(x, y) { 7644 return { x: x || 0, y: y || 0 }; 7645 }; 7646 7647 /** 7648 * Returns a new vector with `x` and `y` copied from the given `vector`. 7649 * @method clone 7650 * @param {vector} vector 7651 * @return {vector} A new cloned vector 7652 */ 7653 Vector.clone = function(vector) { 7654 return { x: vector.x, y: vector.y }; 7655 }; 7656 7657 /** 7658 * Returns the magnitude (length) of a vector. 7659 * @method magnitude 7660 * @param {vector} vector 7661 * @return {number} The magnitude of the vector 7662 */ 7663 Vector.magnitude = function(vector) { 7664 return Math.sqrt((vector.x * vector.x) + (vector.y * vector.y)); 7665 }; 7666 7667 /** 7668 * Returns the magnitude (length) of a vector (therefore saving a `sqrt` operation). 7669 * @method magnitudeSquared 7670 * @param {vector} vector 7671 * @return {number} The squared magnitude of the vector 7672 */ 7673 Vector.magnitudeSquared = function(vector) { 7674 return (vector.x * vector.x) + (vector.y * vector.y); 7675 }; 7676 7677 /** 7678 * Rotates the vector about (0, 0) by specified angle. 7679 * @method rotate 7680 * @param {vector} vector 7681 * @param {number} angle 7682 * @param {vector} [output] 7683 * @return {vector} The vector rotated about (0, 0) 7684 */ 7685 Vector.rotate = function(vector, angle, output) { 7686 var cos = Math.cos(angle), sin = Math.sin(angle); 7687 if (!output) output = {}; 7688 var x = vector.x * cos - vector.y * sin; 7689 output.y = vector.x * sin + vector.y * cos; 7690 output.x = x; 7691 return output; 7692 }; 7693 7694 /** 7695 * Rotates the vector about a specified point by specified angle. 7696 * @method rotateAbout 7697 * @param {vector} vector 7698 * @param {number} angle 7699 * @param {vector} point 7700 * @param {vector} [output] 7701 * @return {vector} A new vector rotated about the point 7702 */ 7703 Vector.rotateAbout = function(vector, angle, point, output) { 7704 var cos = Math.cos(angle), sin = Math.sin(angle); 7705 if (!output) output = {}; 7706 var x = point.x + ((vector.x - point.x) * cos - (vector.y - point.y) * sin); 7707 output.y = point.y + ((vector.x - point.x) * sin + (vector.y - point.y) * cos); 7708 output.x = x; 7709 return output; 7710 }; 7711 7712 /** 7713 * Normalises a vector (such that its magnitude is `1`). 7714 * @method normalise 7715 * @param {vector} vector 7716 * @return {vector} A new vector normalised 7717 */ 7718 Vector.normalise = function(vector) { 7719 var magnitude = Vector.magnitude(vector); 7720 if (magnitude === 0) 7721 return { x: 0, y: 0 }; 7722 return { x: vector.x / magnitude, y: vector.y / magnitude }; 7723 }; 7724 7725 /** 7726 * Returns the dot-product of two vectors. 7727 * @method dot 7728 * @param {vector} vectorA 7729 * @param {vector} vectorB 7730 * @return {number} The dot product of the two vectors 7731 */ 7732 Vector.dot = function(vectorA, vectorB) { 7733 return (vectorA.x * vectorB.x) + (vectorA.y * vectorB.y); 7734 }; 7735 7736 /** 7737 * Returns the cross-product of two vectors. 7738 * @method cross 7739 * @param {vector} vectorA 7740 * @param {vector} vectorB 7741 * @return {number} The cross product of the two vectors 7742 */ 7743 Vector.cross = function(vectorA, vectorB) { 7744 return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x); 7745 }; 7746 7747 /** 7748 * Returns the cross-product of three vectors. 7749 * @method cross3 7750 * @param {vector} vectorA 7751 * @param {vector} vectorB 7752 * @param {vector} vectorC 7753 * @return {number} The cross product of the three vectors 7754 */ 7755 Vector.cross3 = function(vectorA, vectorB, vectorC) { 7756 return (vectorB.x - vectorA.x) * (vectorC.y - vectorA.y) - (vectorB.y - vectorA.y) * (vectorC.x - vectorA.x); 7757 }; 7758 7759 /** 7760 * Adds the two vectors. 7761 * @method add 7762 * @param {vector} vectorA 7763 * @param {vector} vectorB 7764 * @param {vector} [output] 7765 * @return {vector} A new vector of vectorA and vectorB added 7766 */ 7767 Vector.add = function(vectorA, vectorB, output) { 7768 if (!output) output = {}; 7769 output.x = vectorA.x + vectorB.x; 7770 output.y = vectorA.y + vectorB.y; 7771 return output; 7772 }; 7773 7774 /** 7775 * Subtracts the two vectors. 7776 * @method sub 7777 * @param {vector} vectorA 7778 * @param {vector} vectorB 7779 * @param {vector} [output] 7780 * @return {vector} A new vector of vectorA and vectorB subtracted 7781 */ 7782 Vector.sub = function(vectorA, vectorB, output) { 7783 if (!output) output = {}; 7784 output.x = vectorA.x - vectorB.x; 7785 output.y = vectorA.y - vectorB.y; 7786 return output; 7787 }; 7788 7789 /** 7790 * Multiplies a vector and a scalar. 7791 * @method mult 7792 * @param {vector} vector 7793 * @param {number} scalar 7794 * @return {vector} A new vector multiplied by scalar 7795 */ 7796 Vector.mult = function(vector, scalar) { 7797 return { x: vector.x * scalar, y: vector.y * scalar }; 7798 }; 7799 7800 /** 7801 * Divides a vector and a scalar. 7802 * @method div 7803 * @param {vector} vector 7804 * @param {number} scalar 7805 * @return {vector} A new vector divided by scalar 7806 */ 7807 Vector.div = function(vector, scalar) { 7808 return { x: vector.x / scalar, y: vector.y / scalar }; 7809 }; 7810 7811 /** 7812 * Returns the perpendicular vector. Set `negate` to true for the perpendicular in the opposite direction. 7813 * @method perp 7814 * @param {vector} vector 7815 * @param {bool} [negate=false] 7816 * @return {vector} The perpendicular vector 7817 */ 7818 Vector.perp = function(vector, negate) { 7819 negate = negate === true ? -1 : 1; 7820 return { x: negate * -vector.y, y: negate * vector.x }; 7821 }; 7822 7823 /** 7824 * Negates both components of a vector such that it points in the opposite direction. 7825 * @method neg 7826 * @param {vector} vector 7827 * @return {vector} The negated vector 7828 */ 7829 Vector.neg = function(vector) { 7830 return { x: -vector.x, y: -vector.y }; 7831 }; 7832 7833 /** 7834 * Returns the angle between the vector `vectorB - vectorA` and the x-axis in radians. 7835 * @method angle 7836 * @param {vector} vectorA 7837 * @param {vector} vectorB 7838 * @return {number} The angle in radians 7839 */ 7840 Vector.angle = function(vectorA, vectorB) { 7841 return Math.atan2(vectorB.y - vectorA.y, vectorB.x - vectorA.x); 7842 }; 7843 7844 /** 7845 * Temporary vector pool (not thread-safe). 7846 * @property _temp 7847 * @type {vector[]} 7848 * @private 7849 */ 7850 Vector._temp = [ 7851 Vector.create(), Vector.create(), 7852 Vector.create(), Vector.create(), 7853 Vector.create(), Vector.create() 7854 ]; 7855 7856})(); 7857},{}],29:[function(_dereq_,module,exports){ 7858/** 7859* The `Matter.Vertices` module contains methods for creating and manipulating sets of vertices. 7860* A set of vertices is an array of `Matter.Vector` with additional indexing properties inserted by `Vertices.create`. 7861* A `Matter.Body` maintains a set of vertices to represent the shape of the object (its convex hull). 7862* 7863* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). 7864* 7865* @class Vertices 7866*/ 7867 7868var Vertices = {}; 7869 7870module.exports = Vertices; 7871 7872var Vector = _dereq_('../geometry/Vector'); 7873var Common = _dereq_('../core/Common'); 7874 7875(function() { 7876 7877 /** 7878 * Creates a new set of `Matter.Body` compatible vertices. 7879 * The `points` argument accepts an array of `Matter.Vector` points orientated around the origin `(0, 0)`, for example: 7880 * 7881 * [{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }] 7882 * 7883 * The `Vertices.create` method returns a new array of vertices, which are similar to Matter.Vector objects, 7884 * but with some additional references required for efficient collision detection routines. 7885 * 7886 * Vertices must be specified in clockwise order. 7887 * 7888 * Note that the `body` argument is not optional, a `Matter.Body` reference must be provided. 7889 * 7890 * @method create 7891 * @param {vector[]} points 7892 * @param {body} body 7893 */ 7894 Vertices.create = function(points, body) { 7895 var vertices = []; 7896 7897 for (var i = 0; i < points.length; i++) { 7898 var point = points[i], 7899 vertex = { 7900 x: point.x, 7901 y: point.y, 7902 index: i, 7903 body: body, 7904 isInternal: false 7905 }; 7906 7907 vertices.push(vertex); 7908 } 7909 7910 return vertices; 7911 }; 7912 7913 /** 7914 * Parses a string containing ordered x y pairs separated by spaces (and optionally commas), 7915 * into a `Matter.Vertices` object for the given `Matter.Body`. 7916 * For parsing SVG paths, see `Svg.pathToVertices`. 7917 * @method fromPath 7918 * @param {string} path 7919 * @param {body} body 7920 * @return {vertices} vertices 7921 */ 7922 Vertices.fromPath = function(path, body) { 7923 var pathPattern = /L?\s*([\-\d\.e]+)[\s,]*([\-\d\.e]+)*/ig, 7924 points = []; 7925 7926 path.replace(pathPattern, function(match, x, y) { 7927 points.push({ x: parseFloat(x), y: parseFloat(y) }); 7928 }); 7929 7930 return Vertices.create(points, body); 7931 }; 7932 7933 /** 7934 * Returns the centre (centroid) of the set of vertices. 7935 * @method centre 7936 * @param {vertices} vertices 7937 * @return {vector} The centre point 7938 */ 7939 Vertices.centre = function(vertices) {
7940 var area = Vertices.area(vertices, true), 7941 centre = { x: 0, y: 0 }, 7942 cross, 7943 temp, 7944 j; 7945 7946 for (var i = 0; i < vertices.length; i++) { 7947 j = (i + 1) % vertices.length; 7948 cross = Vector.cross(vertices[i], vertices[j]); 7949 temp = Vector.mult(Vector.add(vertices[i], vertices[j]), cross); 7950 centre = Vector.add(centre, temp); 7951 } 7952 7953 return Vector.div(centre, 6 * area); 7954 }; 7955 7956 /** 7957 * Returns the average (mean) of the set of vertices. 7958 * @method mean 7959 * @param {vertices} vertices 7960 * @return {vector} The average point 7961 */ 7962 Vertices.mean = function(vertices) { 7963 var average = { x: 0, y: 0 }; 7964 7965 for (var i = 0; i < vertices.length; i++) { 7966 average.x += vertices[i].x; 7967 average.y += vertices[i].y; 7968 } 7969 7970 return Vector.div(average, vertices.length); 7971 }; 7972 7973 /** 7974 * Returns the area of the set of vertices. 7975 * @method area 7976 * @param {vertices} vertices 7977 * @param {bool} signed 7978 * @return {number} The area 7979 */ 7980 Vertices.area = function(vertices, signed) { 7981 var area = 0, 7982 j = vertices.length - 1; 7983 7984 for (var i = 0; i < vertices.length; i++) { 7985 area += (vertices[j].x - vertices[i].x) * (vertices[j].y + vertices[i].y); 7986 j = i; 7987 } 7988 7989 if (signed) 7990 return area / 2; 7991 7992 return Math.abs(area) / 2; 7993 }; 7994 7995 /** 7996 * Returns the moment of inertia (second moment of area) of the set of vertices given the total mass. 7997 * @method inertia 7998 * @param {vertices} vertices 7999 * @param {number} mass 8000 * @return {number} The polygon's moment of inertia 8001 */ 8002 Vertices.inertia = function(vertices, mass) { 8003 var numerator = 0, 8004 denominator = 0, 8005 v = vertices, 8006 cross, 8007 j; 8008 8009 // find the polygon's moment of inertia, using second moment of area 8010 // from equations at http://www.physicsforums.com/showthread.php?t=25293 8011 for (var n = 0; n < v.length; n++) { 8012 j = (n + 1) % v.length; 8013 cross = Math.abs(Vector.cross(v[j], v[n])); 8014 numerator += cross * (Vector.dot(v[j], v[j]) + Vector.dot(v[j], v[n]) + Vector.dot(v[n], v[n])); 8015 denominator += cross; 8016 } 8017 8018 return (mass / 6) * (numerator / denominator); 8019 }; 8020 8021 /** 8022 * Translates the set of vertices in-place. 8023 * @method translate 8024 * @param {vertices} vertices 8025 * @param {vector} vector 8026 * @param {number} scalar 8027 */ 8028 Vertices.translate = function(vertices, vector, scalar) { 8029 var i; 8030 if (scalar) { 8031 for (i = 0; i < vertices.length; i++) { 8032 vertices[i].x += vector.x * scalar; 8033 vertices[i].y += vector.y * scalar; 8034 } 8035 } else { 8036 for (i = 0; i < vertices.length; i++) { 8037 vertices[i].x += vector.x; 8038 vertices[i].y += vector.y; 8039 } 8040 } 8041 8042 return vertices; 8043 }; 8044 8045 /** 8046 * Rotates the set of vertices in-place. 8047 * @method rotate 8048 * @param {vertices} vertices 8049 * @param {number} angle 8050 * @param {vector} point 8051 */ 8052 Vertices.rotate = function(vertices, angle, point) { 8053 if (angle === 0) 8054 return; 8055 8056 var cos = Math.cos(angle), 8057 sin = Math.sin(angle); 8058 8059 for (var i = 0; i < vertices.length; i++) { 8060 var vertice = vertices[i], 8061 dx = vertice.x - point.x, 8062 dy = vertice.y - point.y; 8063 8064 vertice.x = point.x + (dx * cos - dy * sin); 8065 vertice.y = point.y + (dx * sin + dy * cos); 8066 } 8067 8068 return vertices; 8069 }; 8070 8071 /** 8072 * Returns `true` if the `point` is inside the set of `vertices`. 8073 * @method contains 8074 * @param {vertices} vertices 8075 * @param {vector} point 8076 * @return {boolean} True if the vertices contains point, otherwise false 8077 */ 8078 Vertices.contains = function(vertices, point) { 8079 for (var i = 0; i < vertices.length; i++) { 8080 var vertice = vertices[i], 8081 nextVertice = vertices[(i + 1) % vertices.length]; 8082 if ((point.x - vertice.x) * (nextVertice.y - vertice.y) + (point.y - vertice.y) * (vertice.x - nextVertice.x) > 0) { 8083 return false;
vendor: 5,007 bytes, lines 8084-8240
8084 } 8085 } 8086 8087 return true; 8088 }; 8089 8090 /** 8091 * Scales the vertices from a point (default is centre) in-place. 8092 * @method scale 8093 * @param {vertices} vertices 8094 * @param {number} scaleX 8095 * @param {number} scaleY 8096 * @param {vector} point 8097 */ 8098 Vertices.scale = function(vertices, scaleX, scaleY, point) { 8099 if (scaleX === 1 && scaleY === 1) 8100 return vertices; 8101 8102 point = point || Vertices.centre(vertices); 8103 8104 var vertex, 8105 delta; 8106 8107 for (var i = 0; i < vertices.length; i++) { 8108 vertex = vertices[i]; 8109 delta = Vector.sub(vertex, point); 8110 vertices[i].x = point.x + delta.x * scaleX; 8111 vertices[i].y = point.y + delta.y * scaleY; 8112 } 8113 8114 return vertices; 8115 }; 8116 8117 /** 8118 * Chamfers a set of vertices by giving them rounded corners, returns a new set of vertices. 8119 * The radius parameter is a single number or an array to specify the radius for each vertex. 8120 * @method chamfer 8121 * @param {vertices} vertices 8122 * @param {number[]} radius 8123 * @param {number} quality 8124 * @param {number} qualityMin 8125 * @param {number} qualityMax 8126 */ 8127 Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) { 8128 if (typeof radius === 'number') { 8129 radius = [radius]; 8130 } else { 8131 radius = radius || [8]; 8132 } 8133 8134 // quality defaults to -1, which is auto 8135 quality = (typeof quality !== 'undefined') ? quality : -1; 8136 qualityMin = qualityMin || 2; 8137 qualityMax = qualityMax || 14; 8138 8139 var newVertices = []; 8140 8141 for (var i = 0; i < vertices.length; i++) { 8142 var prevVertex = vertices[i - 1 >= 0 ? i - 1 : vertices.length - 1], 8143 vertex = vertices[i], 8144 nextVertex = vertices[(i + 1) % vertices.length], 8145 currentRadius = radius[i < radius.length ? i : radius.length - 1]; 8146 8147 if (currentRadius === 0) { 8148 newVertices.push(vertex); 8149 continue; 8150 } 8151 8152 var prevNormal = Vector.normalise({ 8153 x: vertex.y - prevVertex.y, 8154 y: prevVertex.x - vertex.x 8155 }); 8156 8157 var nextNormal = Vector.normalise({ 8158 x: nextVertex.y - vertex.y, 8159 y: vertex.x - nextVertex.x 8160 }); 8161 8162 var diagonalRadius = Math.sqrt(2 * Math.pow(currentRadius, 2)), 8163 radiusVector = Vector.mult(Common.clone(prevNormal), currentRadius), 8164 midNormal = Vector.normalise(Vector.mult(Vector.add(prevNormal, nextNormal), 0.5)), 8165 scaledVertex = Vector.sub(vertex, Vector.mult(midNormal, diagonalRadius)); 8166 8167 var precision = quality; 8168 8169 if (quality === -1) { 8170 // automatically decide precision 8171 precision = Math.pow(currentRadius, 0.32) * 1.75; 8172 } 8173 8174 precision = Common.clamp(precision, qualityMin, qualityMax); 8175 8176 // use an even value for precision, more likely to reduce axes by using symmetry 8177 if (precision % 2 === 1) 8178 precision += 1; 8179 8180 var alpha = Math.acos(Vector.dot(prevNormal, nextNormal)), 8181 theta = alpha / precision; 8182 8183 for (var j = 0; j < precision; j++) { 8184 newVertices.push(Vector.add(Vector.rotate(radiusVector, theta * j), scaledVertex)); 8185 } 8186 } 8187 8188 return newVertices; 8189 }; 8190 8191 /** 8192 * Sorts the input vertices into clockwise order in place. 8193 * @method clockwiseSort 8194 * @param {vertices} vertices 8195 * @return {vertices} vertices 8196 */ 8197 Vertices.clockwiseSort = function(vertices) { 8198 var centre = Vertices.mean(vertices); 8199 8200 vertices.sort(function(vertexA, vertexB) { 8201 return Vector.angle(centre, vertexA) - Vector.angle(centre, vertexB); 8202 }); 8203 8204 return vertices; 8205 }; 8206 8207 /** 8208 * Returns true if the vertices form a convex shape (vertices must be in clockwise order). 8209 * @method isConvex 8210 * @param {vertices} vertices 8211 * @return {bool} `true` if the `vertices` are convex, `false` if not (or `null` if not computable). 8212 */ 8213 Vertices.isConvex = function(vertices) { 8214 // http://paulbourke.net/geometry/polygonmesh/ 8215 // Copyright (c) Paul Bourke (use permitted) 8216 8217 var flag = 0, 8218 n = vertices.length, 8219 i, 8220 j, 8221 k, 8222 z; 8223 8224 if (n < 3) 8225 return null; 8226 8227 for (i = 0; i < n; i++) { 8228 j = (i + 1) % n; 8229 k = (i + 2) % n; 8230 z = (vertices[j].x - vertices[i].x) * (vertices[k].y - vertices[j].y); 8231 z -= (vertices[j].y - vertices[i].y) * (vertices[k].x - vertices[j].x); 8232 8233 if (z < 0) { 8234 flag |= 1; 8235 } else if (z > 0) { 8236 flag |= 2; 8237 } 8238 8239 if (flag === 3) { 8240 return false;
8241 } 8242 } 8243 8244 if (flag !== 0){ 8245 return true; 8246 } else { 8247 return null; 8248 } 8249 }; 8250 8251 /** 8252 * Returns the convex hull of the input vertices as a new array of points. 8253 * @method hull 8254 * @param {vertices} vertices 8255 * @return [vertex] vertices 8256 */ 8257 Vertices.hull = function(vertices) { 8258 // http://geomalgorithms.com/a10-_hull-1.html 8259 8260 var upper = [], 8261 lower = [], 8262 vertex, 8263 i; 8264 8265 // sort vertices on x-axis (y-axis for ties) 8266 vertices = vertices.slice(0); 8267 vertices.sort(function(vertexA, vertexB) { 8268 var dx = vertexA.x - vertexB.x; 8269 return dx !== 0 ? dx : vertexA.y - vertexB.y; 8270 }); 8271 8272 // build lower hull 8273 for (i = 0; i < vertices.length; i += 1) { 8274 vertex = vertices[i]; 8275 8276 while (lower.length >= 2 8277 && Vector.cross3(lower[lower.length - 2], lower[lower.length - 1], vertex) <= 0) { 8278 lower.pop(); 8279 } 8280 8281 lower.push(vertex); 8282 } 8283 8284 // build upper hull 8285 for (i = vertices.length - 1; i >= 0; i -= 1) { 8286 vertex = vertices[i]; 8287 8288 while (upper.length >= 2 8289 && Vector.cross3(upper[upper.length - 2], upper[upper.length - 1], vertex) <= 0) { 8290 upper.pop(); 8291 } 8292 8293 upper.push(vertex); 8294 } 8295 8296 // concatenation of the lower and upper hulls gives the convex hull 8297 // omit last points because they are repeated at the beginning of the other list 8298 upper.pop(); 8299 lower.pop(); 8300 8301 return upper.concat(lower); 8302 }; 8303 8304})(); 8305 8306},{"../core/Common":14,"../geometry/Vector":28}],30:[function(_dereq_,module,exports){ 8307var Matter = module.exports = _dereq_('../core/Matter'); 8308 8309Matter.Body = _dereq_('../body/Body'); 8310Matter.Composite = _dereq_('../body/Composite'); 8311Matter.World = _dereq_('../body/World'); 8312 8313Matter.Contact = _dereq_('../collision/Contact'); 8314Matter.Detector = _dereq_('../collision/Detector'); 8315Matter.Grid = _dereq_('../collision/Grid'); 8316Matter.Pairs = _dereq_('../collision/Pairs'); 8317Matter.Pair = _dereq_('../collision/Pair'); 8318Matter.Query = _dereq_('../collision/Query'); 8319Matter.Resolver = _dereq_('../collision/Resolver'); 8320Matter.SAT = _dereq_('../collision/SAT'); 8321 8322Matter.Constraint = _dereq_('../constraint/Constraint'); 8323Matter.MouseConstraint = _dereq_('../constraint/MouseConstraint'); 8324 8325Matter.Common = _dereq_('../core/Common'); 8326Matter.Engine = _dereq_('../core/Engine'); 8327Matter.Events = _dereq_('../core/Events'); 8328Matter.Mouse = _dereq_('../core/Mouse'); 8329Matter.Runner = _dereq_('../core/Runner'); 8330Matter.Sleeping = _dereq_('../core/Sleeping'); 8331Matter.Plugin = _dereq_('../core/Plugin'); 8332 8333 8334Matter.Bodies = _dereq_('../factory/Bodies'); 8335Matter.Composites = _dereq_('../factory/Composites'); 8336 8337Matter.Axes = _dereq_('../geometry/Axes'); 8338Matter.Bounds = _dereq_('../geometry/Bounds'); 8339Matter.Svg = _dereq_('../geometry/Svg'); 8340Matter.Vector = _dereq_('../geometry/Vector'); 8341Matter.Vertices = _dereq_('../geometry/Vertices'); 8342 8343Matter.Render = _dereq_('../render/Render'); 8344Matter.RenderPixi = _dereq_('../render/RenderPixi'); 8345 8346// aliases 8347 8348Matter.World.add = Matter.Composite.add; 8349Matter.World.remove = Matter.Composite.remove; 8350Matter.World.addComposite = Matter.Composite.addComposite; 8351Matter.World.addBody = Matter.Composite.addBody; 8352Matter.World.addConstraint = Matter.Composite.addConstraint; 8353Matter.World.clear = Matter.Composite.clear; 8354Matter.Engine.run = Matter.Runner.run; 8355 8356},{"../body/Body":1,"../body/Composite":2,"../body/World":3,"../collision/Contact":4,"../collision/Detector":5,"../collision/Grid":6,"../collision/Pair":7,"../collision/Pairs":8,"../collision/Query":9,"../collision/Resolver":10,"../collision/SAT":11,"../constraint/Constraint":12,"../constraint/MouseConstraint":13,"../core/Common":14,"../core/Engine":15,"../core/Events":16,"../core/Matter":17,"../core/Metrics":18,"../core/Mouse":19,"../core/Plugin":20,"../core/Runner":21,"../core/Sleeping":22,"../factory/Bodies":23,"../factory/Composites":24,"../geometry/Axes":25,"../geometry/Bounds":26,"../geometry/Svg":27,"../geometry/Vector":28,"../geometry/Vertices":29,"../render/Render":31,"../render/RenderPixi":32}],31:[function(_dereq_,module,exports){ 8357/** 8358* The `Matter.Render` module is a simple HTML5 canvas based renderer for visualising instances of `Matter.Engine`. 8359* It is intended for development and debugging purposes, but may also be suitable for simple games. 8360* It includes a number of drawing options including wireframe, vector with support for sprites and viewports. 8361* 8362* @class Render 8363*/ 8364 8365var Render = {}; 8366 8367module.exports = Render; 8368 8369var Common = _dereq_('../core/Common'); 8370var Composite = _dereq_('../body/Composite'); 8371var Bounds = _dereq_('../geometry/Bounds'); 8372var Events = _dereq_('../core/Events'); 8373var Grid = _dereq_('../collision/Grid'); 8374var Vector = _dereq_('../geometry/Vector'); 8375var Mouse = _dereq_('../core/Mouse'); 8376 8377(function() { 8378 8379 var _requestAnimationFrame, 8380 _cancelAnimationFrame; 8381 8382 if (typeof window !== 'undefined') { 8383 _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame 8384 || window.mozRequestAnimationFrame || window.msRequestAnimationFrame 8385 || function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); }; 8386 8387 _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame 8388 || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; 8389 } 8390 8391 /** 8392 * Creates a new renderer. The options parameter is an object that specifies any properties you wish to override the defaults. 8393 * All properties have default values, and many are pre-calculated automatically based on other properties. 8394 * See the properties section below for detailed information on what you can pass via the `options` object. 8395 * @method create 8396 * @param {object} [options] 8397 * @return {render} A new renderer 8398 */ 8399 Render.create = function(options) { 8400 var defaults = { 8401 controller: Render, 8402 engine: null, 8403 element: null, 8404 canvas: null, 8405 mouse: null, 8406 frameRequestId: null, 8407 options: { 8408 width: 800, 8409 height: 600, 8410 pixelRatio: 1, 8411 background: '#18181d',
vendor: 12,501 bytes, lines 8412-8768
8412 wireframeBackground: '#0f0f13', 8413 hasBounds: !!options.bounds, 8414 enabled: true, 8415 wireframes: true, 8416 showSleeping: true, 8417 showDebug: false, 8418 showBroadphase: false, 8419 showBounds: false, 8420 showVelocity: false, 8421 showCollisions: false, 8422 showSeparations: false, 8423 showAxes: false, 8424 showPositions: false, 8425 showAngleIndicator: false, 8426 showIds: false, 8427 showShadows: false, 8428 showVertexNumbers: false, 8429 showConvexHulls: false, 8430 showInternalEdges: false, 8431 showMousePosition: false 8432 } 8433 }; 8434 8435 var render = Common.extend(defaults, options); 8436 8437 if (render.canvas) { 8438 render.canvas.width = render.options.width || render.canvas.width; 8439 render.canvas.height = render.options.height || render.canvas.height; 8440 } 8441 8442 render.mouse = options.mouse; 8443 render.engine = options.engine; 8444 render.canvas = render.canvas || _createCanvas(render.options.width, render.options.height); 8445 render.context = render.canvas.getContext('2d'); 8446 render.textures = {}; 8447 8448 render.bounds = render.bounds || { 8449 min: { 8450 x: 0, 8451 y: 0 8452 }, 8453 max: { 8454 x: render.canvas.width, 8455 y: render.canvas.height 8456 } 8457 }; 8458 8459 if (render.options.pixelRatio !== 1) { 8460 Render.setPixelRatio(render, render.options.pixelRatio); 8461 } 8462 8463 if (Common.isElement(render.element)) { 8464 render.element.appendChild(render.canvas); 8465 } else if (!render.canvas.parentNode) { 8466 Common.log('Render.create: options.element was undefined, render.canvas was created but not appended', 'warn'); 8467 } 8468 8469 return render; 8470 }; 8471 8472 /** 8473 * Continuously updates the render canvas on the `requestAnimationFrame` event. 8474 * @method run 8475 * @param {render} render 8476 */ 8477 Render.run = function(render) { 8478 (function loop(time){ 8479 render.frameRequestId = _requestAnimationFrame(loop); 8480 Render.world(render); 8481 })(); 8482 }; 8483 8484 /** 8485 * Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop. 8486 * @method stop 8487 * @param {render} render 8488 */ 8489 Render.stop = function(render) { 8490 _cancelAnimationFrame(render.frameRequestId); 8491 }; 8492 8493 /** 8494 * Sets the pixel ratio of the renderer and updates the canvas. 8495 * To automatically detect the correct ratio, pass the string `'auto'` for `pixelRatio`. 8496 * @method setPixelRatio 8497 * @param {render} render 8498 * @param {number} pixelRatio 8499 */ 8500 Render.setPixelRatio = function(render, pixelRatio) { 8501 var options = render.options, 8502 canvas = render.canvas; 8503 8504 if (pixelRatio === 'auto') { 8505 pixelRatio = _getPixelRatio(canvas); 8506 } 8507 8508 options.pixelRatio = pixelRatio; 8509 canvas.setAttribute('data-pixel-ratio', pixelRatio); 8510 canvas.width = options.width * pixelRatio; 8511 canvas.height = options.height * pixelRatio; 8512 canvas.style.width = options.width + 'px'; 8513 canvas.style.height = options.height + 'px'; 8514 render.context.scale(pixelRatio, pixelRatio); 8515 }; 8516 8517 /** 8518 * Positions and sizes the viewport around the given object bounds. 8519 * Objects must have at least one of the following properties: 8520 * - `object.bounds` 8521 * - `object.position` 8522 * - `object.min` and `object.max` 8523 * - `object.x` and `object.y` 8524 * @method lookAt 8525 * @param {render} render 8526 * @param {object[]} objects 8527 * @param {vector} [padding] 8528 * @param {bool} [center=true] 8529 */ 8530 Render.lookAt = function(render, objects, padding, center) { 8531 center = typeof center !== 'undefined' ? center : true; 8532 objects = Common.isArray(objects) ? objects : [objects]; 8533 padding = padding || { 8534 x: 0, 8535 y: 0 8536 }; 8537 8538 // find bounds of all objects 8539 var bounds = { 8540 min: { x: Infinity, y: Infinity }, 8541 max: { x: -Infinity, y: -Infinity } 8542 }; 8543 8544 for (var i = 0; i < objects.length; i += 1) { 8545 var object = objects[i], 8546 min = object.bounds ? object.bounds.min : (object.min || object.position || object), 8547 max = object.bounds ? object.bounds.max : (object.max || object.position || object); 8548 8549 if (min && max) { 8550 if (min.x < bounds.min.x) 8551 bounds.min.x = min.x; 8552 8553 if (max.x > bounds.max.x) 8554 bounds.max.x = max.x; 8555 8556 if (min.y < bounds.min.y) 8557 bounds.min.y = min.y; 8558 8559 if (max.y > bounds.max.y) 8560 bounds.max.y = max.y; 8561 } 8562 } 8563 8564 // find ratios 8565 var width = (bounds.max.x - bounds.min.x) + 2 * padding.x, 8566 height = (bounds.max.y - bounds.min.y) + 2 * padding.y, 8567 viewHeight = render.canvas.height, 8568 viewWidth = render.canvas.width, 8569 outerRatio = viewWidth / viewHeight, 8570 innerRatio = width / height, 8571 scaleX = 1, 8572 scaleY = 1; 8573 8574 // find scale factor 8575 if (innerRatio > outerRatio) { 8576 scaleY = innerRatio / outerRatio; 8577 } else { 8578 scaleX = outerRatio / innerRatio; 8579 } 8580 8581 // enable bounds 8582 render.options.hasBounds = true; 8583 8584 // position and size 8585 render.bounds.min.x = bounds.min.x; 8586 render.bounds.max.x = bounds.min.x + width * scaleX; 8587 render.bounds.min.y = bounds.min.y; 8588 render.bounds.max.y = bounds.min.y + height * scaleY; 8589 8590 // center 8591 if (center) { 8592 render.bounds.min.x += width * 0.5 - (width * scaleX) * 0.5; 8593 render.bounds.max.x += width * 0.5 - (width * scaleX) * 0.5; 8594 render.bounds.min.y += height * 0.5 - (height * scaleY) * 0.5; 8595 render.bounds.max.y += height * 0.5 - (height * scaleY) * 0.5; 8596 } 8597 8598 // padding 8599 render.bounds.min.x -= padding.x; 8600 render.bounds.max.x -= padding.x; 8601 render.bounds.min.y -= padding.y; 8602 render.bounds.max.y -= padding.y; 8603 8604 // update mouse 8605 if (render.mouse) { 8606 Mouse.setScale(render.mouse, { 8607 x: (render.bounds.max.x - render.bounds.min.x) / render.canvas.width, 8608 y: (render.bounds.max.y - render.bounds.min.y) / render.canvas.height 8609 }); 8610 8611 Mouse.setOffset(render.mouse, render.bounds.min); 8612 } 8613 }; 8614 8615 /** 8616 * Applies viewport transforms based on `render.bounds` to a render context. 8617 * @method startViewTransform 8618 * @param {render} render 8619 */ 8620 Render.startViewTransform = function(render) { 8621 var boundsWidth = render.bounds.max.x - render.bounds.min.x, 8622 boundsHeight = render.bounds.max.y - render.bounds.min.y, 8623 boundsScaleX = boundsWidth / render.options.width, 8624 boundsScaleY = boundsHeight / render.options.height; 8625 8626 render.context.scale(1 / boundsScaleX, 1 / boundsScaleY); 8627 render.context.translate(-render.bounds.min.x, -render.bounds.min.y); 8628 }; 8629 8630 /** 8631 * Resets all transforms on the render context. 8632 * @method endViewTransform 8633 * @param {render} render 8634 */ 8635 Render.endViewTransform = function(render) { 8636 render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0); 8637 }; 8638 8639 /** 8640 * Renders the given `engine`'s `Matter.World` object. 8641 * This is the entry point for all rendering and should be called every time the scene changes. 8642 * @method world 8643 * @param {render} render 8644 */ 8645 Render.world = function(render) { 8646 var engine = render.engine, 8647 world = engine.world, 8648 canvas = render.canvas, 8649 context = render.context, 8650 options = render.options, 8651 allBodies = Composite.allBodies(world), 8652 allConstraints = Composite.allConstraints(world), 8653 background = options.wireframes ? options.wireframeBackground : options.background, 8654 bodies = [], 8655 constraints = [], 8656 i; 8657 8658 var event = { 8659 timestamp: engine.timing.timestamp 8660 }; 8661 8662 Events.trigger(render, 'beforeRender', event); 8663 8664 // apply background if it has changed 8665 if (render.currentBackground !== background) 8666 _applyBackground(render, background); 8667 8668 // clear the canvas with a transparent fill, to allow the canvas background to show 8669 context.globalCompositeOperation = 'source-in'; 8670 context.fillStyle = "transparent"; 8671 context.fillRect(0, 0, canvas.width, canvas.height); 8672 context.globalCompositeOperation = 'source-over'; 8673 8674 // handle bounds 8675 if (options.hasBounds) { 8676 // filter out bodies that are not in view 8677 for (i = 0; i < allBodies.length; i++) { 8678 var body = allBodies[i]; 8679 if (Bounds.overlaps(body.bounds, render.bounds)) 8680 bodies.push(body); 8681 } 8682 8683 // filter out constraints that are not in view 8684 for (i = 0; i < allConstraints.length; i++) { 8685 var constraint = allConstraints[i], 8686 bodyA = constraint.bodyA, 8687 bodyB = constraint.bodyB, 8688 pointAWorld = constraint.pointA, 8689 pointBWorld = constraint.pointB; 8690 8691 if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA); 8692 if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB); 8693 8694 if (!pointAWorld || !pointBWorld) 8695 continue; 8696 8697 if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld)) 8698 constraints.push(constraint); 8699 } 8700 8701 // transform the view 8702 Render.startViewTransform(render); 8703 8704 // update mouse 8705 if (render.mouse) { 8706 Mouse.setScale(render.mouse, { 8707 x: (render.bounds.max.x - render.bounds.min.x) / render.canvas.width, 8708 y: (render.bounds.max.y - render.bounds.min.y) / render.canvas.height 8709 }); 8710 8711 Mouse.setOffset(render.mouse, render.bounds.min); 8712 } 8713 } else { 8714 constraints = allConstraints; 8715 bodies = allBodies; 8716 } 8717 8718 if (!options.wireframes || (engine.enableSleeping && options.showSleeping)) { 8719 // fully featured rendering of bodies 8720 Render.bodies(render, bodies, context); 8721 } else { 8722 if (options.showConvexHulls) 8723 Render.bodyConvexHulls(render, bodies, context); 8724 8725 // optimised method for wireframes only 8726 Render.bodyWireframes(render, bodies, context); 8727 } 8728 8729 if (options.showBounds) 8730 Render.bodyBounds(render, bodies, context); 8731 8732 if (options.showAxes || options.showAngleIndicator) 8733 Render.bodyAxes(render, bodies, context); 8734 8735 if (options.showPositions) 8736 Render.bodyPositions(render, bodies, context); 8737 8738 if (options.showVelocity) 8739 Render.bodyVelocity(render, bodies, context); 8740 8741 if (options.showIds) 8742 Render.bodyIds(render, bodies, context); 8743 8744 if (options.showSeparations) 8745 Render.separations(render, engine.pairs.list, context); 8746 8747 if (options.showCollisions) 8748 Render.collisions(render, engine.pairs.list, context); 8749 8750 if (options.showVertexNumbers) 8751 Render.vertexNumbers(render, bodies, context); 8752 8753 if (options.showMousePosition) 8754 Render.mousePosition(render, render.mouse, context); 8755 8756 Render.constraints(constraints, context); 8757 8758 if (options.showBroadphase && engine.broadphase.controller === Grid) 8759 Render.grid(render, engine.broadphase, context); 8760 8761 if (options.showDebug) 8762 Render.debug(render, context); 8763 8764 if (options.hasBounds) { 8765 // revert view transforms 8766 Render.endViewTransform(render); 8767 } 8768
8769 Events.trigger(render, 'afterRender', event); 8770 }; 8771 8772 /** 8773 * Description 8774 * @private 8775 * @method debug 8776 * @param {render} render 8777 * @param {RenderingContext} context 8778 */ 8779 Render.debug = function(render, context) { 8780 var c = context, 8781 engine = render.engine, 8782 world = engine.world, 8783 metrics = engine.metrics, 8784 options = render.options, 8785 bodies = Composite.allBodies(world), 8786 space = " "; 8787 8788 if (engine.timing.timestamp - (render.debugTimestamp || 0) >= 500) { 8789 var text = ""; 8790 8791 if (metrics.timing) { 8792 text += "fps: " + Math.round(metrics.timing.fps) + space; 8793 } 8794 8795 8796 render.debugString = text; 8797 render.debugTimestamp = engine.timing.timestamp; 8798 } 8799 8800 if (render.debugString) { 8801 c.font = "12px Arial"; 8802 8803 if (options.wireframes) { 8804 c.fillStyle = 'rgba(255,255,255,0.5)'; 8805 } else { 8806 c.fillStyle = 'rgba(0,0,0,0.5)'; 8807 } 8808 8809 var split = render.debugString.split('\n'); 8810 8811 for (var i = 0; i < split.length; i++) { 8812 c.fillText(split[i], 50, 50 + i * 18); 8813 } 8814 } 8815 }; 8816 8817 /** 8818 * Description 8819 * @private 8820 * @method constraints 8821 * @param {constraint[]} constraints 8822 * @param {RenderingContext} context 8823 */ 8824 Render.constraints = function(constraints, context) { 8825 var c = context; 8826 8827 for (var i = 0; i < constraints.length; i++) { 8828 var constraint = constraints[i]; 8829 8830 if (!constraint.render.visible || !constraint.pointA || !constraint.pointB) 8831 continue; 8832 8833 var bodyA = constraint.bodyA, 8834 bodyB = constraint.bodyB, 8835 start, 8836 end; 8837 8838 if (bodyA) { 8839 start = Vector.add(bodyA.position, constraint.pointA); 8840 } else { 8841 start = constraint.pointA; 8842 } 8843 8844 if (constraint.render.type === 'pin') { 8845 c.beginPath(); 8846 c.arc(start.x, start.y, 3, 0, 2 * Math.PI); 8847 c.closePath(); 8848 } else { 8849 if (bodyB) { 8850 end = Vector.add(bodyB.position, constraint.pointB); 8851 } else { 8852 end = constraint.pointB; 8853 } 8854 8855 c.beginPath(); 8856 c.moveTo(start.x, start.y); 8857 8858 if (constraint.render.type === 'spring') { 8859 var delta = Vector.sub(end, start), 8860 normal = Vector.perp(Vector.normalise(delta)), 8861 coils = Math.ceil(Common.clamp(constraint.length / 5, 12, 20)), 8862 offset; 8863 8864 for (var j = 1; j < coils; j += 1) { 8865 offset = j % 2 === 0 ? 1 : -1; 8866 8867 c.lineTo( 8868 start.x + delta.x * (j / coils) + normal.x * offset * 4, 8869 start.y + delta.y * (j / coils) + normal.y * offset * 4 8870 ); 8871 } 8872 } 8873 8874 c.lineTo(end.x, end.y); 8875 } 8876 8877 if (constraint.render.lineWidth) { 8878 c.lineWidth = constraint.render.lineWidth; 8879 c.strokeStyle = constraint.render.strokeStyle; 8880 c.stroke(); 8881 } 8882 8883 if (constraint.render.anchors) { 8884 c.fillStyle = constraint.render.strokeStyle; 8885 c.beginPath(); 8886 c.arc(start.x, start.y, 3, 0, 2 * Math.PI); 8887 c.arc(end.x, end.y, 3, 0, 2 * Math.PI); 8888 c.closePath(); 8889 c.fill(); 8890 } 8891 } 8892 }; 8893 8894 /** 8895 * Description 8896 * @private 8897 * @method bodyShadows 8898 * @param {render} render 8899 * @param {body[]} bodies 8900 * @param {RenderingContext} context 8901 */ 8902 Render.bodyShadows = function(render, bodies, context) { 8903 var c = context, 8904 engine = render.engine; 8905 8906 for (var i = 0; i < bodies.length; i++) { 8907 var body = bodies[i]; 8908 8909 if (!body.render.visible) 8910 continue; 8911 8912 if (body.circleRadius) { 8913 c.beginPath(); 8914 c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI); 8915 c.closePath(); 8916 } else { 8917 c.beginPath(); 8918 c.moveTo(body.vertices[0].x, body.vertices[0].y); 8919 for (var j = 1; j < body.vertices.length; j++) { 8920 c.lineTo(body.vertices[j].x, body.vertices[j].y); 8921 } 8922 c.closePath(); 8923 } 8924 8925 var distanceX = body.position.x - render.options.width * 0.5, 8926 distanceY = body.position.y - render.options.height * 0.2, 8927 distance = Math.abs(distanceX) + Math.abs(distanceY); 8928 8929 c.shadowColor = 'rgba(0,0,0,0.15)'; 8930 c.shadowOffsetX = 0.05 * distanceX; 8931 c.shadowOffsetY = 0.05 * distanceY; 8932 c.shadowBlur = 1 + 12 * Math.min(1, distance / 1000); 8933 8934 c.fill(); 8935 8936 c.shadowColor = null; 8937 c.shadowOffsetX = null; 8938 c.shadowOffsetY = null; 8939 c.shadowBlur = null; 8940 } 8941 }; 8942 8943 /** 8944 * Description 8945 * @private 8946 * @method bodies 8947 * @param {render} render 8948 * @param {body[]} bodies
vendor: 23,379 bytes, lines 8949-9707
8949 * @param {RenderingContext} context 8950 */ 8951 Render.bodies = function(render, bodies, context) { 8952 var c = context, 8953 engine = render.engine, 8954 options = render.options, 8955 showInternalEdges = options.showInternalEdges || !options.wireframes, 8956 body, 8957 part, 8958 i, 8959 k; 8960 8961 for (i = 0; i < bodies.length; i++) { 8962 body = bodies[i]; 8963 8964 if (!body.render.visible) 8965 continue; 8966 8967 // handle compound parts 8968 for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) { 8969 part = body.parts[k]; 8970 8971 if (!part.render.visible) 8972 continue; 8973 8974 if (options.showSleeping && body.isSleeping) { 8975 c.globalAlpha = 0.5 * part.render.opacity; 8976 } else if (part.render.opacity !== 1) { 8977 c.globalAlpha = part.render.opacity; 8978 } 8979 8980 if (part.render.sprite && part.render.sprite.texture && !options.wireframes) { 8981 // part sprite 8982 var sprite = part.render.sprite, 8983 texture = _getTexture(render, sprite.texture); 8984 8985 c.translate(part.position.x, part.position.y); 8986 c.rotate(part.angle); 8987 8988 c.drawImage( 8989 texture, 8990 texture.width * -sprite.xOffset * sprite.xScale, 8991 texture.height * -sprite.yOffset * sprite.yScale, 8992 texture.width * sprite.xScale, 8993 texture.height * sprite.yScale 8994 ); 8995 8996 // revert translation, hopefully faster than save / restore 8997 c.rotate(-part.angle); 8998 c.translate(-part.position.x, -part.position.y); 8999 } else { 9000 // part polygon 9001 if (part.circleRadius) { 9002 c.beginPath(); 9003 c.arc(part.position.x, part.position.y, part.circleRadius, 0, 2 * Math.PI); 9004 } else { 9005 c.beginPath(); 9006 c.moveTo(part.vertices[0].x, part.vertices[0].y); 9007 9008 for (var j = 1; j < part.vertices.length; j++) { 9009 if (!part.vertices[j - 1].isInternal || showInternalEdges) { 9010 c.lineTo(part.vertices[j].x, part.vertices[j].y); 9011 } else { 9012 c.moveTo(part.vertices[j].x, part.vertices[j].y); 9013 } 9014 9015 if (part.vertices[j].isInternal && !showInternalEdges) { 9016 c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y); 9017 } 9018 } 9019 9020 c.lineTo(part.vertices[0].x, part.vertices[0].y); 9021 c.closePath(); 9022 } 9023 9024 if (!options.wireframes) { 9025 c.fillStyle = part.render.fillStyle; 9026 9027 if (part.render.lineWidth) { 9028 c.lineWidth = part.render.lineWidth; 9029 c.strokeStyle = part.render.strokeStyle; 9030 c.stroke(); 9031 } 9032 9033 c.fill(); 9034 } else { 9035 c.lineWidth = 1; 9036 c.strokeStyle = '#bbb'; 9037 c.stroke(); 9038 } 9039 } 9040 9041 c.globalAlpha = 1; 9042 } 9043 } 9044 }; 9045 9046 /** 9047 * Optimised method for drawing body wireframes in one pass 9048 * @private 9049 * @method bodyWireframes 9050 * @param {render} render 9051 * @param {body[]} bodies 9052 * @param {RenderingContext} context 9053 */ 9054 Render.bodyWireframes = function(render, bodies, context) { 9055 var c = context, 9056 showInternalEdges = render.options.showInternalEdges, 9057 body, 9058 part, 9059 i, 9060 j, 9061 k; 9062 9063 c.beginPath(); 9064 9065 // render all bodies 9066 for (i = 0; i < bodies.length; i++) { 9067 body = bodies[i]; 9068 9069 if (!body.render.visible) 9070 continue; 9071 9072 // handle compound parts 9073 for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) { 9074 part = body.parts[k]; 9075 9076 c.moveTo(part.vertices[0].x, part.vertices[0].y); 9077 9078 for (j = 1; j < part.vertices.length; j++) { 9079 if (!part.vertices[j - 1].isInternal || showInternalEdges) { 9080 c.lineTo(part.vertices[j].x, part.vertices[j].y); 9081 } else { 9082 c.moveTo(part.vertices[j].x, part.vertices[j].y); 9083 } 9084 9085 if (part.vertices[j].isInternal && !showInternalEdges) { 9086 c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y); 9087 } 9088 } 9089 9090 c.lineTo(part.vertices[0].x, part.vertices[0].y); 9091 } 9092 } 9093 9094 c.lineWidth = 1; 9095 c.strokeStyle = '#bbb'; 9096 c.stroke(); 9097 }; 9098 9099 /** 9100 * Optimised method for drawing body convex hull wireframes in one pass 9101 * @private 9102 * @method bodyConvexHulls 9103 * @param {render} render 9104 * @param {body[]} bodies 9105 * @param {RenderingContext} context 9106 */ 9107 Render.bodyConvexHulls = function(render, bodies, context) { 9108 var c = context, 9109 body, 9110 part, 9111 i, 9112 j, 9113 k; 9114 9115 c.beginPath(); 9116 9117 // render convex hulls 9118 for (i = 0; i < bodies.length; i++) { 9119 body = bodies[i]; 9120 9121 if (!body.render.visible || body.parts.length === 1) 9122 continue; 9123 9124 c.moveTo(body.vertices[0].x, body.vertices[0].y); 9125 9126 for (j = 1; j < body.vertices.length; j++) { 9127 c.lineTo(body.vertices[j].x, body.vertices[j].y); 9128 } 9129 9130 c.lineTo(body.vertices[0].x, body.vertices[0].y); 9131 } 9132 9133 c.lineWidth = 1; 9134 c.strokeStyle = 'rgba(255,255,255,0.2)'; 9135 c.stroke(); 9136 }; 9137 9138 /** 9139 * Renders body vertex numbers. 9140 * @private 9141 * @method vertexNumbers 9142 * @param {render} render 9143 * @param {body[]} bodies 9144 * @param {RenderingContext} context 9145 */ 9146 Render.vertexNumbers = function(render, bodies, context) { 9147 var c = context, 9148 i, 9149 j, 9150 k; 9151 9152 for (i = 0; i < bodies.length; i++) { 9153 var parts = bodies[i].parts; 9154 for (k = parts.length > 1 ? 1 : 0; k < parts.length; k++) { 9155 var part = parts[k]; 9156 for (j = 0; j < part.vertices.length; j++) { 9157 c.fillStyle = 'rgba(255,255,255,0.2)'; 9158 c.fillText(i + '_' + j, part.position.x + (part.vertices[j].x - part.position.x) * 0.8, part.position.y + (part.vertices[j].y - part.position.y) * 0.8); 9159 } 9160 } 9161 } 9162 }; 9163 9164 /** 9165 * Renders mouse position. 9166 * @private 9167 * @method mousePosition 9168 * @param {render} render 9169 * @param {mouse} mouse 9170 * @param {RenderingContext} context 9171 */ 9172 Render.mousePosition = function(render, mouse, context) { 9173 var c = context; 9174 c.fillStyle = 'rgba(255,255,255,0.8)'; 9175 c.fillText(mouse.position.x + ' ' + mouse.position.y, mouse.position.x + 5, mouse.position.y - 5); 9176 }; 9177 9178 /** 9179 * Draws body bounds 9180 * @private 9181 * @method bodyBounds 9182 * @param {render} render 9183 * @param {body[]} bodies 9184 * @param {RenderingContext} context 9185 */ 9186 Render.bodyBounds = function(render, bodies, context) { 9187 var c = context, 9188 engine = render.engine, 9189 options = render.options; 9190 9191 c.beginPath(); 9192 9193 for (var i = 0; i < bodies.length; i++) { 9194 var body = bodies[i]; 9195 9196 if (body.render.visible) { 9197 var parts = bodies[i].parts; 9198 for (var j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { 9199 var part = parts[j]; 9200 c.rect(part.bounds.min.x, part.bounds.min.y, part.bounds.max.x - part.bounds.min.x, part.bounds.max.y - part.bounds.min.y); 9201 } 9202 } 9203 } 9204 9205 if (options.wireframes) { 9206 c.strokeStyle = 'rgba(255,255,255,0.08)'; 9207 } else { 9208 c.strokeStyle = 'rgba(0,0,0,0.1)'; 9209 } 9210 9211 c.lineWidth = 1; 9212 c.stroke(); 9213 }; 9214 9215 /** 9216 * Draws body angle indicators and axes 9217 * @private 9218 * @method bodyAxes 9219 * @param {render} render 9220 * @param {body[]} bodies 9221 * @param {RenderingContext} context 9222 */ 9223 Render.bodyAxes = function(render, bodies, context) { 9224 var c = context, 9225 engine = render.engine, 9226 options = render.options, 9227 part, 9228 i, 9229 j, 9230 k; 9231 9232 c.beginPath(); 9233 9234 for (i = 0; i < bodies.length; i++) { 9235 var body = bodies[i], 9236 parts = body.parts; 9237 9238 if (!body.render.visible) 9239 continue; 9240 9241 if (options.showAxes) { 9242 // render all axes 9243 for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { 9244 part = parts[j]; 9245 for (k = 0; k < part.axes.length; k++) { 9246 var axis = part.axes[k]; 9247 c.moveTo(part.position.x, part.position.y); 9248 c.lineTo(part.position.x + axis.x * 20, part.position.y + axis.y * 20); 9249 } 9250 } 9251 } else { 9252 for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { 9253 part = parts[j]; 9254 for (k = 0; k < part.axes.length; k++) { 9255 // render a single axis indicator 9256 c.moveTo(part.position.x, part.position.y); 9257 c.lineTo((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2, 9258 (part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2); 9259 } 9260 } 9261 } 9262 } 9263 9264 if (options.wireframes) { 9265 c.strokeStyle = 'indianred'; 9266 c.lineWidth = 1; 9267 } else { 9268 c.strokeStyle = 'rgba(255, 255, 255, 0.4)'; 9269 c.globalCompositeOperation = 'overlay'; 9270 c.lineWidth = 2; 9271 } 9272 9273 c.stroke(); 9274 c.globalCompositeOperation = 'source-over'; 9275 }; 9276 9277 /** 9278 * Draws body positions 9279 * @private 9280 * @method bodyPositions 9281 * @param {render} render 9282 * @param {body[]} bodies 9283 * @param {RenderingContext} context 9284 */ 9285 Render.bodyPositions = function(render, bodies, context) { 9286 var c = context, 9287 engine = render.engine, 9288 options = render.options, 9289 body, 9290 part, 9291 i, 9292 k; 9293 9294 c.beginPath(); 9295 9296 // render current positions 9297 for (i = 0; i < bodies.length; i++) { 9298 body = bodies[i]; 9299 9300 if (!body.render.visible) 9301 continue; 9302 9303 // handle compound parts 9304 for (k = 0; k < body.parts.length; k++) { 9305 part = body.parts[k]; 9306 c.arc(part.position.x, part.position.y, 3, 0, 2 * Math.PI, false); 9307 c.closePath(); 9308 } 9309 } 9310 9311 if (options.wireframes) { 9312 c.fillStyle = 'indianred'; 9313 } else { 9314 c.fillStyle = 'rgba(0,0,0,0.5)'; 9315 } 9316 c.fill(); 9317 9318 c.beginPath(); 9319 9320 // render previous positions 9321 for (i = 0; i < bodies.length; i++) { 9322 body = bodies[i]; 9323 if (body.render.visible) { 9324 c.arc(body.positionPrev.x, body.positionPrev.y, 2, 0, 2 * Math.PI, false); 9325 c.closePath(); 9326 } 9327 } 9328 9329 c.fillStyle = 'rgba(255,165,0,0.8)'; 9330 c.fill(); 9331 }; 9332 9333 /** 9334 * Draws body velocity 9335 * @private 9336 * @method bodyVelocity 9337 * @param {render} render 9338 * @param {body[]} bodies 9339 * @param {RenderingContext} context 9340 */ 9341 Render.bodyVelocity = function(render, bodies, context) { 9342 var c = context; 9343 9344 c.beginPath(); 9345 9346 for (var i = 0; i < bodies.length; i++) { 9347 var body = bodies[i]; 9348 9349 if (!body.render.visible) 9350 continue; 9351 9352 c.moveTo(body.position.x, body.position.y); 9353 c.lineTo(body.position.x + (body.position.x - body.positionPrev.x) * 2, body.position.y + (body.position.y - body.positionPrev.y) * 2); 9354 } 9355 9356 c.lineWidth = 3; 9357 c.strokeStyle = 'cornflowerblue'; 9358 c.stroke(); 9359 }; 9360 9361 /** 9362 * Draws body ids 9363 * @private 9364 * @method bodyIds 9365 * @param {render} render 9366 * @param {body[]} bodies 9367 * @param {RenderingContext} context 9368 */ 9369 Render.bodyIds = function(render, bodies, context) { 9370 var c = context, 9371 i, 9372 j; 9373 9374 for (i = 0; i < bodies.length; i++) { 9375 if (!bodies[i].render.visible) 9376 continue; 9377 9378 var parts = bodies[i].parts; 9379 for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) { 9380 var part = parts[j]; 9381 c.font = "12px Arial"; 9382 c.fillStyle = 'rgba(255,255,255,0.5)'; 9383 c.fillText(part.id, part.position.x + 10, part.position.y - 10); 9384 } 9385 } 9386 }; 9387 9388 /** 9389 * Description 9390 * @private 9391 * @method collisions 9392 * @param {render} render 9393 * @param {pair[]} pairs 9394 * @param {RenderingContext} context 9395 */ 9396 Render.collisions = function(render, pairs, context) { 9397 var c = context, 9398 options = render.options, 9399 pair, 9400 collision, 9401 corrected, 9402 bodyA, 9403 bodyB, 9404 i, 9405 j; 9406 9407 c.beginPath(); 9408 9409 // render collision positions 9410 for (i = 0; i < pairs.length; i++) { 9411 pair = pairs[i]; 9412 9413 if (!pair.isActive) 9414 continue; 9415 9416 collision = pair.collision; 9417 for (j = 0; j < pair.activeContacts.length; j++) { 9418 var contact = pair.activeContacts[j], 9419 vertex = contact.vertex; 9420 c.rect(vertex.x - 1.5, vertex.y - 1.5, 3.5, 3.5); 9421 } 9422 } 9423 9424 if (options.wireframes) { 9425 c.fillStyle = 'rgba(255,255,255,0.7)'; 9426 } else { 9427 c.fillStyle = 'orange'; 9428 } 9429 c.fill(); 9430 9431 c.beginPath(); 9432 9433 // render collision normals 9434 for (i = 0; i < pairs.length; i++) { 9435 pair = pairs[i]; 9436 9437 if (!pair.isActive) 9438 continue; 9439 9440 collision = pair.collision; 9441 9442 if (pair.activeContacts.length > 0) { 9443 var normalPosX = pair.activeContacts[0].vertex.x, 9444 normalPosY = pair.activeContacts[0].vertex.y; 9445 9446 if (pair.activeContacts.length === 2) { 9447 normalPosX = (pair.activeContacts[0].vertex.x + pair.activeContacts[1].vertex.x) / 2; 9448 normalPosY = (pair.activeContacts[0].vertex.y + pair.activeContacts[1].vertex.y) / 2; 9449 } 9450 9451 if (collision.bodyB === collision.supports[0].body || collision.bodyA.isStatic === true) { 9452 c.moveTo(normalPosX - collision.normal.x * 8, normalPosY - collision.normal.y * 8); 9453 } else { 9454 c.moveTo(normalPosX + collision.normal.x * 8, normalPosY + collision.normal.y * 8); 9455 } 9456 9457 c.lineTo(normalPosX, normalPosY); 9458 } 9459 } 9460 9461 if (options.wireframes) { 9462 c.strokeStyle = 'rgba(255,165,0,0.7)'; 9463 } else { 9464 c.strokeStyle = 'orange'; 9465 } 9466 9467 c.lineWidth = 1; 9468 c.stroke(); 9469 }; 9470 9471 /** 9472 * Description 9473 * @private 9474 * @method separations 9475 * @param {render} render 9476 * @param {pair[]} pairs 9477 * @param {RenderingContext} context 9478 */ 9479 Render.separations = function(render, pairs, context) { 9480 var c = context, 9481 options = render.options, 9482 pair, 9483 collision, 9484 corrected, 9485 bodyA, 9486 bodyB, 9487 i, 9488 j; 9489 9490 c.beginPath(); 9491 9492 // render separations 9493 for (i = 0; i < pairs.length; i++) { 9494 pair = pairs[i]; 9495 9496 if (!pair.isActive) 9497 continue; 9498 9499 collision = pair.collision; 9500 bodyA = collision.bodyA; 9501 bodyB = collision.bodyB; 9502 9503 var k = 1; 9504 9505 if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5; 9506 if (bodyB.isStatic) k = 0; 9507 9508 c.moveTo(bodyB.position.x, bodyB.position.y); 9509 c.lineTo(bodyB.position.x - collision.penetration.x * k, bodyB.position.y - collision.penetration.y * k); 9510 9511 k = 1; 9512 9513 if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5; 9514 if (bodyA.isStatic) k = 0; 9515 9516 c.moveTo(bodyA.position.x, bodyA.position.y); 9517 c.lineTo(bodyA.position.x + collision.penetration.x * k, bodyA.position.y + collision.penetration.y * k); 9518 } 9519 9520 if (options.wireframes) { 9521 c.strokeStyle = 'rgba(255,165,0,0.5)'; 9522 } else { 9523 c.strokeStyle = 'orange'; 9524 } 9525 c.stroke(); 9526 }; 9527 9528 /** 9529 * Description 9530 * @private 9531 * @method grid 9532 * @param {render} render 9533 * @param {grid} grid 9534 * @param {RenderingContext} context 9535 */ 9536 Render.grid = function(render, grid, context) { 9537 var c = context, 9538 options = render.options; 9539 9540 if (options.wireframes) { 9541 c.strokeStyle = 'rgba(255,180,0,0.1)'; 9542 } else { 9543 c.strokeStyle = 'rgba(255,180,0,0.5)'; 9544 } 9545 9546 c.beginPath(); 9547 9548 var bucketKeys = Common.keys(grid.buckets); 9549 9550 for (var i = 0; i < bucketKeys.length; i++) { 9551 var bucketId = bucketKeys[i]; 9552 9553 if (grid.buckets[bucketId].length < 2) 9554 continue; 9555 9556 var region = bucketId.split(/C|R/); 9557 c.rect(0.5 + parseInt(region[1], 10) * grid.bucketWidth, 9558 0.5 + parseInt(region[2], 10) * grid.bucketHeight, 9559 grid.bucketWidth, 9560 grid.bucketHeight); 9561 } 9562 9563 c.lineWidth = 1; 9564 c.stroke(); 9565 }; 9566 9567 /** 9568 * Description 9569 * @private 9570 * @method inspector 9571 * @param {inspector} inspector 9572 * @param {RenderingContext} context 9573 */ 9574 Render.inspector = function(inspector, context) { 9575 var engine = inspector.engine, 9576 selected = inspector.selected, 9577 render = inspector.render, 9578 options = render.options, 9579 bounds; 9580 9581 if (options.hasBounds) { 9582 var boundsWidth = render.bounds.max.x - render.bounds.min.x, 9583 boundsHeight = render.bounds.max.y - render.bounds.min.y, 9584 boundsScaleX = boundsWidth / render.options.width, 9585 boundsScaleY = boundsHeight / render.options.height; 9586 9587 context.scale(1 / boundsScaleX, 1 / boundsScaleY); 9588 context.translate(-render.bounds.min.x, -render.bounds.min.y); 9589 } 9590 9591 for (var i = 0; i < selected.length; i++) { 9592 var item = selected[i].data; 9593 9594 context.translate(0.5, 0.5); 9595 context.lineWidth = 1; 9596 context.strokeStyle = 'rgba(255,165,0,0.9)'; 9597 context.setLineDash([1,2]); 9598 9599 switch (item.type) { 9600 9601 case 'body': 9602 9603 // render body selections 9604 bounds = item.bounds; 9605 context.beginPath(); 9606 context.rect(Math.floor(bounds.min.x - 3), Math.floor(bounds.min.y - 3), 9607 Math.floor(bounds.max.x - bounds.min.x + 6), Math.floor(bounds.max.y - bounds.min.y + 6)); 9608 context.closePath(); 9609 context.stroke(); 9610 9611 break; 9612 9613 case 'constraint': 9614 9615 // render constraint selections 9616 var point = item.pointA; 9617 if (item.bodyA) 9618 point = item.pointB; 9619 context.beginPath(); 9620 context.arc(point.x, point.y, 10, 0, 2 * Math.PI); 9621 context.closePath(); 9622 context.stroke(); 9623 9624 break; 9625 9626 } 9627 9628 context.setLineDash([]); 9629 context.translate(-0.5, -0.5); 9630 } 9631 9632 // render selection region 9633 if (inspector.selectStart !== null) { 9634 context.translate(0.5, 0.5); 9635 context.lineWidth = 1; 9636 context.strokeStyle = 'rgba(255,165,0,0.6)'; 9637 context.fillStyle = 'rgba(255,165,0,0.1)'; 9638 bounds = inspector.selectBounds; 9639 context.beginPath(); 9640 context.rect(Math.floor(bounds.min.x), Math.floor(bounds.min.y), 9641 Math.floor(bounds.max.x - bounds.min.x), Math.floor(bounds.max.y - bounds.min.y)); 9642 context.closePath(); 9643 context.stroke(); 9644 context.fill(); 9645 context.translate(-0.5, -0.5); 9646 } 9647 9648 if (options.hasBounds) 9649 context.setTransform(1, 0, 0, 1, 0, 0); 9650 }; 9651 9652 /** 9653 * Description 9654 * @method _createCanvas 9655 * @private 9656 * @param {} width 9657 * @param {} height 9658 * @return canvas 9659 */ 9660 var _createCanvas = function(width, height) { 9661 var canvas = document.createElement('canvas'); 9662 canvas.width = width; 9663 canvas.height = height; 9664 canvas.oncontextmenu = function() { return false; }; 9665 canvas.onselectstart = function() { return false; }; 9666 return canvas; 9667 }; 9668 9669 /** 9670 * Gets the pixel ratio of the canvas. 9671 * @method _getPixelRatio 9672 * @private 9673 * @param {HTMLElement} canvas 9674 * @return {Number} pixel ratio 9675 */ 9676 var _getPixelRatio = function(canvas) { 9677 var context = canvas.getContext('2d'), 9678 devicePixelRatio = window.devicePixelRatio || 1, 9679 backingStorePixelRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio 9680 || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio 9681 || context.backingStorePixelRatio || 1; 9682 9683 return devicePixelRatio / backingStorePixelRatio; 9684 }; 9685 9686 /** 9687 * Gets the requested texture (an Image) via its path 9688 * @method _getTexture 9689 * @private 9690 * @param {render} render 9691 * @param {string} imagePath 9692 * @return {Image} texture 9693 */ 9694 var _getTexture = function(render, imagePath) { 9695 var image = render.textures[imagePath]; 9696 9697 if (image) 9698 return image; 9699 9700 image = render.textures[imagePath] = new Image(); 9701 image.src = imagePath; 9702 9703 return image; 9704 }; 9705 9706 /** 9707 * Applies the background to the canvas using CSS.
9708 * @method applyBackground 9709 * @private 9710 * @param {render} render 9711 * @param {string} background 9712 */ 9713 var _applyBackground = function(render, background) { 9714 var cssBackground = background; 9715 9716 if (/(jpg|gif|png)$/.test(background)) 9717 cssBackground = 'url(' + background + ')'; 9718 9719 render.canvas.style.background = cssBackground; 9720 render.canvas.style.backgroundSize = "contain"; 9721 render.currentBackground = background; 9722 }; 9723 9724 /* 9725 * 9726 * Events Documentation 9727 * 9728 */ 9729 9730 /** 9731 * Fired before rendering 9732 * 9733 * @event beforeRender 9734 * @param {} event An event object 9735 * @param {number} event.timestamp The engine.timing.timestamp of the event 9736 * @param {} event.source The source object of the event 9737 * @param {} event.name The name of the event 9738 */ 9739 9740 /** 9741 * Fired after rendering 9742 * 9743 * @event afterRender 9744 * @param {} event An event object 9745 * @param {number} event.timestamp The engine.timing.timestamp of the event 9746 * @param {} event.source The source object of the event 9747 * @param {} event.name The name of the event 9748 */ 9749 9750 /* 9751 * 9752 * Properties Documentation 9753 * 9754 */ 9755 9756 /** 9757 * A back-reference to the `Matter.Render` module. 9758 * 9759 * @property controller 9760 * @type render 9761 */ 9762 9763 /** 9764 * A reference to the `Matter.Engine` instance to be used. 9765 * 9766 * @property engine 9767 * @type engine 9768 */ 9769 9770 /** 9771 * A reference to the element where the canvas is to be inserted (if `render.canvas` has not been specified) 9772 * 9773 * @property element 9774 * @type HTMLElement 9775 * @default null 9776 */ 9777 9778 /** 9779 * The canvas element to render to. If not specified, one will be created if `render.element` has been specified. 9780 * 9781 * @property canvas 9782 * @type HTMLCanvasElement 9783 * @default null 9784 */ 9785 9786 /** 9787 * The configuration options of the renderer. 9788 * 9789 * @property options 9790 * @type {} 9791 */ 9792 9793 /** 9794 * The target width in pixels of the `render.canvas` to be created. 9795 * 9796 * @property options.width 9797 * @type number 9798 * @default 800 9799 */ 9800 9801 /** 9802 * The target height in pixels of the `render.canvas` to be created. 9803 * 9804 * @property options.height 9805 * @type number 9806 * @default 600 9807 */ 9808 9809 /** 9810 * A flag that specifies if `render.bounds` should be used when rendering. 9811 * 9812 * @property options.hasBounds 9813 * @type boolean 9814 * @default false 9815 */ 9816 9817 /** 9818 * A `Bounds` object that specifies the drawing view region. 9819 * Rendering will be automatically transformed and scaled to fit within the canvas size (`render.options.width` and `render.options.height`). 9820 * This allows for creating views that can pan or zoom around the scene. 9821 * You must also set `render.options.hasBounds` to `true` to enable bounded rendering. 9822 * 9823 * @property bounds 9824 * @type bounds 9825 */ 9826 9827 /** 9828 * The 2d rendering context from the `render.canvas` element. 9829 * 9830 * @property context 9831 * @type CanvasRenderingContext2D 9832 */ 9833 9834 /** 9835 * The sprite texture cache. 9836 * 9837 * @property textures 9838 * @type {} 9839 */ 9840 9841})(); 9842 9843},{"../body/Composite":2,"../collision/Grid":6,"../core/Common":14,"../core/Events":16,"../core/Mouse":19,"../geometry/Bounds":26,"../geometry/Vector":28}],32:[function(_dereq_,module,exports){ 9844/** 9845* The `Matter.RenderPixi` module is an example renderer using pixi.js. 9846* See also `Matter.Render` for a canvas based renderer. 9847* 9848* @class RenderPixi 9849* @deprecated the Matter.RenderPixi module will soon be removed from the Matter.js core. 9850* It will likely be moved to its own repository (but maintenance will be limited). 9851*/ 9852 9853var RenderPixi = {}; 9854 9855module.exports = RenderPixi; 9856 9857var Bounds = _dereq_('../geometry/Bounds'); 9858var Composite = _dereq_('../body/Composite'); 9859var Common = _dereq_('../core/Common'); 9860var Events = _dereq_('../core/Events'); 9861var Vector = _dereq_('../geometry/Vector'); 9862 9863(function() { 9864 9865 var _requestAnimationFrame, 9866 _cancelAnimationFrame; 9867 9868 if (typeof window !== 'undefined') { 9869 _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame 9870 || window.mozRequestAnimationFrame || window.msRequestAnimationFrame 9871 || function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); }; 9872 9873 _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame 9874 || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; 9875 } 9876 9877 /** 9878 * Creates a new Pixi.js WebGL renderer 9879 * @method create 9880 * @param {object} options 9881 * @return {RenderPixi} A new renderer 9882 * @deprecated 9883 */ 9884 RenderPixi.create = function(options) { 9885 Common.warn('RenderPixi.create: Matter.RenderPixi is deprecated (see docs)'); 9886 9887 var defaults = { 9888 controller: RenderPixi, 9889 engine: null, 9890 element: null, 9891 frameRequestId: null, 9892 canvas: null, 9893 renderer: null, 9894 container: null, 9895 spriteContainer: null, 9896 pixiOptions: null, 9897 options: { 9898 width: 800, 9899 height: 600, 9900 background: '#fafafa',
9901 wireframeBackground: '#222', 9902 hasBounds: false, 9903 enabled: true, 9904 wireframes: true, 9905 showSleeping: true, 9906 showDebug: false, 9907 showBroadphase: false, 9908 showBounds: false, 9909 showVelocity: false, 9910 showCollisions: false, 9911 showAxes: false, 9912 showPositions: false, 9913 showAngleIndicator: false, 9914 showIds: false, 9915 showShadows: false 9916 } 9917 }; 9918 9919 var render = Common.extend(defaults, options), 9920 transparent = !render.options.wireframes && render.options.background === 'transparent'; 9921 9922 // init pixi 9923 render.pixiOptions = render.pixiOptions || { 9924 view: render.canvas, 9925 transparent: transparent, 9926 antialias: true, 9927 backgroundColor: options.background 9928 }; 9929 9930 render.mouse = options.mouse; 9931 render.engine = options.engine; 9932 render.renderer = render.renderer || new PIXI.WebGLRenderer(render.options.width, render.options.height, render.pixiOptions); 9933 render.container = render.container || new PIXI.Container(); 9934 render.spriteContainer = render.spriteContainer || new PIXI.Container(); 9935 render.canvas = render.canvas || render.renderer.view; 9936 render.bounds = render.bounds || { 9937 min: { 9938 x: 0, 9939 y: 0 9940 }, 9941 max: { 9942 x: render.options.width, 9943 y: render.options.height 9944 } 9945 }; 9946 9947 // event listeners 9948 Events.on(render.engine, 'beforeUpdate', function() { 9949 RenderPixi.clear(render); 9950 }); 9951 9952 // caches 9953 render.textures = {}; 9954 render.sprites = {}; 9955 render.primitives = {}; 9956 9957 // use a sprite batch for performance 9958 render.container.addChild(render.spriteContainer); 9959 9960 // insert canvas 9961 if (Common.isElement(render.element)) { 9962 render.element.appendChild(render.canvas); 9963 } else { 9964 Common.warn('No "render.element" passed, "render.canvas" was not inserted into document.'); 9965 } 9966 9967 // prevent menus on canvas 9968 render.canvas.oncontextmenu = function() { return false; }; 9969 render.canvas.onselectstart = function() { return false; }; 9970 9971 return render; 9972 }; 9973 9974 /** 9975 * Continuously updates the render canvas on the `requestAnimationFrame` event. 9976 * @method run 9977 * @param {render} render 9978 * @deprecated 9979 */ 9980 RenderPixi.run = function(render) { 9981 (function loop(time){ 9982 render.frameRequestId = _requestAnimationFrame(loop); 9983 RenderPixi.world(render); 9984 })(); 9985 }; 9986 9987 /** 9988 * Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop. 9989 * @method stop 9990 * @param {render} render 9991 * @deprecated 9992 */ 9993 RenderPixi.stop = function(render) { 9994 _cancelAnimationFrame(render.frameRequestId); 9995 }; 9996 9997 /** 9998 * Clears the scene graph 9999 * @method clear 10000 * @param {RenderPixi} render 10001 * @deprecated 10002 */ 10003 RenderPixi.clear = function(render) { 10004 var container = render.container, 10005 spriteContainer = render.spriteContainer; 10006 10007 // clear stage container 10008 while (container.children[0]) { 10009 container.removeChild(container.children[0]); 10010 } 10011 10012 // clear sprite batch 10013 while (spriteContainer.children[0]) { 10014 spriteContainer.removeChild(spriteContainer.children[0]); 10015 } 10016 10017 var bgSprite = render.sprites['bg-0']; 10018 10019 // clear caches 10020 render.textures = {}; 10021 render.sprites = {}; 10022 render.primitives = {}; 10023 10024 // set background sprite 10025 render.sprites['bg-0'] = bgSprite; 10026 if (bgSprite) 10027 container.addChildAt(bgSprite, 0); 10028 10029 // add sprite batch back into container 10030 render.container.addChild(render.spriteContainer); 10031 10032 // reset background state
10033 render.currentBackground = null; 10034 10035 // reset bounds transforms 10036 container.scale.set(1, 1); 10037 container.position.set(0, 0); 10038 }; 10039 10040 /** 10041 * Sets the background of the canvas 10042 * @method setBackground 10043 * @param {RenderPixi} render 10044 * @param {string} background 10045 * @deprecated 10046 */ 10047 RenderPixi.setBackground = function(render, background) { 10048 if (render.currentBackground !== background) { 10049 var isColor = background.indexOf && background.indexOf('#') !== -1, 10050 bgSprite = render.sprites['bg-0']; 10051 10052 if (isColor) { 10053 // if solid background color 10054 var color = Common.colorToNumber(background); 10055 render.renderer.backgroundColor = color; 10056 10057 // remove background sprite if existing 10058 if (bgSprite) 10059 render.container.removeChild(bgSprite); 10060 } else { 10061 // initialise background sprite if needed 10062 if (!bgSprite) { 10063 var texture = _getTexture(render, background); 10064 10065 bgSprite = render.sprites['bg-0'] = new PIXI.Sprite(texture); 10066 bgSprite.position.x = 0; 10067 bgSprite.position.y = 0; 10068 render.container.addChildAt(bgSprite, 0); 10069 } 10070 } 10071 10072 render.currentBackground = background; 10073 } 10074 }; 10075 10076 /** 10077 * Description 10078 * @method world 10079 * @param {engine} engine 10080 * @deprecated 10081 */ 10082 RenderPixi.world = function(render) { 10083 var engine = render.engine, 10084 world = engine.world, 10085 renderer = render.renderer, 10086 container = render.container, 10087 options = render.options, 10088 bodies = Composite.allBodies(world), 10089 allConstraints = Composite.allConstraints(world), 10090 constraints = [], 10091 i; 10092 10093 if (options.wireframes) { 10094 RenderPixi.setBackground(render, options.wireframeBackground); 10095 } else { 10096 RenderPixi.setBackground(render, options.background); 10097 } 10098 10099 // handle bounds 10100 var boundsWidth = render.bounds.max.x - render.bounds.min.x, 10101 boundsHeight = render.bounds.max.y - render.bounds.min.y, 10102 boundsScaleX = boundsWidth / render.options.width, 10103 boundsScaleY = boundsHeight / render.options.height; 10104 10105 if (options.hasBounds) { 10106 // Hide bodies that are not in view 10107 for (i = 0; i < bodies.length; i++) { 10108 var body = bodies[i]; 10109 body.render.sprite.visible = Bounds.overlaps(body.bounds, render.bounds); 10110 } 10111 10112 // filter out constraints that are not in view 10113 for (i = 0; i < allConstraints.length; i++) { 10114 var constraint = allConstraints[i], 10115 bodyA = constraint.bodyA, 10116 bodyB = constraint.bodyB, 10117 pointAWorld = constraint.pointA, 10118 pointBWorld = constraint.pointB; 10119 10120 if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA); 10121 if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB); 10122 10123 if (!pointAWorld || !pointBWorld) 10124 continue; 10125 10126 if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld)) 10127 constraints.push(constraint); 10128 } 10129 10130 // transform the view 10131 container.scale.set(1 / boundsScaleX, 1 / boundsScaleY); 10132 container.position.set(-render.bounds.min.x * (1 / boundsScaleX), -render.bounds.min.y * (1 / boundsScaleY)); 10133 } else { 10134 constraints = allConstraints; 10135 } 10136 10137 for (i = 0; i < bodies.length; i++) 10138 RenderPixi.body(render, bodies[i]); 10139 10140 for (i = 0; i < constraints.length; i++) 10141 RenderPixi.constraint(render, constraints[i]); 10142 10143 renderer.render(container); 10144 }; 10145 10146 10147 /** 10148 * Description 10149 * @method constraint 10150 * @param {engine} engine 10151 * @param {constraint} constraint 10152 * @deprecated 10153 */ 10154 RenderPixi.constraint = function(render, constraint) { 10155 var engine = render.engine, 10156 bodyA = constraint.bodyA, 10157 bodyB = constraint.bodyB, 10158 pointA = constraint.pointA, 10159 pointB = constraint.pointB, 10160 container = render.container, 10161 constraintRender = constraint.render, 10162 primitiveId = 'c-' + constraint.id, 10163 primitive = render.primitives[primitiveId]; 10164 10165 // initialise constraint primitive if not existing 10166 if (!primitive) 10167 primitive = render.primitives[primitiveId] = new PIXI.Graphics(); 10168 10169 // don't render if constraint does not have two end points 10170 if (!constraintRender.visible || !constraint.pointA || !constraint.pointB) { 10171 primitive.clear(); 10172 return; 10173 } 10174 10175 // add to scene graph if not already there 10176 if (Common.indexOf(container.children, primitive) === -1) 10177 container.addChild(primitive); 10178 10179 // render the constraint on every update, since they can change dynamically 10180 primitive.clear(); 10181 primitive.beginFill(0, 0); 10182 primitive.lineStyle(constraintRender.lineWidth, Common.colorToNumber(constraintRender.strokeStyle), 1); 10183 10184 if (bodyA) { 10185 primitive.moveTo(bodyA.position.x + pointA.x, bodyA.position.y + pointA.y); 10186 } else { 10187 primitive.moveTo(pointA.x, pointA.y); 10188 } 10189 10190 if (bodyB) { 10191 primitive.lineTo(bodyB.position.x + pointB.x, bodyB.position.y + pointB.y); 10192 } else { 10193 primitive.lineTo(pointB.x, pointB.y); 10194 } 10195 10196 primitive.endFill(); 10197 }; 10198 10199 /** 10200 * Description 10201 * @method body 10202 * @param {engine} engine 10203 * @param {body} body 10204 * @deprecated 10205 */ 10206 RenderPixi.body = function(render, body) { 10207 var engine = render.engine, 10208 bodyRender = body.render; 10209 10210 if (!bodyRender.visible) 10211 return; 10212 10213 if (bodyRender.sprite && bodyRender.sprite.texture) { 10214 var spriteId = 'b-' + body.id, 10215 sprite = render.sprites[spriteId], 10216 spriteContainer = render.spriteContainer; 10217 10218 // initialise body sprite if not existing 10219 if (!sprite) 10220 sprite = render.sprites[spriteId] = _createBodySprite(render, body); 10221 10222 // add to scene graph if not already there 10223 if (Common.indexOf(spriteContainer.children, sprite) === -1) 10224 spriteContainer.addChild(sprite); 10225 10226 // update body sprite 10227 sprite.position.x = body.position.x; 10228 sprite.position.y = body.position.y; 10229 sprite.rotation = body.angle; 10230 sprite.scale.x = bodyRender.sprite.xScale || 1; 10231 sprite.scale.y = bodyRender.sprite.yScale || 1; 10232 } else { 10233 var primitiveId = 'b-' + body.id, 10234 primitive = render.primitives[primitiveId], 10235 container = render.container; 10236 10237 // initialise body primitive if not existing 10238 if (!primitive) { 10239 primitive = render.primitives[primitiveId] = _createBodyPrimitive(render, body); 10240 primitive.initialAngle = body.angle; 10241 } 10242 10243 // add to scene graph if not already there 10244 if (Common.indexOf(container.children, primitive) === -1) 10245 container.addChild(primitive); 10246 10247 // update body primitive 10248 primitive.position.x = body.position.x; 10249 primitive.position.y = body.position.y; 10250 primitive.rotation = body.angle - primitive.initialAngle; 10251 } 10252 }; 10253 10254 /** 10255 * Creates a body sprite
10256 * @method _createBodySprite 10257 * @private 10258 * @param {RenderPixi} render 10259 * @param {body} body 10260 * @return {PIXI.Sprite} sprite 10261 * @deprecated 10262 */ 10263 var _createBodySprite = function(render, body) { 10264 var bodyRender = body.render, 10265 texturePath = bodyRender.sprite.texture, 10266 texture = _getTexture(render, texturePath), 10267 sprite = new PIXI.Sprite(texture); 10268 10269 sprite.anchor.x = body.render.sprite.xOffset; 10270 sprite.anchor.y = body.render.sprite.yOffset; 10271 10272 return sprite; 10273 }; 10274 10275 /** 10276 * Creates a body primitive 10277 * @method _createBodyPrimitive 10278 * @private 10279 * @param {RenderPixi} render 10280 * @param {body} body 10281 * @return {PIXI.Graphics} graphics 10282 * @deprecated 10283 */ 10284 var _createBodyPrimitive = function(render, body) { 10285 var bodyRender = body.render, 10286 options = render.options, 10287 primitive = new PIXI.Graphics(), 10288 fillStyle = Common.colorToNumber(bodyRender.fillStyle), 10289 strokeStyle = Common.colorToNumber(bodyRender.strokeStyle), 10290 strokeStyleIndicator = Common.colorToNumber(bodyRender.strokeStyle), 10291 strokeStyleWireframe = Common.colorToNumber('#bbb'), 10292 strokeStyleWireframeIndicator = Common.colorToNumber('#CD5C5C'), 10293 part; 10294 10295 primitive.clear(); 10296 10297 // handle compound parts 10298 for (var k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) { 10299 part = body.parts[k]; 10300 10301 if (!options.wireframes) { 10302 primitive.beginFill(fillStyle, 1); 10303 primitive.lineStyle(bodyRender.lineWidth, strokeStyle, 1); 10304 } else { 10305 primitive.beginFill(0, 0); 10306 primitive.lineStyle(1, strokeStyleWireframe, 1); 10307 } 10308 10309 primitive.moveTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y); 10310 10311 for (var j = 1; j < part.vertices.length; j++) { 10312 primitive.lineTo(part.vertices[j].x - body.position.x, part.vertices[j].y - body.position.y); 10313 } 10314 10315 primitive.lineTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y); 10316 10317 primitive.endFill(); 10318 10319 // angle indicator 10320 if (options.showAngleIndicator || options.showAxes) { 10321 primitive.beginFill(0, 0); 10322 10323 if (options.wireframes) { 10324 primitive.lineStyle(1, strokeStyleWireframeIndicator, 1); 10325 } else { 10326 primitive.lineStyle(1, strokeStyleIndicator); 10327 } 10328 10329 primitive.moveTo(part.position.x - body.position.x, part.position.y - body.position.y); 10330 primitive.lineTo(((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2 - body.position.x), 10331 ((part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2 - body.position.y)); 10332 10333 primitive.endFill(); 10334 } 10335 } 10336 10337 return primitive; 10338 }; 10339 10340 /** 10341 * Gets the requested texture (a PIXI.Texture) via its path 10342 * @method _getTexture 10343 * @private 10344 * @param {RenderPixi} render 10345 * @param {string} imagePath 10346 * @return {PIXI.Texture} texture 10347 * @deprecated 10348 */ 10349 var _getTexture = function(render, imagePath) { 10350 var texture = render.textures[imagePath]; 10351 10352 if (!texture) 10353 texture = render.textures[imagePath] = PIXI.Texture.fromImage(imagePath); 10354 10355 return texture; 10356 }; 10357 10358})(); 10359 10360},{"../body/Composite":2,"../core/Common":14,"../core/Events":16,"../geometry/Bounds":26,"../geometry/Vector":28}]},{},[30])(30) 10361});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.