2014-02-19 09:15:05 -05:00
/ * *
2016-04-07 15:03:37 -04:00
* matter - js 0.9 . 2 by @ liabru 2016 - 04 - 07
2014-02-19 09:15:05 -05:00
* http : //brm.io/matter-js/
2015-12-05 11:47:50 -05:00
* License MIT
2014-02-19 09:15:05 -05:00
* /
/ * *
* The MIT License ( MIT )
*
* Copyright ( c ) 2014 Liam Brummitt
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the "Software" ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
* /
2015-08-17 18:50:03 -04:00
( 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 e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports : { } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ? n : e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Body ` module contains methods for creating and manipulating body models .
* A ` Matter.Body ` is a rigid body that can be simulated by a ` Matter.Engine ` .
* Factories for commonly used body configurations ( such as rectangles , circles and other polygons ) can be found in the module ` Matter.Bodies ` .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-06-09 14:40:24 -04:00
2014-02-28 20:10:08 -05:00
* @ class Body
* /
2014-02-19 09:15:05 -05:00
var Body = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Body ;
var Vertices = require ( '../geometry/Vertices' ) ;
var Vector = require ( '../geometry/Vector' ) ;
var Sleeping = require ( '../core/Sleeping' ) ;
var Render = require ( '../render/Render' ) ;
var Common = require ( '../core/Common' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
var Axes = require ( '../geometry/Axes' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-06-09 14:40:24 -04:00
Body . _inertiaScale = 4 ;
2016-01-16 17:43:32 -05:00
Body . _nextCollidingGroupId = 1 ;
Body . _nextNonCollidingGroupId = - 1 ;
Body . _nextCategory = 0x0001 ;
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new rigid body model . The options parameter is an object that specifies any properties you wish to override the defaults .
* All properties have default values , and many are pre - calculated automatically based on other properties .
2015-06-29 15:58:24 -04:00
* See the properties section below for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method create
* @ param { } options
* @ return { body } body
* /
2014-02-19 09:15:05 -05:00
Body . create = function ( options ) {
var defaults = {
2014-05-01 09:09:06 -04:00
id : Common . nextId ( ) ,
2014-03-30 14:45:30 -04:00
type : 'body' ,
2014-05-01 09:09:06 -04:00
label : 'Body' ,
2015-05-20 15:38:41 -04:00
parts : [ ] ,
2014-02-19 09:15:05 -05:00
angle : 0 ,
2014-05-05 14:32:51 -04:00
vertices : Vertices . fromPath ( 'L 0 0 L 40 0 L 40 40 L 0 40' ) ,
2014-02-19 09:15:05 -05:00
position : { x : 0 , y : 0 } ,
force : { x : 0 , y : 0 } ,
torque : 0 ,
positionImpulse : { x : 0 , y : 0 } ,
2014-03-30 14:45:30 -04:00
constraintImpulse : { x : 0 , y : 0 , angle : 0 } ,
2015-05-20 15:38:41 -04:00
totalContacts : 0 ,
2014-02-19 09:15:05 -05:00
speed : 0 ,
angularSpeed : 0 ,
velocity : { x : 0 , y : 0 } ,
angularVelocity : 0 ,
2016-04-07 15:03:37 -04:00
isSensor : false ,
2014-02-19 09:15:05 -05:00
isStatic : false ,
isSleeping : false ,
motion : 0 ,
sleepThreshold : 60 ,
density : 0.001 ,
restitution : 0 ,
friction : 0.1 ,
2015-05-20 15:38:41 -04:00
frictionStatic : 0.5 ,
2014-02-19 09:15:05 -05:00
frictionAir : 0.01 ,
2014-07-29 11:26:49 -04:00
collisionFilter : {
category : 0x0001 ,
mask : 0xFFFFFFFF ,
group : 0
} ,
2014-03-22 13:51:49 -04:00
slop : 0.05 ,
2014-05-01 09:09:06 -04:00
timeScale : 1 ,
2014-03-22 13:51:49 -04:00
render : {
visible : true ,
2016-02-07 10:53:07 -05:00
opacity : 1 ,
2014-03-30 14:45:30 -04:00
sprite : {
xScale : 1 ,
2015-12-23 08:08:54 -05:00
yScale : 1 ,
xOffset : 0 ,
yOffset : 0
2014-03-30 14:45:30 -04:00
} ,
2014-03-22 13:51:49 -04:00
lineWidth : 1.5
}
2014-02-19 09:15:05 -05:00
} ;
var body = Common . extend ( defaults , options ) ;
2014-06-09 14:40:24 -04:00
_initProperties ( body , options ) ;
2014-02-19 09:15:05 -05:00
return body ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-07-29 11:26:49 -04:00
* Returns the next unique group index for which bodies will collide .
* If ` isNonColliding ` is ` true ` , returns the next unique group index for which bodies will _not _ collide .
* See ` body.collisionFilter ` for more information .
* @ method nextGroup
* @ param { bool } [ isNonColliding = false ]
* @ return { Number } Unique group index
2014-02-28 20:10:08 -05:00
* /
2014-07-29 11:26:49 -04:00
Body . nextGroup = function ( isNonColliding ) {
if ( isNonColliding )
2016-01-16 17:43:32 -05:00
return Body . _nextNonCollidingGroupId -- ;
2014-07-29 11:26:49 -04:00
2016-01-16 17:43:32 -05:00
return Body . _nextCollidingGroupId ++ ;
2014-02-19 09:15:05 -05:00
} ;
2015-01-01 18:10:10 -05:00
/ * *
* Returns the next unique category bitfield ( starting after the initial default category ` 0x0001 ` ) .
* There are 32 available . See ` body.collisionFilter ` for more information .
* @ method nextCategory
* @ return { Number } Unique category bitfield
* /
Body . nextCategory = function ( ) {
2016-01-16 17:43:32 -05:00
Body . _nextCategory = Body . _nextCategory << 1 ;
return Body . _nextCategory ;
2015-01-01 18:10:10 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Initialises body properties .
2014-05-01 09:09:06 -04:00
* @ method _initProperties
* @ private
2014-02-28 20:10:08 -05:00
* @ param { body } body
2014-06-09 14:40:24 -04:00
* @ param { } options
2014-02-28 20:10:08 -05:00
* /
2014-06-09 14:40:24 -04:00
var _initProperties = function ( body , options ) {
2015-05-20 15:38:41 -04:00
// init required properties (order is important)
2014-12-28 13:37:43 -05:00
Body . set ( body , {
bounds : body . bounds || Bounds . create ( body . vertices ) ,
positionPrev : body . positionPrev || Vector . clone ( body . position ) ,
anglePrev : body . anglePrev || body . angle ,
vertices : body . vertices ,
2015-05-20 15:38:41 -04:00
parts : body . parts || [ body ] ,
2014-12-28 13:37:43 -05:00
isStatic : body . isStatic ,
2015-05-20 15:38:41 -04:00
isSleeping : body . isSleeping ,
parent : body . parent || body
2014-12-28 13:37:43 -05:00
} ) ;
2014-02-19 09:15:05 -05:00
Vertices . rotate ( body . vertices , body . angle , body . position ) ;
Axes . rotate ( body . axes , body . angle ) ;
2014-07-29 11:26:49 -04:00
Bounds . update ( body . bounds , body . vertices , body . velocity ) ;
2014-02-19 09:15:05 -05:00
2014-06-09 14:40:24 -04:00
// allow options to override the automatically calculated properties
2014-12-28 13:37:43 -05:00
Body . set ( body , {
axes : options . axes || body . axes ,
area : options . area || body . area ,
mass : options . mass || body . mass ,
inertia : options . inertia || body . inertia
} ) ;
2014-06-09 14:40:24 -04:00
// render properties
var defaultFillStyle = ( body . isStatic ? '#eeeeee' : Common . choose ( [ '#556270' , '#4ECDC4' , '#C7F464' , '#FF6B6B' , '#C44D58' ] ) ) ,
defaultStrokeStyle = Common . shadeColor ( defaultFillStyle , - 20 ) ;
body . render . fillStyle = body . render . fillStyle || defaultFillStyle ;
body . render . strokeStyle = body . render . strokeStyle || defaultStrokeStyle ;
2015-12-23 08:08:54 -05:00
body . render . sprite . xOffset += - ( body . bounds . min . x - body . position . x ) / ( body . bounds . max . x - body . bounds . min . x ) ;
body . render . sprite . yOffset += - ( body . bounds . min . y - body . position . y ) / ( body . bounds . max . y - body . bounds . min . y ) ;
2014-05-01 09:09:06 -04:00
} ;
2014-12-28 13:37:43 -05:00
/ * *
* Given a property and a value ( or map of ) , sets the property ( s ) on the body , using the appropriate setter functions if they exist .
* Prefer to use the actual setter functions in performance critical situations .
* @ method set
* @ param { body } body
* @ param { } settings A property name ( or map of properties and values ) to set on the body .
* @ param { } value The value to set if ` settings ` is a single property name .
* /
Body . set = function ( body , settings , value ) {
var property ;
if ( typeof settings === 'string' ) {
property = settings ;
settings = { } ;
settings [ property ] = value ;
}
for ( property in settings ) {
value = settings [ property ] ;
if ( ! settings . hasOwnProperty ( property ) )
continue ;
switch ( property ) {
case 'isStatic' :
Body . setStatic ( body , value ) ;
break ;
case 'isSleeping' :
Sleeping . set ( body , value ) ;
break ;
case 'mass' :
Body . setMass ( body , value ) ;
break ;
case 'density' :
Body . setDensity ( body , value ) ;
break ;
case 'inertia' :
Body . setInertia ( body , value ) ;
break ;
case 'vertices' :
Body . setVertices ( body , value ) ;
break ;
case 'position' :
Body . setPosition ( body , value ) ;
break ;
case 'angle' :
Body . setAngle ( body , value ) ;
break ;
case 'velocity' :
Body . setVelocity ( body , value ) ;
break ;
case 'angularVelocity' :
Body . setAngularVelocity ( body , value ) ;
break ;
2015-05-20 15:38:41 -04:00
case 'parts' :
Body . setParts ( body , value ) ;
break ;
2014-12-28 13:37:43 -05:00
default :
body [ property ] = value ;
}
}
} ;
2014-05-01 09:09:06 -04:00
/ * *
2014-06-09 14:40:24 -04:00
* Sets the body as static , including isStatic flag and setting mass and inertia to Infinity .
2014-05-01 09:09:06 -04:00
* @ method setStatic
2014-06-09 14:40:24 -04:00
* @ param { body } body
2014-05-01 09:09:06 -04:00
* @ param { bool } isStatic
* /
Body . setStatic = function ( body , isStatic ) {
2015-05-20 15:38:41 -04:00
for ( var i = 0 ; i < body . parts . length ; i ++ ) {
var part = body . parts [ i ] ;
part . isStatic = isStatic ;
if ( isStatic ) {
part . restitution = 0 ;
part . friction = 1 ;
part . mass = part . inertia = part . density = Infinity ;
part . inverseMass = part . inverseInertia = 0 ;
part . positionPrev . x = part . position . x ;
part . positionPrev . y = part . position . y ;
part . anglePrev = part . angle ;
part . angularVelocity = 0 ;
part . speed = 0 ;
part . angularSpeed = 0 ;
part . motion = 0 ;
}
2014-05-01 09:09:06 -04:00
}
2014-02-19 09:15:05 -05:00
} ;
2014-07-29 11:26:49 -04:00
/ * *
* Sets the mass of the body . Inverse mass and density are automatically updated to reflect the change .
* @ method setMass
* @ param { body } body
* @ param { number } mass
* /
Body . setMass = function ( body , mass ) {
body . mass = mass ;
body . inverseMass = 1 / body . mass ;
body . density = body . mass / body . area ;
} ;
/ * *
* Sets the density of the body . Mass is automatically updated to reflect the change .
* @ method setDensity
* @ param { body } body
* @ param { number } density
* /
Body . setDensity = function ( body , density ) {
Body . setMass ( body , density * body . area ) ;
body . density = density ;
} ;
/ * *
* Sets the moment of inertia ( i . e . second moment of area ) of the body of the body .
* Inverse inertia is automatically updated to reflect the change . Mass is not changed .
* @ method setInertia
* @ param { body } body
* @ param { number } inertia
* /
Body . setInertia = function ( body , inertia ) {
body . inertia = inertia ;
body . inverseInertia = 1 / body . inertia ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Sets the body ' s vertices and updates body properties accordingly , including inertia , area and mass ( with respect to ` body.density ` ) .
* Vertices will be automatically transformed to be orientated around their centre of mass as the origin .
* They are then automatically translated to world space based on ` body.position ` .
*
* The ` vertices ` argument should be passed as an array of ` Matter.Vector ` points ( or a ` Matter.Vertices ` array ) .
* Vertices must form a convex hull , concave hulls are not supported .
*
* @ method setVertices
* @ param { body } body
* @ param { vector [ ] } vertices
* /
Body . setVertices = function ( body , vertices ) {
// change vertices
if ( vertices [ 0 ] . body === body ) {
body . vertices = vertices ;
} else {
body . vertices = Vertices . create ( vertices , body ) ;
}
// update properties
body . axes = Axes . fromVertices ( body . vertices ) ;
body . area = Vertices . area ( body . vertices ) ;
2014-07-29 11:26:49 -04:00
Body . setMass ( body , body . density * body . area ) ;
2014-06-09 14:40:24 -04:00
// orient vertices around the centre of mass at origin (0, 0)
var centre = Vertices . centre ( body . vertices ) ;
Vertices . translate ( body . vertices , centre , - 1 ) ;
// update inertia while vertices are at origin (0, 0)
2014-07-29 11:26:49 -04:00
Body . setInertia ( body , Body . _inertiaScale * Vertices . inertia ( body . vertices , body . mass ) ) ;
2014-06-09 14:40:24 -04:00
// update geometry
Vertices . translate ( body . vertices , body . position ) ;
Bounds . update ( body . bounds , body . vertices , body . velocity ) ;
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Sets the parts of the ` body ` and updates mass , inertia and centroid .
* Each part will have its parent set to ` body ` .
* By default the convex hull will be automatically computed and set on ` body ` , unless ` autoHull ` is set to ` false. `
* Note that this method will ensure that the first part in ` body.parts ` will always be the ` body ` .
* @ method setParts
* @ param { body } body
* @ param [ body ] parts
* @ param { bool } [ autoHull = true ]
* /
Body . setParts = function ( body , parts , autoHull ) {
var i ;
// add all the parts, ensuring that the first part is always the parent body
parts = parts . slice ( 0 ) ;
body . parts . length = 0 ;
body . parts . push ( body ) ;
body . parent = body ;
for ( i = 0 ; i < parts . length ; i ++ ) {
var part = parts [ i ] ;
if ( part !== body ) {
part . parent = body ;
body . parts . push ( part ) ;
}
}
if ( body . parts . length === 1 )
return ;
autoHull = typeof autoHull !== 'undefined' ? autoHull : true ;
// find the convex hull of all parts to set on the parent body
if ( autoHull ) {
var vertices = [ ] ;
for ( i = 0 ; i < parts . length ; i ++ ) {
vertices = vertices . concat ( parts [ i ] . vertices ) ;
}
Vertices . clockwiseSort ( vertices ) ;
var hull = Vertices . hull ( vertices ) ,
hullCentre = Vertices . centre ( hull ) ;
Body . setVertices ( body , hull ) ;
Vertices . translate ( body . vertices , hullCentre ) ;
}
// sum the properties of all compound parts of the parent body
var total = _totalProperties ( body ) ;
body . area = total . area ;
body . parent = body ;
body . position . x = total . centre . x ;
body . position . y = total . centre . y ;
body . positionPrev . x = total . centre . x ;
body . positionPrev . y = total . centre . y ;
Body . setMass ( body , total . mass ) ;
Body . setInertia ( body , total . inertia ) ;
Body . setPosition ( body , total . centre ) ;
} ;
2014-06-09 14:40:24 -04:00
/ * *
* Sets the position of the body instantly . Velocity , angle , force etc . are unchanged .
* @ method setPosition
* @ param { body } body
* @ param { vector } position
* /
Body . setPosition = function ( body , position ) {
var delta = Vector . sub ( position , body . position ) ;
body . positionPrev . x += delta . x ;
body . positionPrev . y += delta . y ;
2015-05-20 15:38:41 -04:00
for ( var i = 0 ; i < body . parts . length ; i ++ ) {
var part = body . parts [ i ] ;
part . position . x += delta . x ;
part . position . y += delta . y ;
Vertices . translate ( part . vertices , delta ) ;
Bounds . update ( part . bounds , part . vertices , body . velocity ) ;
}
2014-06-09 14:40:24 -04:00
} ;
/ * *
* Sets the angle of the body instantly . Angular velocity , position , force etc . are unchanged .
* @ method setAngle
* @ param { body } body
* @ param { number } angle
* /
Body . setAngle = function ( body , angle ) {
var delta = angle - body . angle ;
body . anglePrev += delta ;
2015-05-20 15:38:41 -04:00
for ( var i = 0 ; i < body . parts . length ; i ++ ) {
var part = body . parts [ i ] ;
part . angle += delta ;
Vertices . rotate ( part . vertices , delta , body . position ) ;
Axes . rotate ( part . axes , delta ) ;
Bounds . update ( part . bounds , part . vertices , body . velocity ) ;
if ( i > 0 ) {
Vector . rotateAbout ( part . position , delta , body . position , part . position ) ;
}
}
2014-06-09 14:40:24 -04:00
} ;
/ * *
* Sets the linear velocity of the body instantly . Position , angle , force etc . are unchanged . See also ` Body.applyForce ` .
* @ method setVelocity
* @ param { body } body
* @ param { vector } velocity
* /
Body . setVelocity = function ( body , velocity ) {
body . positionPrev . x = body . position . x - velocity . x ;
body . positionPrev . y = body . position . y - velocity . y ;
body . velocity . x = velocity . x ;
body . velocity . y = velocity . y ;
body . speed = Vector . magnitude ( body . velocity ) ;
} ;
/ * *
* Sets the angular velocity of the body instantly . Position , angle , force etc . are unchanged . See also ` Body.applyForce ` .
* @ method setAngularVelocity
* @ param { body } body
* @ param { number } velocity
* /
Body . setAngularVelocity = function ( body , velocity ) {
body . anglePrev = body . angle - velocity ;
body . angularVelocity = velocity ;
body . angularSpeed = Math . abs ( body . angularVelocity ) ;
} ;
/ * *
* Moves a body by a given vector relative to its current position , without imparting any velocity .
* @ method translate
* @ param { body } body
* @ param { vector } translation
* /
Body . translate = function ( body , translation ) {
Body . setPosition ( body , Vector . add ( body . position , translation ) ) ;
} ;
/ * *
* Rotates a body by a given angle relative to its current angle , without imparting any angular velocity .
* @ method rotate
* @ param { body } body
* @ param { number } rotation
* /
Body . rotate = function ( body , rotation ) {
2014-07-29 11:26:49 -04:00
Body . setAngle ( body , body . angle + rotation ) ;
2014-06-09 14:40:24 -04:00
} ;
/ * *
* Scales the body , including updating physical properties ( mass , area , axes , inertia ) , from a world - space point ( default is body centre ) .
* @ method scale
* @ param { body } body
* @ param { number } scaleX
* @ param { number } scaleY
* @ param { vector } [ point ]
* /
Body . scale = function ( body , scaleX , scaleY , point ) {
2015-05-20 15:38:41 -04:00
for ( var i = 0 ; i < body . parts . length ; i ++ ) {
var part = body . parts [ i ] ;
2014-06-09 14:40:24 -04:00
2015-05-20 15:38:41 -04:00
// scale vertices
Vertices . scale ( part . vertices , scaleX , scaleY , body . position ) ;
2014-06-09 14:40:24 -04:00
2015-05-20 15:38:41 -04:00
// update properties
part . axes = Axes . fromVertices ( part . vertices ) ;
2014-06-09 14:40:24 -04:00
2015-05-20 15:38:41 -04:00
if ( ! body . isStatic ) {
part . area = Vertices . area ( part . vertices ) ;
Body . setMass ( part , body . density * part . area ) ;
// update inertia (requires vertices to be at origin)
Vertices . translate ( part . vertices , { x : - part . position . x , y : - part . position . y } ) ;
Body . setInertia ( part , Vertices . inertia ( part . vertices , part . mass ) ) ;
Vertices . translate ( part . vertices , { x : part . position . x , y : part . position . y } ) ;
}
// update bounds
Bounds . update ( part . bounds , part . vertices , body . velocity ) ;
}
2016-04-07 15:03:37 -04:00
// handle circles
if ( body . circleRadius ) {
if ( scaleX === scaleY ) {
body . circleRadius *= scaleX ;
} else {
// body is no longer a circle
body . circleRadius = null ;
}
}
2015-05-20 15:38:41 -04:00
if ( ! body . isStatic ) {
var total = _totalProperties ( body ) ;
body . area = total . area ;
Body . setMass ( body , total . mass ) ;
Body . setInertia ( body , total . inertia ) ;
}
2014-06-09 14:40:24 -04:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Performs a simulation step for the given ` body ` , including updating position and angle using Verlet integration .
2014-02-28 20:10:08 -05:00
* @ method update
* @ param { body } body
* @ param { number } deltaTime
2014-05-05 14:32:51 -04:00
* @ param { number } timeScale
2014-02-28 20:10:08 -05:00
* @ param { number } correction
* /
2014-05-05 14:32:51 -04:00
Body . update = function ( body , deltaTime , timeScale , correction ) {
var deltaTimeSquared = Math . pow ( deltaTime * timeScale * body . timeScale , 2 ) ;
2014-02-19 09:15:05 -05:00
// from the previous step
2014-05-05 14:32:51 -04:00
var frictionAir = 1 - body . frictionAir * timeScale * body . timeScale ,
2014-02-19 09:15:05 -05:00
velocityPrevX = body . position . x - body . positionPrev . x ,
velocityPrevY = body . position . y - body . positionPrev . y ;
2015-06-29 15:58:24 -04:00
// update velocity with Verlet integration
2014-02-19 09:15:05 -05:00
body . velocity . x = ( velocityPrevX * frictionAir * correction ) + ( body . force . x / body . mass ) * deltaTimeSquared ;
body . velocity . y = ( velocityPrevY * frictionAir * correction ) + ( body . force . y / body . mass ) * deltaTimeSquared ;
body . positionPrev . x = body . position . x ;
body . positionPrev . y = body . position . y ;
body . position . x += body . velocity . x ;
body . position . y += body . velocity . y ;
2015-06-29 15:58:24 -04:00
// update angular velocity with Verlet integration
2014-02-19 09:15:05 -05:00
body . angularVelocity = ( ( body . angle - body . anglePrev ) * frictionAir * correction ) + ( body . torque / body . inertia ) * deltaTimeSquared ;
body . anglePrev = body . angle ;
body . angle += body . angularVelocity ;
// track speed and acceleration
body . speed = Vector . magnitude ( body . velocity ) ;
body . angularSpeed = Math . abs ( body . angularVelocity ) ;
// transform the body geometry
2015-05-20 15:38:41 -04:00
for ( var i = 0 ; i < body . parts . length ; i ++ ) {
var part = body . parts [ i ] ;
Vertices . translate ( part . vertices , body . velocity ) ;
if ( i > 0 ) {
part . position . x += body . velocity . x ;
part . position . y += body . velocity . y ;
}
if ( body . angularVelocity !== 0 ) {
Vertices . rotate ( part . vertices , body . angularVelocity , body . position ) ;
Axes . rotate ( part . axes , body . angularVelocity ) ;
if ( i > 0 ) {
Vector . rotateAbout ( part . position , body . angularVelocity , body . position , part . position ) ;
}
}
Bounds . update ( part . bounds , part . vertices , body . velocity ) ;
2014-04-01 08:47:17 -04:00
}
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Applies a force to a body from a given world - space position , including resulting torque .
2014-02-28 20:10:08 -05:00
* @ method applyForce
* @ param { body } body
* @ param { vector } position
* @ param { vector } force
* /
2014-02-19 09:15:05 -05:00
Body . applyForce = function ( body , position , force ) {
body . force . x += force . x ;
body . force . y += force . y ;
var offset = { x : position . x - body . position . x , y : position . y - body . position . y } ;
2015-12-23 08:42:22 -05:00
body . torque += offset . x * force . y - offset . y * force . x ;
2014-02-19 09:15:05 -05:00
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Returns the sums of the properties of all compound parts of the parent body .
* @ method _totalProperties
* @ private
* @ param { body } body
* @ return { }
* /
var _totalProperties = function ( body ) {
// https://ecourses.ou.edu/cgi-bin/ebook.cgi?doc=&topic=st&chap_sec=07.2&page=theory
// http://output.to/sideway/default.asp?qno=121100087
var properties = {
mass : 0 ,
area : 0 ,
inertia : 0 ,
centre : { x : 0 , y : 0 }
} ;
// sum the properties of all compound parts of the parent body
for ( var i = body . parts . length === 1 ? 0 : 1 ; i < body . parts . length ; i ++ ) {
var part = body . parts [ i ] ;
properties . mass += part . mass ;
properties . area += part . area ;
properties . inertia += part . inertia ;
properties . centre = Vector . add ( properties . centre ,
Vector . mult ( part . position , part . mass !== Infinity ? part . mass : 1 ) ) ;
}
properties . centre = Vector . div ( properties . centre ,
properties . mass !== Infinity ? properties . mass : body . parts . length ) ;
return properties ;
} ;
2015-06-29 15:58:24 -04:00
/ *
*
* Events Documentation
*
* /
/ * *
* Fired when a body starts sleeping ( where ` this ` is the body ) .
*
* @ event sleepStart
* @ this { body } The body that has started sleeping
* @ param { } event An event object
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired when a body ends sleeping ( where ` this ` is the body ) .
*
* @ event sleepEnd
* @ this { body } The body that has ended sleeping
* @ param { } event An event object
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
2014-06-09 14:40:24 -04:00
/ *
*
* Properties Documentation
*
* /
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* An integer ` Number ` uniquely identifying number generated in ` Body.create ` by ` Common.nextId ` .
*
* @ property id
* @ type number
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* A ` String ` denoting the type of object .
*
* @ property type
* @ type string
* @ default "body"
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
2014-05-01 09:09:06 -04:00
/ * *
2014-06-09 14:40:24 -04:00
* An arbitrary ` String ` name to help the user identify and manage bodies .
*
* @ property label
* @ type string
* @ default "Body"
2014-05-01 09:09:06 -04:00
* /
2015-05-20 15:38:41 -04:00
/ * *
* An array of bodies that make up this body .
* The first body in the array must always be a self reference to the current body instance .
* All bodies in the ` parts ` array together form a single rigid compound body .
* Parts are allowed to overlap , have gaps or holes or even form concave bodies .
* Parts themselves should never be added to a ` World ` , only the parent body should be .
* Use ` Body.setParts ` when setting parts to ensure correct updates of all properties .
*
* @ property parts
* @ type body [ ]
* /
/ * *
* A self reference if the body is _not _ a part of another body .
* Otherwise this is a reference to the body that this is a part of .
* See ` body.parts ` .
*
* @ property parent
* @ type body
* /
2014-06-09 14:40:24 -04:00
/ * *
* A ` Number ` specifying the angle of the body , in radians .
*
* @ property angle
* @ type number
* @ default 0
* /
2014-05-01 09:09:06 -04:00
2014-06-09 14:40:24 -04:00
/ * *
* An array of ` Vector ` objects that specify the convex hull of the rigid body .
* These should be provided about the origin ` (0, 0) ` . E . g .
*
* [ { x : 0 , y : 0 } , { x : 25 , y : 50 } , { x : 50 , y : 0 } ]
*
2015-06-29 15:58:24 -04:00
* 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 ) .
2014-06-09 14:40:24 -04:00
* The ` Vector ` objects are also augmented with additional properties required for efficient collision detection .
*
* Other properties such as ` inertia ` and ` bounds ` are automatically calculated from the passed vertices ( unless provided via ` options ` ) .
* Concave hulls are not currently supported . The module ` Matter.Vertices ` contains useful methods for working with vertices .
*
* @ property vertices
* @ type vector [ ]
* /
2014-05-01 09:09:06 -04:00
2014-06-09 14:40:24 -04:00
/ * *
* A ` Vector ` that specifies the current world - space position of the body .
*
* @ property position
* @ type vector
* @ default { x : 0 , y : 0 }
* /
/ * *
* A ` Vector ` that specifies the force to apply in the current step . It is zeroed after every ` Body.update ` . See also ` Body.applyForce ` .
*
* @ property force
* @ type vector
* @ default { x : 0 , y : 0 }
* /
/ * *
* A ` Number ` that specifies the torque ( turning force ) to apply in the current step . It is zeroed after every ` Body.update ` .
*
* @ property torque
* @ type number
* @ default 0
* /
/ * *
* 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 ` ) .
*
* @ readOnly
* @ property speed
* @ type number
* @ default 0
* /
/ * *
* 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 ` ) .
*
* @ readOnly
* @ property angularSpeed
* @ type number
* @ default 0
* /
/ * *
* A ` Vector ` that _measures _ the current velocity of the body after the last ` Body.update ` . It is read - only .
* 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 ) .
*
* @ readOnly
* @ property velocity
* @ type vector
* @ default { x : 0 , y : 0 }
* /
/ * *
* A ` Number ` that _measures _ the current angular velocity of the body after the last ` Body.update ` . It is read - only .
* 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 ) .
*
* @ readOnly
* @ property angularVelocity
* @ type number
* @ default 0
* /
/ * *
* A flag that indicates whether a body is considered static . A static body can never change position or angle and is completely fixed .
* 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 .
*
* @ property isStatic
* @ type boolean
* @ default false
* /
2016-04-07 15:03:37 -04:00
/ * *
* A flag that indicates whether a body is a sensor . Sensor triggers collision events , but doesn ' t react with colliding body physically .
*
* @ property isSensor
* @ type boolean
* @ default false
* /
2014-06-09 14:40:24 -04:00
/ * *
* 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 .
* If you need to set a body as sleeping , you should use ` Sleeping.set ` as this requires more than just setting this flag .
*
* @ property isSleeping
* @ type boolean
* @ default false
* /
/ * *
* 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 .
* It is used and updated by the ` Matter.Sleeping ` module during simulation to decide if a body has come to rest .
*
* @ readOnly
* @ property motion
* @ type number
* @ default 0
* /
/ * *
* 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 ) .
*
* @ property sleepThreshold
* @ type number
* @ default 60
* /
/ * *
* A ` Number ` that defines the density of the body , that is its mass per unit area .
* If you pass the density via ` Body.create ` the ` mass ` property is automatically calculated for you based on the size ( area ) of the object .
* 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 ) .
*
* @ property density
* @ type number
* @ default 0.001
* /
/ * *
* A ` Number ` that defines the mass of the body , although it may be more appropriate to specify the ` density ` property instead .
* If you modify this value , you must also modify the ` body.inverseMass ` property ( ` 1 / mass ` ) .
*
* @ property mass
* @ type number
* /
/ * *
* A ` Number ` that defines the inverse mass of the body ( ` 1 / mass ` ) .
* If you modify this value , you must also modify the ` body.mass ` property .
*
* @ property inverseMass
* @ type number
* /
/ * *
* A ` Number ` that defines the moment of inertia ( i . e . second moment of area ) of the body .
* It is automatically calculated from the given convex hull ( ` vertices ` array ) and density in ` Body.create ` .
* If you modify this value , you must also modify the ` body.inverseInertia ` property ( ` 1 / inertia ` ) .
*
* @ property inertia
* @ type number
* /
/ * *
* A ` Number ` that defines the inverse moment of inertia of the body ( ` 1 / inertia ` ) .
* If you modify this value , you must also modify the ` body.inertia ` property .
*
* @ property inverseInertia
* @ type number
* /
/ * *
* A ` Number ` that defines the restitution ( elasticity ) of the body . The value is always positive and is in the range ` (0, 1) ` .
* A value of ` 0 ` means collisions may be perfectly inelastic and no bouncing may occur .
* A value of ` 0.8 ` means the body may bounce back with approximately 80 % of its kinetic energy .
* Note that collision response is based on _pairs _ of bodies , and that ` restitution ` values are _combined _ with the following formula :
*
* Math . max ( bodyA . restitution , bodyB . restitution )
*
* @ property restitution
* @ type number
* @ default 0
* /
/ * *
* A ` Number ` that defines the friction of the body . The value is always positive and is in the range ` (0, 1) ` .
* A value of ` 0 ` means that the body may slide indefinitely .
* A value of ` 1 ` means the body may come to a stop almost instantly after a force is applied .
*
* The effects of the value may be non - linear .
* High values may be unstable depending on the body .
* The engine uses a Coulomb friction model including static and kinetic friction .
* Note that collision response is based on _pairs _ of bodies , and that ` friction ` values are _combined _ with the following formula :
*
* Math . min ( bodyA . friction , bodyB . friction )
*
* @ property friction
* @ type number
* @ default 0.1
* /
2015-05-20 15:38:41 -04:00
/ * *
* A ` Number ` that defines the static friction of the body ( in the Coulomb friction model ) .
* A value of ` 0 ` means the body will never 'stick' when it is nearly stationary and only dynamic ` friction ` is used .
* The higher the value ( e . g . ` 10 ` ) , the more force it will take to initially get the body moving when nearly stationary .
* This value is multiplied with the ` friction ` property to make it easier to change ` friction ` and maintain an appropriate amount of static friction .
*
* @ property frictionStatic
* @ type number
* @ default 0.5
* /
2014-06-09 14:40:24 -04:00
/ * *
* A ` Number ` that defines the air friction of the body ( air resistance ) .
* A value of ` 0 ` means the body will never slow as it moves through space .
* The higher the value , the faster a body slows when moving through space .
* The effects of the value are non - linear .
*
* @ property frictionAir
* @ type number
* @ default 0.01
* /
/ * *
2014-07-29 11:26:49 -04:00
* An ` Object ` that specifies the collision filtering properties of this body .
2014-06-09 14:40:24 -04:00
*
2014-07-29 11:26:49 -04:00
* Collisions between two bodies will obey the following rules :
* - If the two bodies have the same non - zero value of ` collisionFilter.group ` ,
* they will always collide if the value is positive , and they will never collide
* if the value is negative .
* - If the two bodies have different values of ` collisionFilter.group ` or if one
* ( or both ) of the bodies has a value of 0 , then the category / mask rules apply as follows :
*
* Each body belongs to a collision category , given by ` collisionFilter.category ` . This
* value is used as a bit field and the category should have only one bit set , meaning that
* the value of this property is a power of two in the range [ 1 , 2 ^ 31 ] . Thus , there are 32
* different collision categories available .
*
* Each body also defines a collision bitmask , given by ` collisionFilter.mask ` which specifies
* the categories it collides with ( the value is the bitwise AND value of all these categories ) .
*
* Using the category / mask rules , two bodies ` A ` and ` B ` collide if each includes the other ' s
* category in its mask , i . e . ` (categoryA & maskB) !== 0 ` and ` (categoryB & maskA) !== 0 `
* are both true .
*
* @ property collisionFilter
* @ type object
* /
/ * *
* An Integer ` Number ` , that specifies the collision group this body belongs to .
* See ` body.collisionFilter ` for more information .
*
* @ property collisionFilter . group
* @ type object
2014-06-09 14:40:24 -04:00
* @ default 0
* /
/ * *
2014-07-29 11:26:49 -04:00
* A bit field that specifies the collision category this body belongs to .
* The category value should have only one bit set , for example ` 0x0001 ` .
* This means there are up to 32 unique collision categories available .
* See ` body.collisionFilter ` for more information .
*
* @ property collisionFilter . category
* @ type object
* @ default 1
* /
/ * *
* A bit mask that specifies the collision categories this body may collide with .
* See ` body.collisionFilter ` for more information .
*
* @ property collisionFilter . mask
* @ type object
* @ default - 1
* /
/ * *
* A ` Number ` that specifies a tolerance on how far a body is allowed to 'sink' or rotate into other bodies .
2014-06-09 14:40:24 -04:00
* Avoid changing this value unless you understand the purpose of ` slop ` in physics engines .
* The default should generally suffice , although very large bodies may require larger values for stable stacking .
*
* @ property slop
* @ type number
* @ default 0.05
* /
/ * *
* 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 .
*
* @ property timeScale
* @ type number
* @ default 1
* /
/ * *
* An ` Object ` that defines the rendering properties to be consumed by the module ` Matter.Render ` .
*
* @ property render
* @ type object
* /
/ * *
* A flag that indicates if the body should be rendered .
*
* @ property render . visible
* @ type boolean
* @ default true
* /
2016-02-07 10:53:07 -05:00
/ * *
* Sets the opacity to use when rendering .
*
* @ property render . opacity
* @ type number
* @ default 1
* /
2014-06-09 14:40:24 -04:00
/ * *
* An ` Object ` that defines the sprite properties to use when rendering , if any .
*
* @ property render . sprite
* @ type object
* /
/ * *
* An ` String ` that defines the path to the image to use as the sprite texture , if any .
*
* @ property render . sprite . texture
* @ type string
* /
/ * *
* A ` Number ` that defines the scaling in the x - axis for the sprite , if any .
*
* @ property render . sprite . xScale
* @ type number
* @ default 1
* /
/ * *
* A ` Number ` that defines the scaling in the y - axis for the sprite , if any .
*
* @ property render . sprite . yScale
* @ type number
* @ default 1
* /
2015-12-23 08:08:54 -05:00
/ * *
* A ` Number ` that defines the offset in the x - axis for the sprite ( normalised by texture width ) .
*
* @ property render . sprite . xOffset
* @ type number
* @ default 0
* /
/ * *
* A ` Number ` that defines the offset in the y - axis for the sprite ( normalised by texture height ) .
*
* @ property render . sprite . yOffset
* @ type number
* @ default 0
* /
2014-06-09 14:40:24 -04:00
/ * *
* A ` Number ` that defines the line width to use when rendering the body outline ( if a sprite is not defined ) .
* A value of ` 0 ` means no outline will be rendered .
*
* @ property render . lineWidth
* @ type number
* @ default 1.5
* /
/ * *
* A ` String ` that defines the fill style to use when rendering the body ( if a sprite is not defined ) .
* It is the same as when using a canvas , so it accepts CSS style property values .
*
* @ property render . fillStyle
* @ type string
* @ default a random colour
* /
/ * *
* A ` String ` that defines the stroke style to use when rendering the body outline ( if a sprite is not defined ) .
* It is the same as when using a canvas , so it accepts CSS style property values .
*
* @ property render . strokeStyle
* @ type string
* @ default a random colour
* /
/ * *
* An array of unique axis vectors ( edge normals ) used for collision detection .
* These are automatically calculated from the given convex hull ( ` vertices ` array ) in ` Body.create ` .
* They are constantly updated by ` Body.update ` during the simulation .
*
* @ property axes
* @ type vector [ ]
* /
/ * *
* A ` Number ` that _measures _ the area of the body ' s convex hull , calculated at creation by ` Body.create ` .
*
* @ property area
* @ type string
* @ default
* /
/ * *
* A ` Bounds ` object that defines the AABB region for the body .
* It is automatically calculated from the given convex hull ( ` vertices ` array ) in ` Body.create ` and constantly updated by ` Body.update ` during simulation .
*
* @ property bounds
* @ type bounds
* /
2014-05-01 09:09:06 -04:00
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "../core/Sleeping" : 20 , "../geometry/Axes" : 23 , "../geometry/Bounds" : 24 , "../geometry/Vector" : 26 , "../geometry/Vertices" : 27 , "../render/Render" : 29 } ] , 2 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Composite ` module contains methods for creating and manipulating composite bodies .
* A composite body is a collection of ` Matter.Body ` , ` Matter.Constraint ` and other ` Matter.Composite ` , therefore composites form a tree structure .
* It is important to use the functions in this module to modify composites , rather than directly modifying their properties .
* 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 ` .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class Composite
* /
2014-02-19 09:15:05 -05:00
var Composite = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Composite ;
var Events = require ( '../core/Events' ) ;
var Common = require ( '../core/Common' ) ;
var Body = require ( './Body' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new composite . The options parameter is an object that specifies any properties you wish to override the defaults .
* See the properites section below for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method create
2014-06-09 14:40:24 -04:00
* @ param { } [ options ]
2014-02-28 20:10:08 -05:00
* @ return { composite } A new composite
* /
2014-02-19 09:15:05 -05:00
Composite . create = function ( options ) {
2014-03-24 16:11:42 -04:00
return Common . extend ( {
2014-05-01 09:09:06 -04:00
id : Common . nextId ( ) ,
2014-03-30 14:45:30 -04:00
type : 'composite' ,
2014-03-24 16:11:42 -04:00
parent : null ,
isModified : false ,
bodies : [ ] ,
constraints : [ ] ,
2014-05-01 09:09:06 -04:00
composites : [ ] ,
label : 'Composite'
2014-03-24 16:11:42 -04:00
} , options ) ;
} ;
/ * *
* Sets the composite ' s ` isModified ` flag .
* If ` updateParents ` is true , all parents will be set ( default : false ) .
* If ` updateChildren ` is true , all children will be set ( default : false ) .
* @ method setModified
* @ param { composite } composite
* @ param { boolean } isModified
2014-06-09 14:40:24 -04:00
* @ param { boolean } [ updateParents = false ]
* @ param { boolean } [ updateChildren = false ]
2014-03-24 16:11:42 -04:00
* /
Composite . setModified = function ( composite , isModified , updateParents , updateChildren ) {
composite . isModified = isModified ;
if ( updateParents && composite . parent ) {
Composite . setModified ( composite . parent , isModified , updateParents , updateChildren ) ;
}
if ( updateChildren ) {
for ( var i = 0 ; i < composite . composites . length ; i ++ ) {
var childComposite = composite . composites [ i ] ;
Composite . setModified ( childComposite , isModified , updateParents , updateChildren ) ;
}
}
2014-02-19 09:15:05 -05:00
} ;
2014-03-30 14:45:30 -04:00
/ * *
* Generic add function . Adds one or many body ( s ) , constraint ( s ) or a composite ( s ) to the given composite .
2014-07-29 11:26:49 -04:00
* Triggers ` beforeAdd ` and ` afterAdd ` events on the ` composite ` .
2014-03-30 14:45:30 -04:00
* @ method add
* @ param { composite } composite
* @ param { } object
* @ return { composite } The original composite with the objects added
* /
Composite . add = function ( composite , object ) {
var objects = [ ] . concat ( object ) ;
2014-07-29 11:26:49 -04:00
Events . trigger ( composite , 'beforeAdd' , { object : object } ) ;
2014-03-30 14:45:30 -04:00
for ( var i = 0 ; i < objects . length ; i ++ ) {
var obj = objects [ i ] ;
switch ( obj . type ) {
case 'body' :
2015-05-20 15:38:41 -04:00
// skip adding compound parts
if ( obj . parent !== obj ) {
Common . log ( 'Composite.add: skipped adding a compound body part (you must add its parent instead)' , 'warn' ) ;
break ;
}
2014-03-30 14:45:30 -04:00
Composite . addBody ( composite , obj ) ;
break ;
case 'constraint' :
Composite . addConstraint ( composite , obj ) ;
break ;
case 'composite' :
Composite . addComposite ( composite , obj ) ;
break ;
case 'mouseConstraint' :
Composite . addConstraint ( composite , obj . constraint ) ;
break ;
}
}
2014-07-29 11:26:49 -04:00
Events . trigger ( composite , 'afterAdd' , { object : object } ) ;
2014-03-30 14:45:30 -04:00
return composite ;
} ;
/ * *
* Generic remove function . Removes one or many body ( s ) , constraint ( s ) or a composite ( s ) to the given composite .
* Optionally searching its children recursively .
2014-07-29 11:26:49 -04:00
* Triggers ` beforeRemove ` and ` afterRemove ` events on the ` composite ` .
2014-03-30 14:45:30 -04:00
* @ method remove
* @ param { composite } composite
* @ param { } object
2014-06-09 14:40:24 -04:00
* @ param { boolean } [ deep = false ]
2014-03-30 14:45:30 -04:00
* @ return { composite } The original composite with the objects removed
* /
Composite . remove = function ( composite , object , deep ) {
var objects = [ ] . concat ( object ) ;
2014-07-29 11:26:49 -04:00
Events . trigger ( composite , 'beforeRemove' , { object : object } ) ;
2014-03-30 14:45:30 -04:00
for ( var i = 0 ; i < objects . length ; i ++ ) {
var obj = objects [ i ] ;
switch ( obj . type ) {
case 'body' :
Composite . removeBody ( composite , obj , deep ) ;
break ;
case 'constraint' :
Composite . removeConstraint ( composite , obj , deep ) ;
break ;
case 'composite' :
Composite . removeComposite ( composite , obj , deep ) ;
break ;
case 'mouseConstraint' :
Composite . removeConstraint ( composite , obj . constraint ) ;
break ;
}
}
2014-07-29 11:26:49 -04:00
Events . trigger ( composite , 'afterRemove' , { object : object } ) ;
2014-03-30 14:45:30 -04:00
return composite ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Adds a composite to the given composite .
2014-07-29 11:26:49 -04:00
* @ private
2014-03-24 16:11:42 -04:00
* @ method addComposite
2014-02-28 20:10:08 -05:00
* @ param { composite } compositeA
* @ param { composite } compositeB
* @ return { composite } The original compositeA with the objects from compositeB added
* /
2014-03-24 16:11:42 -04:00
Composite . addComposite = function ( compositeA , compositeB ) {
compositeA . composites . push ( compositeB ) ;
compositeB . parent = compositeA ;
Composite . setModified ( compositeA , true , true , false ) ;
2014-02-19 09:15:05 -05:00
return compositeA ;
} ;
2014-03-30 14:45:30 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Removes a composite from the given composite , and optionally searching its children recursively .
2014-07-29 11:26:49 -04:00
* @ private
2014-03-30 14:45:30 -04:00
* @ method removeComposite
* @ param { composite } compositeA
* @ param { composite } compositeB
2014-06-09 14:40:24 -04:00
* @ param { boolean } [ deep = false ]
2014-03-30 14:45:30 -04:00
* @ return { composite } The original compositeA with the composite removed
* /
Composite . removeComposite = function ( compositeA , compositeB , deep ) {
2014-07-29 11:26:49 -04:00
var position = Common . indexOf ( compositeA . composites , compositeB ) ;
2014-03-30 14:45:30 -04:00
if ( position !== - 1 ) {
Composite . removeCompositeAt ( compositeA , position ) ;
Composite . setModified ( compositeA , true , true , false ) ;
}
if ( deep ) {
for ( var i = 0 ; i < compositeA . composites . length ; i ++ ) {
Composite . removeComposite ( compositeA . composites [ i ] , compositeB , true ) ;
}
}
return compositeA ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Removes a composite from the given composite .
2014-07-29 11:26:49 -04:00
* @ private
2014-03-30 14:45:30 -04:00
* @ method removeCompositeAt
* @ param { composite } composite
* @ param { number } position
* @ return { composite } The original composite with the composite removed
* /
Composite . removeCompositeAt = function ( composite , position ) {
composite . composites . splice ( position , 1 ) ;
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Adds a body to the given composite .
2014-07-29 11:26:49 -04:00
* @ private
2014-02-28 20:10:08 -05:00
* @ method addBody
* @ param { composite } composite
* @ param { body } body
* @ return { composite } The original composite with the body added
* /
2014-02-19 09:15:05 -05:00
Composite . addBody = function ( composite , body ) {
composite . bodies . push ( body ) ;
2014-03-24 16:11:42 -04:00
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Removes a body from the given composite , and optionally searching its children recursively .
2014-07-29 11:26:49 -04:00
* @ private
2014-03-24 16:11:42 -04:00
* @ method removeBody
* @ param { composite } composite
* @ param { body } body
2014-06-09 14:40:24 -04:00
* @ param { boolean } [ deep = false ]
2014-03-24 16:11:42 -04:00
* @ return { composite } The original composite with the body removed
* /
Composite . removeBody = function ( composite , body , deep ) {
2014-07-29 11:26:49 -04:00
var position = Common . indexOf ( composite . bodies , body ) ;
2014-03-24 16:11:42 -04:00
if ( position !== - 1 ) {
Composite . removeBodyAt ( composite , position ) ;
Composite . setModified ( composite , true , true , false ) ;
}
if ( deep ) {
for ( var i = 0 ; i < composite . composites . length ; i ++ ) {
Composite . removeBody ( composite . composites [ i ] , body , true ) ;
}
}
return composite ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Removes a body from the given composite .
2014-07-29 11:26:49 -04:00
* @ private
2014-03-24 16:11:42 -04:00
* @ method removeBodyAt
* @ param { composite } composite
* @ param { number } position
* @ return { composite } The original composite with the body removed
* /
Composite . removeBodyAt = function ( composite , position ) {
composite . bodies . splice ( position , 1 ) ;
Composite . setModified ( composite , true , true , false ) ;
2014-02-19 09:15:05 -05:00
return composite ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Adds a constraint to the given composite .
2014-07-29 11:26:49 -04:00
* @ private
2014-02-28 20:10:08 -05:00
* @ method addConstraint
* @ param { composite } composite
* @ param { constraint } constraint
* @ return { composite } The original composite with the constraint added
* /
2014-02-19 09:15:05 -05:00
Composite . addConstraint = function ( composite , constraint ) {
composite . constraints . push ( constraint ) ;
2014-03-24 16:11:42 -04:00
Composite . setModified ( composite , true , true , false ) ;
2014-02-19 09:15:05 -05:00
return composite ;
} ;
2014-03-24 16:11:42 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Removes a constraint from the given composite , and optionally searching its children recursively .
2014-07-29 11:26:49 -04:00
* @ private
2014-03-24 16:11:42 -04:00
* @ method removeConstraint
* @ param { composite } composite
* @ param { constraint } constraint
2014-06-09 14:40:24 -04:00
* @ param { boolean } [ deep = false ]
2014-03-24 16:11:42 -04:00
* @ return { composite } The original composite with the constraint removed
* /
Composite . removeConstraint = function ( composite , constraint , deep ) {
2014-07-29 11:26:49 -04:00
var position = Common . indexOf ( composite . constraints , constraint ) ;
2014-03-24 16:11:42 -04:00
if ( position !== - 1 ) {
Composite . removeConstraintAt ( composite , position ) ;
}
if ( deep ) {
for ( var i = 0 ; i < composite . composites . length ; i ++ ) {
Composite . removeConstraint ( composite . composites [ i ] , constraint , true ) ;
}
}
return composite ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Removes a body from the given composite .
2014-07-29 11:26:49 -04:00
* @ private
2014-03-24 16:11:42 -04:00
* @ method removeConstraintAt
* @ param { composite } composite
* @ param { number } position
* @ return { composite } The original composite with the constraint removed
* /
Composite . removeConstraintAt = function ( composite , position ) {
composite . constraints . splice ( position , 1 ) ;
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Removes all bodies , constraints and composites from the given composite .
* Optionally clearing its children recursively .
2014-03-24 16:11:42 -04:00
* @ method clear
2015-06-29 15:58:24 -04:00
* @ param { composite } composite
2014-03-24 16:11:42 -04:00
* @ param { boolean } keepStatic
2014-06-09 14:40:24 -04:00
* @ param { boolean } [ deep = false ]
2014-03-24 16:11:42 -04:00
* /
Composite . clear = function ( composite , keepStatic , deep ) {
if ( deep ) {
for ( var i = 0 ; i < composite . composites . length ; i ++ ) {
Composite . clear ( composite . composites [ i ] , keepStatic , true ) ;
}
}
if ( keepStatic ) {
composite . bodies = composite . bodies . filter ( function ( body ) { return body . isStatic ; } ) ;
} else {
composite . bodies . length = 0 ;
}
composite . constraints . length = 0 ;
composite . composites . length = 0 ;
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Returns all bodies in the given composite , including all bodies in its children , recursively .
2014-03-24 16:11:42 -04:00
* @ method allBodies
* @ param { composite } composite
* @ return { body [ ] } All the bodies
* /
Composite . allBodies = function ( composite ) {
var bodies = [ ] . concat ( composite . bodies ) ;
for ( var i = 0 ; i < composite . composites . length ; i ++ )
bodies = bodies . concat ( Composite . allBodies ( composite . composites [ i ] ) ) ;
return bodies ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Returns all constraints in the given composite , including all constraints in its children , recursively .
2014-03-24 16:11:42 -04:00
* @ method allConstraints
* @ param { composite } composite
* @ return { constraint [ ] } All the constraints
* /
Composite . allConstraints = function ( composite ) {
var constraints = [ ] . concat ( composite . constraints ) ;
for ( var i = 0 ; i < composite . composites . length ; i ++ )
constraints = constraints . concat ( Composite . allConstraints ( composite . composites [ i ] ) ) ;
return constraints ;
} ;
2014-03-30 14:45:30 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns all composites in the given composite , including all composites in its children , recursively .
2014-03-30 14:45:30 -04:00
* @ method allComposites
* @ param { composite } composite
* @ return { composite [ ] } All the composites
* /
Composite . allComposites = function ( composite ) {
var composites = [ ] . concat ( composite . composites ) ;
for ( var i = 0 ; i < composite . composites . length ; i ++ )
composites = composites . concat ( Composite . allComposites ( composite . composites [ i ] ) ) ;
return composites ;
} ;
2014-05-01 09:09:06 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Searches the composite recursively for an object matching the type and id supplied , null if not found .
2014-05-01 09:09:06 -04:00
* @ method get
* @ param { composite } composite
* @ param { number } id
* @ param { string } type
* @ return { object } The requested object , if found
* /
Composite . get = function ( composite , id , type ) {
var objects ,
object ;
switch ( type ) {
case 'body' :
objects = Composite . allBodies ( composite ) ;
break ;
case 'constraint' :
objects = Composite . allConstraints ( composite ) ;
break ;
case 'composite' :
objects = Composite . allComposites ( composite ) . concat ( composite ) ;
break ;
}
if ( ! objects )
return null ;
object = objects . filter ( function ( object ) {
return object . id . toString ( ) === id . toString ( ) ;
} ) ;
return object . length === 0 ? null : object [ 0 ] ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Moves the given object ( s ) from compositeA to compositeB ( equal to a remove followed by an add ) .
2014-05-01 09:09:06 -04:00
* @ method move
* @ param { compositeA } compositeA
* @ param { object [ ] } objects
* @ param { compositeB } compositeB
* @ return { composite } Returns compositeA
* /
Composite . move = function ( compositeA , objects , compositeB ) {
Composite . remove ( compositeA , objects ) ;
Composite . add ( compositeB , objects ) ;
return compositeA ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Assigns new ids for all objects in the composite , recursively .
2014-06-09 14:40:24 -04:00
* @ method rebase
* @ param { composite } composite
* @ return { composite } Returns composite
* /
Composite . rebase = function ( composite ) {
var objects = Composite . allBodies ( composite )
. concat ( Composite . allConstraints ( composite ) )
. concat ( Composite . allComposites ( composite ) ) ;
for ( var i = 0 ; i < objects . length ; i ++ ) {
objects [ i ] . id = Common . nextId ( ) ;
}
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
2014-07-30 12:29:21 -04:00
/ * *
* Translates all children in the composite by a given vector relative to their current positions ,
* without imparting any velocity .
* @ method translate
* @ param { composite } composite
* @ param { vector } translation
* @ param { bool } [ recursive = true ]
* /
Composite . translate = function ( composite , translation , recursive ) {
var bodies = recursive ? Composite . allBodies ( composite ) : composite . bodies ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
Body . translate ( bodies [ i ] , translation ) ;
}
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
/ * *
* Rotates all children in the composite by a given angle about the given point , without imparting any angular velocity .
* @ method rotate
* @ param { composite } composite
* @ param { number } rotation
* @ param { vector } point
* @ param { bool } [ recursive = true ]
* /
Composite . rotate = function ( composite , rotation , point , recursive ) {
var cos = Math . cos ( rotation ) ,
sin = Math . sin ( rotation ) ,
bodies = recursive ? Composite . allBodies ( composite ) : composite . bodies ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ,
dx = body . position . x - point . x ,
dy = body . position . y - point . y ;
Body . setPosition ( body , {
x : point . x + ( dx * cos - dy * sin ) ,
y : point . y + ( dx * sin + dy * cos )
} ) ;
Body . rotate ( body , rotation ) ;
}
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
/ * *
* Scales all children in the composite , including updating physical properties ( mass , area , axes , inertia ) , from a world - space point .
* @ method scale
* @ param { composite } composite
* @ param { number } scaleX
* @ param { number } scaleY
* @ param { vector } point
* @ param { bool } [ recursive = true ]
* /
Composite . scale = function ( composite , scaleX , scaleY , point , recursive ) {
var bodies = recursive ? Composite . allBodies ( composite ) : composite . bodies ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ,
dx = body . position . x - point . x ,
dy = body . position . y - point . y ;
Body . setPosition ( body , {
x : point . x + dx * scaleX ,
y : point . y + dy * scaleY
} ) ;
Body . scale ( body , scaleX , scaleY ) ;
}
Composite . setModified ( composite , true , true , false ) ;
return composite ;
} ;
2014-07-29 11:26:49 -04:00
/ *
*
* Events Documentation
*
* /
/ * *
* Fired when a call to ` Composite.add ` is made , before objects have been added .
*
* @ event beforeAdd
* @ param { } event An event object
* @ param { } event . object The object ( s ) to be added ( may be a single body , constraint , composite or a mixed array of these )
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired when a call to ` Composite.add ` is made , after objects have been added .
*
* @ event afterAdd
* @ param { } event An event object
* @ param { } event . object The object ( s ) that have been added ( may be a single body , constraint , composite or a mixed array of these )
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired when a call to ` Composite.remove ` is made , before objects have been removed .
*
* @ event beforeRemove
* @ param { } event An event object
* @ param { } event . object The object ( s ) to be removed ( may be a single body , constraint , composite or a mixed array of these )
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired when a call to ` Composite.remove ` is made , after objects have been removed .
*
* @ event afterRemove
* @ param { } event An event object
* @ param { } event . object The object ( s ) that have been removed ( may be a single body , constraint , composite or a mixed array of these )
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
2014-06-09 14:40:24 -04:00
/ *
*
* Properties Documentation
*
* /
/ * *
* An integer ` Number ` uniquely identifying number generated in ` Composite.create ` by ` Common.nextId ` .
*
* @ property id
* @ type number
* /
/ * *
* A ` String ` denoting the type of object .
*
* @ property type
* @ type string
* @ default "composite"
* /
/ * *
* An arbitrary ` String ` name to help the user identify and manage composites .
*
* @ property label
* @ type string
* @ default "Composite"
* /
/ * *
* A flag that specifies whether the composite has been modified during the current step .
* Most ` Matter.Composite ` methods will automatically set this flag to ` true ` to inform the engine of changes to be handled .
* If you need to change it manually , you should use the ` Composite.setModified ` method .
*
* @ property isModified
* @ type boolean
* @ default false
2014-05-01 09:09:06 -04:00
* /
2014-06-09 14:40:24 -04:00
/ * *
* The ` Composite ` that is the parent of this composite . It is automatically managed by the ` Matter.Composite ` methods .
*
* @ property parent
* @ type composite
* @ default null
* /
2014-05-01 09:09:06 -04:00
2014-06-09 14:40:24 -04:00
/ * *
* An array of ` Body ` that are _direct _ children of this composite .
* To add or remove bodies you should use ` Composite.add ` and ` Composite.remove ` methods rather than directly modifying this property .
* If you wish to recursively find all descendants , you should use the ` Composite.allBodies ` method .
*
* @ property bodies
* @ type body [ ]
* @ default [ ]
* /
2014-05-01 09:09:06 -04:00
2014-06-09 14:40:24 -04:00
/ * *
* An array of ` Constraint ` that are _direct _ children of this composite .
* To add or remove constraints you should use ` Composite.add ` and ` Composite.remove ` methods rather than directly modifying this property .
* If you wish to recursively find all descendants , you should use the ` Composite.allConstraints ` method .
*
* @ property constraints
* @ type constraint [ ]
* @ default [ ]
* /
/ * *
* An array of ` Composite ` that are _direct _ children of this composite .
* To add or remove composites you should use ` Composite.add ` and ` Composite.remove ` methods rather than directly modifying this property .
* If you wish to recursively find all descendants , you should use the ` Composite.allComposites ` method .
*
* @ property composites
* @ type composite [ ]
* @ default [ ]
* /
2014-05-01 09:09:06 -04:00
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "../core/Events" : 16 , "./Body" : 1 } ] , 3 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.World ` module contains methods for creating and manipulating the world composite .
* A ` Matter.World ` is a ` Matter.Composite ` body , which is a collection of ` Matter.Body ` , ` Matter.Constraint ` and other ` Matter.Composite ` .
* A ` Matter.World ` has a few additional properties including ` gravity ` and ` bounds ` .
* It is important to use the functions in the ` Matter.Composite ` module to modify the world composite , rather than directly modifying its properties .
* There are also a few methods here that alias those in ` Matter.Composite ` for easier readability .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class World
2015-05-20 15:38:41 -04:00
* @ extends Composite
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var World = { } ;
2015-08-17 18:50:03 -04:00
module . exports = World ;
var Composite = require ( './Composite' ) ;
var Constraint = require ( '../constraint/Constraint' ) ;
var Common = require ( '../core/Common' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new world composite . The options parameter is an object that specifies any properties you wish to override the defaults .
2015-06-29 15:58:24 -04:00
* See the properties section below for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method create
* @ constructor
* @ param { } options
* @ return { world } A new world
* /
2014-02-19 09:15:05 -05:00
World . create = function ( options ) {
2014-03-24 16:11:42 -04:00
var composite = Composite . create ( ) ;
2014-02-19 09:15:05 -05:00
var defaults = {
2014-05-01 09:09:06 -04:00
label : 'World' ,
2016-01-16 17:43:32 -05:00
gravity : {
x : 0 ,
y : 1 ,
scale : 0.001
} ,
2014-02-19 09:15:05 -05:00
bounds : {
2015-05-21 19:33:26 -04:00
min : { x : - Infinity , y : - Infinity } ,
max : { x : Infinity , y : Infinity }
2014-02-19 09:15:05 -05:00
}
} ;
2014-03-24 16:11:42 -04:00
return Common . extend ( composite , defaults , options ) ;
2014-02-19 09:15:05 -05:00
} ;
2014-03-24 16:11:42 -04:00
2016-01-16 17:43:32 -05:00
/ *
*
* Properties Documentation
*
* /
/ * *
* The gravity to apply on the world .
*
* @ property gravity
* @ type object
* /
/ * *
* The gravity x component .
*
* @ property gravity . x
* @ type object
* @ default 0
* /
/ * *
* The gravity y component .
*
* @ property gravity . y
* @ type object
* @ default 1
* /
/ * *
* The gravity scale factor .
*
* @ property gravity . scale
* @ type object
* @ default 0.001
* /
2016-04-07 15:03:37 -04:00
/ * *
* A ` Bounds ` object that defines the world bounds for collision detection .
*
* @ property bounds
* @ type bounds
* @ default { min : { x : - Infinity , y : - Infinity } , max : { x : Infinity , y : Infinity } }
* /
2014-03-24 16:11:42 -04:00
// World is a Composite body
// see src/module/Outro.js for these aliases:
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* An alias for Composite . clear
2014-02-28 20:10:08 -05:00
* @ method clear
* @ param { world } world
* @ param { boolean } keepStatic
* /
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* An alias for Composite . add
2014-02-28 20:10:08 -05:00
* @ method addComposite
* @ param { world } world
* @ param { composite } composite
* @ return { world } The original world with the objects from composite added
* /
/ * *
2016-01-16 17:43:32 -05:00
* An alias for Composite . addBody
2014-02-28 20:10:08 -05:00
* @ method addBody
* @ param { world } world
* @ param { body } body
* @ return { world } The original world with the body added
* /
/ * *
2016-01-16 17:43:32 -05:00
* An alias for Composite . addConstraint
2014-02-28 20:10:08 -05:00
* @ method addConstraint
* @ param { world } world
* @ param { constraint } constraint
* @ return { world } The original world with the constraint added
* /
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../constraint/Constraint" : 12 , "../core/Common" : 14 , "./Composite" : 2 } ] , 4 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Contact ` module contains methods for creating and manipulating collision contacts .
2014-02-28 20:10:08 -05:00
*
* @ class Contact
* /
2014-02-19 09:15:05 -05:00
var Contact = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Contact ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a new contact .
2014-02-28 20:10:08 -05:00
* @ method create
* @ param { vertex } vertex
* @ return { contact } A new contact
* /
2014-02-19 09:15:05 -05:00
Contact . create = function ( vertex ) {
return {
id : Contact . id ( vertex ) ,
vertex : vertex ,
normalImpulse : 0 ,
tangentImpulse : 0
} ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Generates a contact id .
2014-02-28 20:10:08 -05:00
* @ method id
* @ param { vertex } vertex
2015-01-01 18:10:10 -05:00
* @ return { string } Unique contactID
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
Contact . id = function ( vertex ) {
return vertex . body . id + '_' + vertex . index ;
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { } ] , 5 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Detector ` module contains methods for detecting collisions given a set of pairs .
2014-02-28 20:10:08 -05:00
*
* @ class Detector
* /
2014-02-19 09:15:05 -05:00
// TODO: speculative contacts
var Detector = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Detector ;
var SAT = require ( './SAT' ) ;
var Pair = require ( './Pair' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Finds all collisions given a list of pairs .
2014-02-28 20:10:08 -05:00
* @ method collisions
2014-03-22 13:51:49 -04:00
* @ param { pair [ ] } broadphasePairs
* @ param { engine } engine
2014-02-28 20:10:08 -05:00
* @ return { array } collisions
* /
2014-03-22 13:51:49 -04:00
Detector . collisions = function ( broadphasePairs , engine ) {
var collisions = [ ] ,
pairsTable = engine . pairs . table ;
2014-02-19 09:15:05 -05:00
2015-05-20 15:38:41 -04:00
2014-03-22 13:51:49 -04:00
for ( var i = 0 ; i < broadphasePairs . length ; i ++ ) {
var bodyA = broadphasePairs [ i ] [ 0 ] ,
bodyB = broadphasePairs [ i ] [ 1 ] ;
2014-02-19 09:15:05 -05:00
if ( ( bodyA . isStatic || bodyA . isSleeping ) && ( bodyB . isStatic || bodyB . isSleeping ) )
continue ;
2014-07-29 11:26:49 -04:00
if ( ! Detector . canCollide ( bodyA . collisionFilter , bodyB . collisionFilter ) )
continue ;
2014-02-19 09:15:05 -05:00
2015-12-05 11:47:50 -05:00
2014-02-19 09:15:05 -05:00
// mid phase
if ( Bounds . overlaps ( bodyA . bounds , bodyB . bounds ) ) {
2015-05-20 15:38:41 -04:00
for ( var j = bodyA . parts . length > 1 ? 1 : 0 ; j < bodyA . parts . length ; j ++ ) {
var partA = bodyA . parts [ j ] ;
for ( var k = bodyB . parts . length > 1 ? 1 : 0 ; k < bodyB . parts . length ; k ++ ) {
var partB = bodyB . parts [ k ] ;
if ( ( partA === bodyA && partB === bodyB ) || Bounds . overlaps ( partA . bounds , partB . bounds ) ) {
// find a previous collision we could reuse
var pairId = Pair . id ( partA , partB ) ,
pair = pairsTable [ pairId ] ,
previousCollision ;
if ( pair && pair . isActive ) {
previousCollision = pair . collision ;
} else {
previousCollision = null ;
}
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
// narrow phase
var collision = SAT . collides ( partA , partB , previousCollision ) ;
2014-03-22 13:51:49 -04:00
2015-12-05 11:47:50 -05:00
2015-05-20 15:38:41 -04:00
if ( collision . collided ) {
collisions . push ( collision ) ;
}
}
}
2014-02-19 09:15:05 -05:00
}
}
}
return collisions ;
} ;
2014-07-29 11:26:49 -04:00
/ * *
* Returns ` true ` if both supplied collision filters will allow a collision to occur .
* See ` body.collisionFilter ` for more information .
* @ method canCollide
* @ param { } filterA
* @ param { } filterB
* @ return { bool } ` true ` if collision can occur
* /
Detector . canCollide = function ( filterA , filterB ) {
if ( filterA . group === filterB . group && filterA . group !== 0 )
return filterA . group > 0 ;
return ( filterA . mask & filterB . category ) !== 0 && ( filterB . mask & filterA . category ) !== 0 ;
} ;
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../geometry/Bounds" : 24 , "./Pair" : 7 , "./SAT" : 11 } ] , 6 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Grid ` module contains methods for creating and manipulating collision broadphase grid structures .
2014-02-28 20:10:08 -05:00
*
* @ class Grid
* /
2014-02-19 09:15:05 -05:00
var Grid = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Grid ;
var Pair = require ( './Pair' ) ;
var Detector = require ( './Detector' ) ;
var Common = require ( '../core/Common' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a new grid .
2014-02-28 20:10:08 -05:00
* @ method create
2014-07-29 11:26:49 -04:00
* @ param { } options
2014-02-28 20:10:08 -05:00
* @ return { grid } A new grid
* /
2014-07-29 11:26:49 -04:00
Grid . create = function ( options ) {
var defaults = {
controller : Grid ,
detector : Detector . collisions ,
2014-02-19 09:15:05 -05:00
buckets : { } ,
pairs : { } ,
pairsList : [ ] ,
2014-07-29 11:26:49 -04:00
bucketWidth : 48 ,
bucketHeight : 48
2014-02-19 09:15:05 -05:00
} ;
2014-07-29 11:26:49 -04:00
return Common . extend ( defaults , options ) ;
2014-02-19 09:15:05 -05:00
} ;
2016-04-07 15:03:37 -04:00
/ * *
* The width of a single grid bucket .
*
* @ property bucketWidth
* @ type number
* @ default 48
* /
/ * *
* The height of a single grid bucket .
*
* @ property bucketHeight
* @ type number
* @ default 48
* /
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Updates the grid .
2014-02-28 20:10:08 -05:00
* @ method update
* @ param { grid } grid
* @ param { body [ ] } bodies
* @ param { engine } engine
* @ param { boolean } forceUpdate
* /
2014-02-19 09:15:05 -05:00
Grid . update = function ( grid , bodies , engine , forceUpdate ) {
var i , col , row ,
world = engine . world ,
buckets = grid . buckets ,
bucket ,
bucketId ,
gridChanged = false ;
2015-12-05 11:47:50 -05:00
2014-02-19 09:15:05 -05:00
for ( i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
2014-03-24 16:11:42 -04:00
if ( body . isSleeping && ! forceUpdate )
2014-02-19 09:15:05 -05:00
continue ;
// don't update out of world bodies
2016-04-07 15:03:37 -04:00
if ( body . bounds . max . x < world . bounds . min . x || body . bounds . min . x > world . bounds . max . x
|| body . bounds . max . y < world . bounds . min . y || body . bounds . min . y > world . bounds . max . y )
2014-02-19 09:15:05 -05:00
continue ;
var newRegion = _getRegion ( grid , body ) ;
// if the body has changed grid region
if ( ! body . region || newRegion . id !== body . region . id || forceUpdate ) {
2015-12-05 11:47:50 -05:00
2014-02-19 09:15:05 -05:00
if ( ! body . region || forceUpdate )
body . region = newRegion ;
var union = _regionUnion ( newRegion , body . region ) ;
// update grid buckets affected by region change
// iterate over the union of both regions
for ( col = union . startCol ; col <= union . endCol ; col ++ ) {
for ( row = union . startRow ; row <= union . endRow ; row ++ ) {
bucketId = _getBucketId ( col , row ) ;
bucket = buckets [ bucketId ] ;
var isInsideNewRegion = ( col >= newRegion . startCol && col <= newRegion . endCol
&& row >= newRegion . startRow && row <= newRegion . endRow ) ;
var isInsideOldRegion = ( col >= body . region . startCol && col <= body . region . endCol
&& row >= body . region . startRow && row <= body . region . endRow ) ;
// remove from old region buckets
if ( ! isInsideNewRegion && isInsideOldRegion ) {
if ( isInsideOldRegion ) {
if ( bucket )
_bucketRemoveBody ( grid , bucket , body ) ;
}
}
// add to new region buckets
if ( body . region === newRegion || ( isInsideNewRegion && ! isInsideOldRegion ) || forceUpdate ) {
if ( ! bucket )
bucket = _createBucket ( buckets , bucketId ) ;
_bucketAddBody ( grid , bucket , body ) ;
}
}
}
// set the new region
body . region = newRegion ;
// flag changes so we can update pairs
gridChanged = true ;
}
}
// update pairs list only if pairs changed (i.e. a body changed region)
if ( gridChanged )
grid . pairsList = _createActivePairsList ( grid ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Clears the grid .
2014-02-28 20:10:08 -05:00
* @ method clear
* @ param { grid } grid
* /
2014-02-19 09:15:05 -05:00
Grid . clear = function ( grid ) {
grid . buckets = { } ;
grid . pairs = { } ;
grid . pairsList = [ ] ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Finds the union of two regions .
2014-02-28 20:10:08 -05:00
* @ method _regionUnion
* @ private
* @ param { } regionA
* @ param { } regionB
2016-01-16 17:43:32 -05:00
* @ return { } region
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var _regionUnion = function ( regionA , regionB ) {
var startCol = Math . min ( regionA . startCol , regionB . startCol ) ,
endCol = Math . max ( regionA . endCol , regionB . endCol ) ,
startRow = Math . min ( regionA . startRow , regionB . startRow ) ,
endRow = Math . max ( regionA . endRow , regionB . endRow ) ;
return _createRegion ( startCol , endCol , startRow , endRow ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Gets the region a given body falls in for a given grid .
2014-02-28 20:10:08 -05:00
* @ method _getRegion
* @ private
* @ param { } grid
* @ param { } body
2016-01-16 17:43:32 -05:00
* @ return { } region
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var _getRegion = function ( grid , body ) {
var bounds = body . bounds ,
startCol = Math . floor ( bounds . min . x / grid . bucketWidth ) ,
endCol = Math . floor ( bounds . max . x / grid . bucketWidth ) ,
startRow = Math . floor ( bounds . min . y / grid . bucketHeight ) ,
endRow = Math . floor ( bounds . max . y / grid . bucketHeight ) ;
return _createRegion ( startCol , endCol , startRow , endRow ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a region .
2014-02-28 20:10:08 -05:00
* @ method _createRegion
* @ private
* @ param { } startCol
* @ param { } endCol
* @ param { } startRow
* @ param { } endRow
2016-01-16 17:43:32 -05:00
* @ return { } region
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var _createRegion = function ( startCol , endCol , startRow , endRow ) {
return {
id : startCol + ',' + endCol + ',' + startRow + ',' + endRow ,
startCol : startCol ,
endCol : endCol ,
startRow : startRow ,
endRow : endRow
} ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Gets the bucket id at the given position .
2014-02-28 20:10:08 -05:00
* @ method _getBucketId
* @ private
* @ param { } column
* @ param { } row
2016-01-16 17:43:32 -05:00
* @ return { string } bucket id
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var _getBucketId = function ( column , row ) {
return column + ',' + row ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a bucket .
2014-02-28 20:10:08 -05:00
* @ method _createBucket
* @ private
* @ param { } buckets
* @ param { } bucketId
2016-01-16 17:43:32 -05:00
* @ return { } bucket
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var _createBucket = function ( buckets , bucketId ) {
var bucket = buckets [ bucketId ] = [ ] ;
return bucket ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Adds a body to a bucket .
2014-02-28 20:10:08 -05:00
* @ method _bucketAddBody
* @ private
* @ param { } grid
* @ param { } bucket
* @ param { } body
* /
2014-02-19 09:15:05 -05:00
var _bucketAddBody = function ( grid , bucket , body ) {
// add new pairs
for ( var i = 0 ; i < bucket . length ; i ++ ) {
var bodyB = bucket [ i ] ;
if ( body . id === bodyB . id || ( body . isStatic && bodyB . isStatic ) )
continue ;
// keep track of the number of buckets the pair exists in
// important for Grid.update to work
2014-03-22 13:51:49 -04:00
var pairId = Pair . id ( body , bodyB ) ,
pair = grid . pairs [ pairId ] ;
if ( pair ) {
pair [ 2 ] += 1 ;
2014-02-19 09:15:05 -05:00
} else {
grid . pairs [ pairId ] = [ body , bodyB , 1 ] ;
}
}
// add to bodies (after pairs, otherwise pairs with self)
bucket . push ( body ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Removes a body from a bucket .
2014-02-28 20:10:08 -05:00
* @ method _bucketRemoveBody
* @ private
* @ param { } grid
* @ param { } bucket
* @ param { } body
* /
2014-02-19 09:15:05 -05:00
var _bucketRemoveBody = function ( grid , bucket , body ) {
2014-03-22 13:51:49 -04:00
// remove from bucket
2014-07-29 11:26:49 -04:00
bucket . splice ( Common . indexOf ( bucket , body ) , 1 ) ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
// update pair counts
for ( var i = 0 ; i < bucket . length ; i ++ ) {
// keep track of the number of buckets the pair exists in
// important for _createActivePairsList to work
var bodyB = bucket [ i ] ,
pairId = Pair . id ( body , bodyB ) ,
pair = grid . pairs [ pairId ] ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( pair )
pair [ 2 ] -= 1 ;
2014-02-19 09:15:05 -05:00
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Generates a list of the active pairs in the grid .
2014-02-28 20:10:08 -05:00
* @ method _createActivePairsList
* @ private
* @ param { } grid
2016-01-16 17:43:32 -05:00
* @ return [ ] pairs
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var _createActivePairsList = function ( grid ) {
var pairKeys ,
pair ,
pairs = [ ] ;
// grid.pairs is used as a hashmap
pairKeys = Common . keys ( grid . pairs ) ;
// iterate over grid.pairs
for ( var k = 0 ; k < pairKeys . length ; k ++ ) {
pair = grid . pairs [ pairKeys [ k ] ] ;
// if pair exists in at least one bucket
// it is a pair that needs further collision testing so push it
2014-03-22 13:51:49 -04:00
if ( pair [ 2 ] > 0 ) {
2014-02-19 09:15:05 -05:00
pairs . push ( pair ) ;
2014-03-22 13:51:49 -04:00
} else {
delete grid . pairs [ pairKeys [ k ] ] ;
}
2014-02-19 09:15:05 -05:00
}
return pairs ;
} ;
} ) ( ) ;
2016-01-16 17:43:32 -05:00
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "./Detector" : 5 , "./Pair" : 7 } ] , 7 : [ function ( require , module , exports ) {
2014-03-24 16:11:42 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Pair ` module contains methods for creating and manipulating collision pairs .
2014-03-24 16:11:42 -04:00
*
* @ class Pair
* /
var Pair = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Pair ;
var Contact = require ( './Contact' ) ;
2014-03-24 16:11:42 -04:00
( function ( ) {
/ * *
2016-01-16 17:43:32 -05:00
* Creates a pair .
2014-03-24 16:11:42 -04:00
* @ method create
* @ param { collision } collision
2015-06-29 15:58:24 -04:00
* @ param { number } timestamp
2014-03-24 16:11:42 -04:00
* @ return { pair } A new pair
* /
Pair . create = function ( collision , timestamp ) {
var bodyA = collision . bodyA ,
2015-05-20 15:38:41 -04:00
bodyB = collision . bodyB ,
parentA = collision . parentA ,
parentB = collision . parentB ;
2014-03-24 16:11:42 -04:00
var pair = {
id : Pair . id ( bodyA , bodyB ) ,
bodyA : bodyA ,
bodyB : bodyB ,
contacts : { } ,
activeContacts : [ ] ,
separation : 0 ,
isActive : true ,
2016-04-07 15:03:37 -04:00
isSensor : bodyA . isSensor || bodyB . isSensor ,
2014-03-24 16:11:42 -04:00
timeCreated : timestamp ,
timeUpdated : timestamp ,
2015-05-20 15:38:41 -04:00
inverseMass : parentA . inverseMass + parentB . inverseMass ,
friction : Math . min ( parentA . friction , parentB . friction ) ,
frictionStatic : Math . max ( parentA . frictionStatic , parentB . frictionStatic ) ,
restitution : Math . max ( parentA . restitution , parentB . restitution ) ,
slop : Math . max ( parentA . slop , parentB . slop )
2014-03-24 16:11:42 -04:00
} ;
Pair . update ( pair , collision , timestamp ) ;
return pair ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Updates a pair given a collision .
2014-03-24 16:11:42 -04:00
* @ method update
* @ param { pair } pair
* @ param { collision } collision
2015-06-29 15:58:24 -04:00
* @ param { number } timestamp
2014-03-24 16:11:42 -04:00
* /
Pair . update = function ( pair , collision , timestamp ) {
var contacts = pair . contacts ,
supports = collision . supports ,
2015-05-20 15:38:41 -04:00
activeContacts = pair . activeContacts ,
parentA = collision . parentA ,
parentB = collision . parentB ;
2014-03-24 16:11:42 -04:00
pair . collision = collision ;
2015-05-20 15:38:41 -04:00
pair . inverseMass = parentA . inverseMass + parentB . inverseMass ;
pair . friction = Math . min ( parentA . friction , parentB . friction ) ;
pair . frictionStatic = Math . max ( parentA . frictionStatic , parentB . frictionStatic ) ;
pair . restitution = Math . max ( parentA . restitution , parentB . restitution ) ;
pair . slop = Math . max ( parentA . slop , parentB . slop ) ;
2014-03-24 16:11:42 -04:00
activeContacts . length = 0 ;
if ( collision . collided ) {
for ( var i = 0 ; i < supports . length ; i ++ ) {
var support = supports [ i ] ,
2014-03-30 14:45:30 -04:00
contactId = Contact . id ( support ) ,
contact = contacts [ contactId ] ;
2014-03-24 16:11:42 -04:00
2014-03-30 14:45:30 -04:00
if ( contact ) {
activeContacts . push ( contact ) ;
2014-03-24 16:11:42 -04:00
} else {
activeContacts . push ( contacts [ contactId ] = Contact . create ( support ) ) ;
}
}
pair . separation = collision . depth ;
Pair . setActive ( pair , true , timestamp ) ;
} else {
if ( pair . isActive === true )
Pair . setActive ( pair , false , timestamp ) ;
}
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Set a pair as active or inactive .
2014-03-24 16:11:42 -04:00
* @ method setActive
* @ param { pair } pair
* @ param { bool } isActive
2015-06-29 15:58:24 -04:00
* @ param { number } timestamp
2014-03-24 16:11:42 -04:00
* /
Pair . setActive = function ( pair , isActive , timestamp ) {
if ( isActive ) {
pair . isActive = true ;
pair . timeUpdated = timestamp ;
} else {
pair . isActive = false ;
pair . activeContacts . length = 0 ;
}
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Get the id for the given pair .
2014-03-24 16:11:42 -04:00
* @ method id
* @ param { body } bodyA
* @ param { body } bodyB
2015-01-01 18:10:10 -05:00
* @ return { string } Unique pairId
2014-03-24 16:11:42 -04:00
* /
Pair . id = function ( bodyA , bodyB ) {
if ( bodyA . id < bodyB . id ) {
return bodyA . id + '_' + bodyB . id ;
} else {
return bodyB . id + '_' + bodyA . id ;
}
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "./Contact" : 4 } ] , 8 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Pairs ` module contains methods for creating and manipulating collision pair sets .
2014-02-28 20:10:08 -05:00
*
2014-03-24 16:11:42 -04:00
* @ class Pairs
2014-02-28 20:10:08 -05:00
* /
2014-03-24 16:11:42 -04:00
var Pairs = { } ;
2014-02-19 09:15:05 -05:00
2015-08-17 18:50:03 -04:00
module . exports = Pairs ;
var Pair = require ( './Pair' ) ;
var Common = require ( '../core/Common' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-03-11 06:29:14 -04:00
var _pairMaxIdleLife = 1000 ;
2014-02-19 09:15:05 -05:00
2014-03-24 16:11:42 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a new pairs structure .
2014-03-24 16:11:42 -04:00
* @ method create
* @ param { object } options
* @ return { pairs } A new pairs structure
* /
Pairs . create = function ( options ) {
return Common . extend ( {
table : { } ,
list : [ ] ,
collisionStart : [ ] ,
collisionActive : [ ] ,
collisionEnd : [ ]
} , options ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Updates pairs given a list of collisions .
2014-03-24 16:11:42 -04:00
* @ method update
2014-02-28 20:10:08 -05:00
* @ param { object } pairs
2014-03-11 06:29:14 -04:00
* @ param { collision [ ] } collisions
2015-06-29 15:58:24 -04:00
* @ param { number } timestamp
2014-02-28 20:10:08 -05:00
* /
2014-03-24 16:11:42 -04:00
Pairs . update = function ( pairs , collisions , timestamp ) {
2014-03-11 06:29:14 -04:00
var pairsList = pairs . list ,
pairsTable = pairs . table ,
collisionStart = pairs . collisionStart ,
collisionEnd = pairs . collisionEnd ,
collisionActive = pairs . collisionActive ,
activePairIds = [ ] ,
collision ,
pairId ,
pair ,
i ;
2014-02-19 09:15:05 -05:00
2014-03-11 06:29:14 -04:00
// clear collision state arrays, but maintain old reference
collisionStart . length = 0 ;
collisionEnd . length = 0 ;
collisionActive . length = 0 ;
2014-02-19 09:15:05 -05:00
for ( i = 0 ; i < collisions . length ; i ++ ) {
2014-03-11 06:29:14 -04:00
collision = collisions [ i ] ;
if ( collision . collided ) {
2014-02-19 09:15:05 -05:00
pairId = Pair . id ( collision . bodyA , collision . bodyB ) ;
2014-03-11 06:29:14 -04:00
activePairIds . push ( pairId ) ;
2014-03-30 14:45:30 -04:00
pair = pairsTable [ pairId ] ;
2014-03-11 06:29:14 -04:00
2014-03-30 14:45:30 -04:00
if ( pair ) {
2014-03-11 06:29:14 -04:00
// pair already exists (but may or may not be active)
if ( pair . isActive ) {
// pair exists and is active
collisionActive . push ( pair ) ;
} else {
// pair exists but was inactive, so a collision has just started again
collisionStart . push ( pair ) ;
}
// update the pair
2014-03-22 13:51:49 -04:00
Pair . update ( pair , collision , timestamp ) ;
2014-03-11 06:29:14 -04:00
} else {
// pair did not exist, create a new pair
2014-03-22 13:51:49 -04:00
pair = Pair . create ( collision , timestamp ) ;
2014-03-11 06:29:14 -04:00
pairsTable [ pairId ] = pair ;
// push the new pair
collisionStart . push ( pair ) ;
pairsList . push ( pair ) ;
}
}
}
// deactivate previously active pairs that are now inactive
for ( i = 0 ; i < pairsList . length ; i ++ ) {
pair = pairsList [ i ] ;
2014-07-29 11:26:49 -04:00
if ( pair . isActive && Common . indexOf ( activePairIds , pair . id ) === - 1 ) {
2014-03-22 13:51:49 -04:00
Pair . setActive ( pair , false , timestamp ) ;
2014-03-11 06:29:14 -04:00
collisionEnd . push ( pair ) ;
2014-02-19 09:15:05 -05:00
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Finds and removes pairs that have been inactive for a set amount of time .
2014-03-24 16:11:42 -04:00
* @ method removeOld
2014-02-28 20:10:08 -05:00
* @ param { object } pairs
2015-06-29 15:58:24 -04:00
* @ param { number } timestamp
2014-02-28 20:10:08 -05:00
* /
2014-03-24 16:11:42 -04:00
Pairs . removeOld = function ( pairs , timestamp ) {
2014-03-11 06:29:14 -04:00
var pairsList = pairs . list ,
pairsTable = pairs . table ,
indexesToRemove = [ ] ,
pair ,
collision ,
pairIndex ,
2014-02-19 09:15:05 -05:00
i ;
2014-03-11 06:29:14 -04:00
2014-02-19 09:15:05 -05:00
for ( i = 0 ; i < pairsList . length ; i ++ ) {
2014-03-11 06:29:14 -04:00
pair = pairsList [ i ] ;
collision = pair . collision ;
2014-02-19 09:15:05 -05:00
// never remove sleeping pairs
if ( collision . bodyA . isSleeping || collision . bodyB . isSleeping ) {
2014-03-22 13:51:49 -04:00
pair . timeUpdated = timestamp ;
2014-02-19 09:15:05 -05:00
continue ;
}
2014-03-11 06:29:14 -04:00
// if pair is inactive for too long, mark it to be removed
2014-03-22 13:51:49 -04:00
if ( timestamp - pair . timeUpdated > _pairMaxIdleLife ) {
2014-03-11 06:29:14 -04:00
indexesToRemove . push ( i ) ;
2014-02-19 09:15:05 -05:00
}
}
2014-03-11 06:29:14 -04:00
// remove marked pairs
for ( i = 0 ; i < indexesToRemove . length ; i ++ ) {
2014-03-22 13:51:49 -04:00
pairIndex = indexesToRemove [ i ] - i ;
2014-03-11 06:29:14 -04:00
pair = pairsList [ pairIndex ] ;
delete pairsTable [ pair . id ] ;
pairsList . splice ( pairIndex , 1 ) ;
}
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Clears the given pairs structure .
2015-06-29 15:58:24 -04:00
* @ method clear
2014-03-24 16:11:42 -04:00
* @ param { pairs } pairs
2015-06-29 15:58:24 -04:00
* @ return { pairs } pairs
2014-03-24 16:11:42 -04:00
* /
Pairs . clear = function ( pairs ) {
pairs . table = { } ;
pairs . list . length = 0 ;
pairs . collisionStart . length = 0 ;
pairs . collisionActive . length = 0 ;
pairs . collisionEnd . length = 0 ;
return pairs ;
2014-02-19 09:15:05 -05:00
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "./Pair" : 7 } ] , 9 : [ function ( require , module , exports ) {
2014-05-01 09:09:06 -04:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Query ` module contains methods for performing collision queries .
2014-05-01 09:09:06 -04:00
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
*
2014-05-01 09:09:06 -04:00
* @ class Query
* /
var Query = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Query ;
var Vector = require ( '../geometry/Vector' ) ;
var SAT = require ( './SAT' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
var Bodies = require ( '../factory/Bodies' ) ;
var Vertices = require ( '../geometry/Vertices' ) ;
2014-05-01 09:09:06 -04:00
( function ( ) {
/ * *
* Casts a ray segment against a set of bodies and returns all collisions , ray width is optional . Intersection points are not provided .
* @ method ray
* @ param { body [ ] } bodies
* @ param { vector } startPoint
* @ param { vector } endPoint
2014-06-09 14:40:24 -04:00
* @ param { number } [ rayWidth ]
2014-05-01 09:09:06 -04:00
* @ return { object [ ] } Collisions
* /
Query . ray = function ( bodies , startPoint , endPoint , rayWidth ) {
2015-05-20 15:38:41 -04:00
rayWidth = rayWidth || 1e-100 ;
2014-05-01 09:09:06 -04:00
var rayAngle = Vector . angle ( startPoint , endPoint ) ,
rayLength = Vector . magnitude ( Vector . sub ( startPoint , endPoint ) ) ,
rayX = ( endPoint . x + startPoint . x ) * 0.5 ,
rayY = ( endPoint . y + startPoint . y ) * 0.5 ,
ray = Bodies . rectangle ( rayX , rayY , rayLength , rayWidth , { angle : rayAngle } ) ,
collisions = [ ] ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var bodyA = bodies [ i ] ;
2015-05-20 15:38:41 -04:00
2014-05-01 09:09:06 -04:00
if ( Bounds . overlaps ( bodyA . bounds , ray . bounds ) ) {
2015-05-20 15:38:41 -04:00
for ( var j = bodyA . parts . length === 1 ? 0 : 1 ; j < bodyA . parts . length ; j ++ ) {
var part = bodyA . parts [ j ] ;
if ( Bounds . overlaps ( part . bounds , ray . bounds ) ) {
var collision = SAT . collides ( part , ray ) ;
if ( collision . collided ) {
collision . body = collision . bodyA = collision . bodyB = bodyA ;
collisions . push ( collision ) ;
break ;
}
}
2014-05-01 09:09:06 -04:00
}
}
}
return collisions ;
} ;
/ * *
2014-06-09 14:40:24 -04:00
* Returns all bodies whose bounds are inside ( or outside if set ) the given set of bounds , from the given set of bodies .
2014-05-01 09:09:06 -04:00
* @ method region
* @ param { body [ ] } bodies
* @ param { bounds } bounds
2014-06-09 14:40:24 -04:00
* @ param { bool } [ outside = false ]
2014-05-01 09:09:06 -04:00
* @ return { body [ ] } The bodies matching the query
* /
Query . region = function ( bodies , bounds , outside ) {
var result = [ ] ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ,
overlaps = Bounds . overlaps ( body . bounds , bounds ) ;
if ( ( overlaps && ! outside ) || ( ! overlaps && outside ) )
result . push ( body ) ;
}
return result ;
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Returns all bodies whose vertices contain the given point , from the given set of bodies .
* @ method point
* @ param { body [ ] } bodies
* @ param { vector } point
* @ return { body [ ] } The bodies matching the query
* /
Query . point = function ( bodies , point ) {
var result = [ ] ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
if ( Bounds . contains ( body . bounds , point ) ) {
for ( var j = body . parts . length === 1 ? 0 : 1 ; j < body . parts . length ; j ++ ) {
var part = body . parts [ j ] ;
if ( Bounds . contains ( part . bounds , point )
&& Vertices . contains ( part . vertices , point ) ) {
result . push ( body ) ;
break ;
}
}
}
}
return result ;
} ;
2014-05-01 09:09:06 -04:00
} ) ( ) ;
2016-01-16 17:43:32 -05:00
2015-08-17 18:50:03 -04:00
} , { "../factory/Bodies" : 21 , "../geometry/Bounds" : 24 , "../geometry/Vector" : 26 , "../geometry/Vertices" : 27 , "./SAT" : 11 } ] , 10 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Resolver ` module contains methods for resolving collision pairs .
2014-02-28 20:10:08 -05:00
*
* @ class Resolver
* /
2014-02-19 09:15:05 -05:00
var Resolver = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Resolver ;
var Vertices = require ( '../geometry/Vertices' ) ;
var Vector = require ( '../geometry/Vector' ) ;
var Common = require ( '../core/Common' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2015-05-20 15:38:41 -04:00
Resolver . _restingThresh = 4 ;
2015-12-23 08:08:54 -05:00
Resolver . _restingThreshTangent = 6 ;
2015-05-20 15:38:41 -04:00
Resolver . _positionDampen = 0.9 ;
Resolver . _positionWarming = 0.8 ;
Resolver . _frictionNormalMultiplier = 5 ;
/ * *
2016-01-16 17:43:32 -05:00
* Prepare pairs for position solving .
2015-05-20 15:38:41 -04:00
* @ method preSolvePosition
* @ param { pair [ ] } pairs
* /
Resolver . preSolvePosition = function ( pairs ) {
var i ,
pair ,
activeCount ;
// find total contacts on each body
for ( i = 0 ; i < pairs . length ; i ++ ) {
pair = pairs [ i ] ;
if ( ! pair . isActive )
continue ;
activeCount = pair . activeContacts . length ;
pair . collision . parentA . totalContacts += activeCount ;
pair . collision . parentB . totalContacts += activeCount ;
}
} ;
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Find a solution for pair positions .
2014-02-28 20:10:08 -05:00
* @ method solvePosition
* @ param { pair [ ] } pairs
2014-05-01 09:09:06 -04:00
* @ param { number } timeScale
2014-02-28 20:10:08 -05:00
* /
2014-05-01 09:09:06 -04:00
Resolver . solvePosition = function ( pairs , timeScale ) {
2014-02-19 09:15:05 -05:00
var i ,
pair ,
collision ,
bodyA ,
bodyB ,
normal ,
2015-05-20 15:38:41 -04:00
bodyBtoA ,
contactShare ,
2015-07-02 15:17:03 -04:00
positionImpulse ,
2015-05-20 15:38:41 -04:00
contactCount = { } ,
tempA = Vector . _temp [ 0 ] ,
tempB = Vector . _temp [ 1 ] ,
tempC = Vector . _temp [ 2 ] ,
tempD = Vector . _temp [ 3 ] ;
2014-02-19 09:15:05 -05:00
// find impulses required to resolve penetration
for ( i = 0 ; i < pairs . length ; i ++ ) {
pair = pairs [ i ] ;
2016-04-07 15:03:37 -04:00
if ( ! pair . isActive || pair . isSensor )
2014-02-19 09:15:05 -05:00
continue ;
2016-04-07 15:03:37 -04:00
2014-02-19 09:15:05 -05:00
collision = pair . collision ;
2015-05-20 15:38:41 -04:00
bodyA = collision . parentA ;
bodyB = collision . parentB ;
2014-02-19 09:15:05 -05:00
normal = collision . normal ;
// get current separation between body edges involved in collision
2015-05-20 15:38:41 -04:00
bodyBtoA = Vector . sub ( Vector . add ( bodyB . positionImpulse , bodyB . position , tempA ) ,
Vector . add ( bodyA . positionImpulse ,
Vector . sub ( bodyB . position , collision . penetration , tempB ) , tempC ) , tempD ) ;
2014-02-19 09:15:05 -05:00
pair . separation = Vector . dot ( normal , bodyBtoA ) ;
}
for ( i = 0 ; i < pairs . length ; i ++ ) {
pair = pairs [ i ] ;
2015-05-20 15:38:41 -04:00
2016-04-07 15:03:37 -04:00
if ( ! pair . isActive || pair . isSensor || pair . separation < 0 )
2014-02-19 09:15:05 -05:00
continue ;
collision = pair . collision ;
2015-05-20 15:38:41 -04:00
bodyA = collision . parentA ;
bodyB = collision . parentB ;
2014-02-19 09:15:05 -05:00
normal = collision . normal ;
2015-05-20 15:38:41 -04:00
positionImpulse = ( pair . separation - pair . slop ) * timeScale ;
2016-04-07 15:03:37 -04:00
2014-02-19 09:15:05 -05:00
if ( bodyA . isStatic || bodyB . isStatic )
positionImpulse *= 2 ;
if ( ! ( bodyA . isStatic || bodyA . isSleeping ) ) {
2015-05-20 15:38:41 -04:00
contactShare = Resolver . _positionDampen / bodyA . totalContacts ;
bodyA . positionImpulse . x += normal . x * positionImpulse * contactShare ;
bodyA . positionImpulse . y += normal . y * positionImpulse * contactShare ;
2014-02-19 09:15:05 -05:00
}
if ( ! ( bodyB . isStatic || bodyB . isSleeping ) ) {
2015-05-20 15:38:41 -04:00
contactShare = Resolver . _positionDampen / bodyB . totalContacts ;
bodyB . positionImpulse . x -= normal . x * positionImpulse * contactShare ;
bodyB . positionImpulse . y -= normal . y * positionImpulse * contactShare ;
2014-02-19 09:15:05 -05:00
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Apply position resolution .
2014-02-28 20:10:08 -05:00
* @ method postSolvePosition
* @ param { body [ ] } bodies
* /
2014-02-19 09:15:05 -05:00
Resolver . postSolvePosition = function ( bodies ) {
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
2015-05-20 15:38:41 -04:00
// reset contact count
body . totalContacts = 0 ;
2014-02-19 09:15:05 -05:00
if ( body . positionImpulse . x !== 0 || body . positionImpulse . y !== 0 ) {
2015-05-20 15:38:41 -04:00
// update body geometry
for ( var j = 0 ; j < body . parts . length ; j ++ ) {
var part = body . parts [ j ] ;
Vertices . translate ( part . vertices , body . positionImpulse ) ;
Bounds . update ( part . bounds , part . vertices , body . velocity ) ;
part . position . x += body . positionImpulse . x ;
part . position . y += body . positionImpulse . y ;
}
2014-02-19 09:15:05 -05:00
// move the body without changing velocity
body . positionPrev . x += body . positionImpulse . x ;
body . positionPrev . y += body . positionImpulse . y ;
2015-05-20 15:38:41 -04:00
if ( Vector . dot ( body . positionImpulse , body . velocity ) < 0 ) {
// reset cached impulse if the body has velocity along it
body . positionImpulse . x = 0 ;
body . positionImpulse . y = 0 ;
} else {
// warm the next iteration
body . positionImpulse . x *= Resolver . _positionWarming ;
body . positionImpulse . y *= Resolver . _positionWarming ;
}
2014-02-19 09:15:05 -05:00
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Prepare pairs for velocity solving .
2014-02-28 20:10:08 -05:00
* @ method preSolveVelocity
* @ param { pair [ ] } pairs
* /
2014-02-19 09:15:05 -05:00
Resolver . preSolveVelocity = function ( pairs ) {
2015-05-20 15:38:41 -04:00
var i ,
2014-02-19 09:15:05 -05:00
j ,
pair ,
contacts ,
collision ,
bodyA ,
bodyB ,
normal ,
tangent ,
contact ,
contactVertex ,
normalImpulse ,
tangentImpulse ,
2015-05-20 15:38:41 -04:00
offset ,
impulse = Vector . _temp [ 0 ] ,
tempA = Vector . _temp [ 1 ] ;
2014-02-19 09:15:05 -05:00
for ( i = 0 ; i < pairs . length ; i ++ ) {
pair = pairs [ i ] ;
2016-04-07 15:03:37 -04:00
if ( ! pair . isActive || pair . isSensor )
2014-02-19 09:15:05 -05:00
continue ;
contacts = pair . activeContacts ;
collision = pair . collision ;
2015-05-20 15:38:41 -04:00
bodyA = collision . parentA ;
bodyB = collision . parentB ;
2014-02-19 09:15:05 -05:00
normal = collision . normal ;
tangent = collision . tangent ;
2016-04-07 15:03:37 -04:00
2014-02-19 09:15:05 -05:00
// resolve each contact
for ( j = 0 ; j < contacts . length ; j ++ ) {
contact = contacts [ j ] ;
contactVertex = contact . vertex ;
normalImpulse = contact . normalImpulse ;
tangentImpulse = contact . tangentImpulse ;
2015-05-20 15:38:41 -04:00
if ( normalImpulse !== 0 || tangentImpulse !== 0 ) {
// total impulse from contact
impulse . x = ( normal . x * normalImpulse ) + ( tangent . x * tangentImpulse ) ;
impulse . y = ( normal . y * normalImpulse ) + ( tangent . y * tangentImpulse ) ;
// apply impulse from contact
if ( ! ( bodyA . isStatic || bodyA . isSleeping ) ) {
offset = Vector . sub ( contactVertex , bodyA . position , tempA ) ;
bodyA . positionPrev . x += impulse . x * bodyA . inverseMass ;
bodyA . positionPrev . y += impulse . y * bodyA . inverseMass ;
bodyA . anglePrev += Vector . cross ( offset , impulse ) * bodyA . inverseInertia ;
}
if ( ! ( bodyB . isStatic || bodyB . isSleeping ) ) {
offset = Vector . sub ( contactVertex , bodyB . position , tempA ) ;
bodyB . positionPrev . x -= impulse . x * bodyB . inverseMass ;
bodyB . positionPrev . y -= impulse . y * bodyB . inverseMass ;
bodyB . anglePrev -= Vector . cross ( offset , impulse ) * bodyB . inverseInertia ;
}
2014-02-19 09:15:05 -05:00
}
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Find a solution for pair velocities .
2014-02-28 20:10:08 -05:00
* @ method solveVelocity
* @ param { pair [ ] } pairs
2015-06-29 15:58:24 -04:00
* @ param { number } timeScale
2014-02-28 20:10:08 -05:00
* /
2014-05-05 14:32:51 -04:00
Resolver . solveVelocity = function ( pairs , timeScale ) {
2015-05-20 15:38:41 -04:00
var timeScaleSquared = timeScale * timeScale ,
impulse = Vector . _temp [ 0 ] ,
tempA = Vector . _temp [ 1 ] ,
tempB = Vector . _temp [ 2 ] ,
tempC = Vector . _temp [ 3 ] ,
tempD = Vector . _temp [ 4 ] ,
tempE = Vector . _temp [ 5 ] ;
2014-02-19 09:15:05 -05:00
for ( var i = 0 ; i < pairs . length ; i ++ ) {
var pair = pairs [ i ] ;
2016-04-07 15:03:37 -04:00
if ( ! pair . isActive || pair . isSensor )
2014-02-19 09:15:05 -05:00
continue ;
var collision = pair . collision ,
2015-05-20 15:38:41 -04:00
bodyA = collision . parentA ,
bodyB = collision . parentB ,
2014-02-19 09:15:05 -05:00
normal = collision . normal ,
tangent = collision . tangent ,
contacts = pair . activeContacts ,
contactShare = 1 / contacts . length ;
// update body velocities
bodyA . velocity . x = bodyA . position . x - bodyA . positionPrev . x ;
bodyA . velocity . y = bodyA . position . y - bodyA . positionPrev . y ;
bodyB . velocity . x = bodyB . position . x - bodyB . positionPrev . x ;
bodyB . velocity . y = bodyB . position . y - bodyB . positionPrev . y ;
bodyA . angularVelocity = bodyA . angle - bodyA . anglePrev ;
bodyB . angularVelocity = bodyB . angle - bodyB . anglePrev ;
// resolve each contact
for ( var j = 0 ; j < contacts . length ; j ++ ) {
var contact = contacts [ j ] ,
contactVertex = contact . vertex ,
2015-05-20 15:38:41 -04:00
offsetA = Vector . sub ( contactVertex , bodyA . position , tempA ) ,
offsetB = Vector . sub ( contactVertex , bodyB . position , tempB ) ,
velocityPointA = Vector . add ( bodyA . velocity , Vector . mult ( Vector . perp ( offsetA ) , bodyA . angularVelocity ) , tempC ) ,
velocityPointB = Vector . add ( bodyB . velocity , Vector . mult ( Vector . perp ( offsetB ) , bodyB . angularVelocity ) , tempD ) ,
relativeVelocity = Vector . sub ( velocityPointA , velocityPointB , tempE ) ,
2014-02-19 09:15:05 -05:00
normalVelocity = Vector . dot ( normal , relativeVelocity ) ;
var tangentVelocity = Vector . dot ( tangent , relativeVelocity ) ,
tangentSpeed = Math . abs ( tangentVelocity ) ,
tangentVelocityDirection = Common . sign ( tangentVelocity ) ;
// raw impulses
var normalImpulse = ( 1 + pair . restitution ) * normalVelocity ,
2015-05-20 15:38:41 -04:00
normalForce = Common . clamp ( pair . separation + normalVelocity , 0 , 1 ) * Resolver . _frictionNormalMultiplier ;
2014-02-19 09:15:05 -05:00
// coulomb friction
2015-05-20 15:38:41 -04:00
var tangentImpulse = tangentVelocity ,
maxFriction = Infinity ;
if ( tangentSpeed > pair . friction * pair . frictionStatic * normalForce * timeScaleSquared ) {
maxFriction = tangentSpeed ;
2015-12-23 08:08:54 -05:00
tangentImpulse = Common . clamp (
pair . friction * tangentVelocityDirection * timeScaleSquared ,
- maxFriction , maxFriction
) ;
2015-05-20 15:38:41 -04:00
}
2014-02-19 09:15:05 -05:00
// modify impulses accounting for mass, inertia and offset
var oAcN = Vector . cross ( offsetA , normal ) ,
oBcN = Vector . cross ( offsetB , normal ) ,
2015-12-23 08:08:54 -05:00
share = contactShare / ( bodyA . inverseMass + bodyB . inverseMass + bodyA . inverseInertia * oAcN * oAcN + bodyB . inverseInertia * oBcN * oBcN ) ;
2015-05-20 15:38:41 -04:00
2015-12-23 08:08:54 -05:00
normalImpulse *= share ;
tangentImpulse *= share ;
2015-05-20 15:38:41 -04:00
2014-02-19 09:15:05 -05:00
// handle high velocity and resting collisions separately
2015-05-20 15:38:41 -04:00
if ( normalVelocity < 0 && normalVelocity * normalVelocity > Resolver . _restingThresh * timeScaleSquared ) {
2015-12-23 08:08:54 -05:00
// high normal velocity so clear cached contact normal impulse
2014-02-19 09:15:05 -05:00
contact . normalImpulse = 0 ;
} else {
// solve resting collision constraints using Erin Catto's method (GDC08)
2015-12-23 08:08:54 -05:00
// impulse constraint tends to 0
2014-02-19 09:15:05 -05:00
var contactNormalImpulse = contact . normalImpulse ;
contact . normalImpulse = Math . min ( contact . normalImpulse + normalImpulse , 0 ) ;
normalImpulse = contact . normalImpulse - contactNormalImpulse ;
2015-12-23 08:08:54 -05:00
}
// handle high velocity and resting collisions separately
if ( tangentVelocity * tangentVelocity > Resolver . _restingThreshTangent * timeScaleSquared ) {
// high tangent velocity so clear cached contact tangent impulse
contact . tangentImpulse = 0 ;
} else {
// solve resting collision constraints using Erin Catto's method (GDC08)
// tangent impulse tends to -tangentSpeed or +tangentSpeed
2014-02-19 09:15:05 -05:00
var contactTangentImpulse = contact . tangentImpulse ;
2015-05-20 15:38:41 -04:00
contact . tangentImpulse = Common . clamp ( contact . tangentImpulse + tangentImpulse , - maxFriction , maxFriction ) ;
2014-02-19 09:15:05 -05:00
tangentImpulse = contact . tangentImpulse - contactTangentImpulse ;
}
2015-12-23 08:08:54 -05:00
2014-02-19 09:15:05 -05:00
// total impulse from contact
impulse . x = ( normal . x * normalImpulse ) + ( tangent . x * tangentImpulse ) ;
impulse . y = ( normal . y * normalImpulse ) + ( tangent . y * tangentImpulse ) ;
// apply impulse from contact
if ( ! ( bodyA . isStatic || bodyA . isSleeping ) ) {
bodyA . positionPrev . x += impulse . x * bodyA . inverseMass ;
bodyA . positionPrev . y += impulse . y * bodyA . inverseMass ;
bodyA . anglePrev += Vector . cross ( offsetA , impulse ) * bodyA . inverseInertia ;
}
if ( ! ( bodyB . isStatic || bodyB . isSleeping ) ) {
bodyB . positionPrev . x -= impulse . x * bodyB . inverseMass ;
bodyB . positionPrev . y -= impulse . y * bodyB . inverseMass ;
bodyB . anglePrev -= Vector . cross ( offsetB , impulse ) * bodyB . inverseInertia ;
}
}
}
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "../geometry/Bounds" : 24 , "../geometry/Vector" : 26 , "../geometry/Vertices" : 27 } ] , 11 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.SAT ` module contains methods for detecting collisions using the Separating Axis Theorem .
2014-02-28 20:10:08 -05:00
*
* @ class SAT
* /
2014-02-19 09:15:05 -05:00
// TODO: true circles and curves
var SAT = { } ;
2015-08-17 18:50:03 -04:00
module . exports = SAT ;
var Vertices = require ( '../geometry/Vertices' ) ;
var Vector = require ( '../geometry/Vector' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Detect collision between two bodies using the Separating Axis Theorem .
2014-02-28 20:10:08 -05:00
* @ method collides
* @ param { body } bodyA
* @ param { body } bodyB
2014-03-22 13:51:49 -04:00
* @ param { collision } previousCollision
2014-02-28 20:10:08 -05:00
* @ return { collision } collision
* /
2014-03-22 13:51:49 -04:00
SAT . collides = function ( bodyA , bodyB , previousCollision ) {
2014-02-19 09:15:05 -05:00
var overlapAB ,
overlapBA ,
minOverlap ,
2014-03-22 13:51:49 -04:00
collision ,
prevCol = previousCollision ,
canReusePrevCol = false ;
if ( prevCol ) {
// estimate total motion
2015-05-20 15:38:41 -04:00
var parentA = bodyA . parent ,
parentB = bodyB . parent ,
motion = parentA . speed * parentA . speed + parentA . angularSpeed * parentA . angularSpeed
+ parentB . speed * parentB . speed + parentB . angularSpeed * parentB . angularSpeed ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
// we may be able to (partially) reuse collision result
// but only safe if collision was resting
canReusePrevCol = prevCol && prevCol . collided && motion < 0.2 ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
// reuse collision object
collision = prevCol ;
} else {
collision = { collided : false , bodyA : bodyA , bodyB : bodyB } ;
}
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( prevCol && canReusePrevCol ) {
// if we can reuse the collision result
// we only need to test the previously found axis
2015-05-20 15:38:41 -04:00
var axisBodyA = collision . axisBody ,
axisBodyB = axisBodyA === bodyA ? bodyB : bodyA ,
axes = [ axisBodyA . axes [ prevCol . axisNumber ] ] ;
2014-02-19 09:15:05 -05:00
2015-05-20 15:38:41 -04:00
minOverlap = _overlapAxes ( axisBodyA . vertices , axisBodyB . vertices , axes ) ;
2014-03-22 13:51:49 -04:00
collision . reused = true ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( minOverlap . overlap <= 0 ) {
collision . collided = false ;
return collision ;
}
2014-02-19 09:15:05 -05:00
} else {
2014-03-22 13:51:49 -04:00
// if we can't reuse a result, perform a full SAT test
overlapAB = _overlapAxes ( bodyA . vertices , bodyB . vertices , bodyA . axes ) ;
if ( overlapAB . overlap <= 0 ) {
collision . collided = false ;
return collision ;
}
overlapBA = _overlapAxes ( bodyB . vertices , bodyA . vertices , bodyB . axes ) ;
if ( overlapBA . overlap <= 0 ) {
collision . collided = false ;
return collision ;
}
if ( overlapAB . overlap < overlapBA . overlap ) {
minOverlap = overlapAB ;
2015-05-20 15:38:41 -04:00
collision . axisBody = bodyA ;
2014-03-22 13:51:49 -04:00
} else {
minOverlap = overlapBA ;
2015-05-20 15:38:41 -04:00
collision . axisBody = bodyB ;
2014-03-22 13:51:49 -04:00
}
// important for reuse later
collision . axisNumber = minOverlap . axisNumber ;
2014-02-19 09:15:05 -05:00
}
2015-05-20 15:38:41 -04:00
collision . bodyA = bodyA . id < bodyB . id ? bodyA : bodyB ;
collision . bodyB = bodyA . id < bodyB . id ? bodyB : bodyA ;
2014-02-19 09:15:05 -05:00
collision . collided = true ;
collision . normal = minOverlap . axis ;
collision . depth = minOverlap . overlap ;
2015-05-20 15:38:41 -04:00
collision . parentA = collision . bodyA . parent ;
collision . parentB = collision . bodyB . parent ;
2014-02-19 09:15:05 -05:00
bodyA = collision . bodyA ;
bodyB = collision . bodyB ;
// ensure normal is facing away from bodyA
if ( Vector . dot ( collision . normal , Vector . sub ( bodyB . position , bodyA . position ) ) > 0 )
collision . normal = Vector . neg ( collision . normal ) ;
collision . tangent = Vector . perp ( collision . normal ) ;
collision . penetration = {
x : collision . normal . x * collision . depth ,
y : collision . normal . y * collision . depth
} ;
// find support points, there is always either exactly one or two
var verticesB = _findSupports ( bodyA , bodyB , collision . normal ) ,
2014-07-29 11:26:49 -04:00
supports = collision . supports || [ ] ;
supports . length = 0 ;
// find the supports from bodyB that are inside bodyA
if ( Vertices . contains ( bodyA . vertices , verticesB [ 0 ] ) )
supports . push ( verticesB [ 0 ] ) ;
if ( Vertices . contains ( bodyA . vertices , verticesB [ 1 ] ) )
2014-02-19 09:15:05 -05:00
supports . push ( verticesB [ 1 ] ) ;
2014-07-29 11:26:49 -04:00
// find the supports from bodyA that are inside bodyB
if ( supports . length < 2 ) {
2014-02-19 09:15:05 -05:00
var verticesA = _findSupports ( bodyB , bodyA , Vector . neg ( collision . normal ) ) ;
2014-07-29 11:26:49 -04:00
if ( Vertices . contains ( bodyB . vertices , verticesA [ 0 ] ) )
2014-02-19 09:15:05 -05:00
supports . push ( verticesA [ 0 ] ) ;
2014-07-29 11:26:49 -04:00
if ( supports . length < 2 && Vertices . contains ( bodyB . vertices , verticesA [ 1 ] ) )
2014-02-19 09:15:05 -05:00
supports . push ( verticesA [ 1 ] ) ;
}
2014-07-29 11:26:49 -04:00
// account for the edge case of overlapping but no vertex containment
2015-05-20 15:38:41 -04:00
if ( supports . length < 1 )
2014-07-29 11:26:49 -04:00
supports = [ verticesB [ 0 ] ] ;
2014-02-19 09:15:05 -05:00
collision . supports = supports ;
return collision ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Find the overlap between two sets of vertices .
2014-02-28 20:10:08 -05:00
* @ method _overlapAxes
* @ private
* @ param { } verticesA
* @ param { } verticesB
* @ param { } axes
* @ return result
* /
2014-02-19 09:15:05 -05:00
var _overlapAxes = function ( verticesA , verticesB , axes ) {
2015-05-20 15:38:41 -04:00
var projectionA = Vector . _temp [ 0 ] ,
projectionB = Vector . _temp [ 1 ] ,
2014-02-19 09:15:05 -05:00
result = { overlap : Number . MAX _VALUE } ,
overlap ,
axis ;
for ( var i = 0 ; i < axes . length ; i ++ ) {
axis = axes [ i ] ;
_projectToAxis ( projectionA , verticesA , axis ) ;
_projectToAxis ( projectionB , verticesB , axis ) ;
2015-05-20 15:38:41 -04:00
overlap = Math . min ( projectionA . max - projectionB . min , projectionB . max - projectionA . min ) ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( overlap <= 0 ) {
result . overlap = overlap ;
return result ;
}
2014-02-19 09:15:05 -05:00
if ( overlap < result . overlap ) {
result . overlap = overlap ;
result . axis = axis ;
2014-03-22 13:51:49 -04:00
result . axisNumber = i ;
2014-02-19 09:15:05 -05:00
}
}
return result ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Projects vertices on an axis and returns an interval .
2014-02-28 20:10:08 -05:00
* @ method _projectToAxis
* @ private
* @ param { } projection
* @ param { } vertices
* @ param { } axis
* /
2014-02-19 09:15:05 -05:00
var _projectToAxis = function ( projection , vertices , axis ) {
var min = Vector . dot ( vertices [ 0 ] , axis ) ,
max = min ;
for ( var i = 1 ; i < vertices . length ; i += 1 ) {
var dot = Vector . dot ( vertices [ i ] , axis ) ;
if ( dot > max ) {
max = dot ;
} else if ( dot < min ) {
min = dot ;
}
}
projection . min = min ;
projection . max = max ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Finds supporting vertices given two bodies along a given direction using hill - climbing .
2014-02-28 20:10:08 -05:00
* @ method _findSupports
* @ private
* @ param { } bodyA
* @ param { } bodyB
* @ param { } normal
2016-01-16 17:43:32 -05:00
* @ return [ vector ]
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
var _findSupports = function ( bodyA , bodyB , normal ) {
var nearestDistance = Number . MAX _VALUE ,
2015-05-20 15:38:41 -04:00
vertexToBody = Vector . _temp [ 0 ] ,
2014-02-19 09:15:05 -05:00
vertices = bodyB . vertices ,
bodyAPosition = bodyA . position ,
distance ,
vertex ,
2015-05-20 15:38:41 -04:00
vertexA ,
vertexB ;
2014-02-19 09:15:05 -05:00
// find closest vertex on bodyB
for ( var i = 0 ; i < vertices . length ; i ++ ) {
vertex = vertices [ i ] ;
vertexToBody . x = vertex . x - bodyAPosition . x ;
vertexToBody . y = vertex . y - bodyAPosition . y ;
distance = - Vector . dot ( normal , vertexToBody ) ;
if ( distance < nearestDistance ) {
nearestDistance = distance ;
vertexA = vertex ;
}
}
// find next closest vertex using the two connected to it
var prevIndex = vertexA . index - 1 >= 0 ? vertexA . index - 1 : vertices . length - 1 ;
vertex = vertices [ prevIndex ] ;
vertexToBody . x = vertex . x - bodyAPosition . x ;
vertexToBody . y = vertex . y - bodyAPosition . y ;
nearestDistance = - Vector . dot ( normal , vertexToBody ) ;
vertexB = vertex ;
var nextIndex = ( vertexA . index + 1 ) % vertices . length ;
vertex = vertices [ nextIndex ] ;
vertexToBody . x = vertex . x - bodyAPosition . x ;
vertexToBody . y = vertex . y - bodyAPosition . y ;
distance = - Vector . dot ( normal , vertexToBody ) ;
if ( distance < nearestDistance ) {
vertexB = vertex ;
}
return [ vertexA , vertexB ] ;
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../geometry/Vector" : 26 , "../geometry/Vertices" : 27 } ] , 12 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Constraint ` module contains methods for creating and manipulating constraints .
* Constraints are used for specifying that a fixed distance must be maintained between two bodies ( or a body and a fixed world - space position ) .
* The stiffness of constraints can be modified to create springs or elastic .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class Constraint
* /
2015-06-29 15:58:24 -04:00
// TODO: fix instability issues with torque
2014-02-19 09:15:05 -05:00
// TODO: linked constraints
// TODO: breakable constraints
2015-06-29 15:58:24 -04:00
// TODO: collision constraints
2014-02-19 09:15:05 -05:00
// TODO: allow constrained bodies to sleep
// TODO: handle 0 length constraints properly
// TODO: impulse caching and warming
var Constraint = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Constraint ;
var Vertices = require ( '../geometry/Vertices' ) ;
var Vector = require ( '../geometry/Vector' ) ;
var Sleeping = require ( '../core/Sleeping' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
var Axes = require ( '../geometry/Axes' ) ;
var Common = require ( '../core/Common' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-03-22 13:51:49 -04:00
var _minLength = 0.000001 ,
2014-05-01 09:09:06 -04:00
_minDifference = 0.001 ;
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new constraint .
* All properties have default values , and many are pre - calculated automatically based on other properties .
2015-06-29 15:58:24 -04:00
* See the properties section below for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method create
* @ param { } options
* @ return { constraint } constraint
* /
2014-02-19 09:15:05 -05:00
Constraint . create = function ( options ) {
var constraint = options ;
// if bodies defined but no points, use body centre
if ( constraint . bodyA && ! constraint . pointA )
constraint . pointA = { x : 0 , y : 0 } ;
if ( constraint . bodyB && ! constraint . pointB )
constraint . pointB = { x : 0 , y : 0 } ;
// calculate static length using initial world space points
var initialPointA = constraint . bodyA ? Vector . add ( constraint . bodyA . position , constraint . pointA ) : constraint . pointA ,
initialPointB = constraint . bodyB ? Vector . add ( constraint . bodyB . position , constraint . pointB ) : constraint . pointB ,
length = Vector . magnitude ( Vector . sub ( initialPointA , initialPointB ) ) ;
constraint . length = constraint . length || length || _minLength ;
2014-03-22 13:51:49 -04:00
// render
var render = {
visible : true ,
lineWidth : 2 ,
strokeStyle : '#666'
} ;
constraint . render = Common . extend ( render , constraint . render ) ;
2014-02-19 09:15:05 -05:00
// option defaults
2014-05-01 09:09:06 -04:00
constraint . id = constraint . id || Common . nextId ( ) ;
constraint . label = constraint . label || 'Constraint' ;
2014-03-30 14:45:30 -04:00
constraint . type = 'constraint' ;
2014-02-19 09:15:05 -05:00
constraint . stiffness = constraint . stiffness || 1 ;
constraint . angularStiffness = constraint . angularStiffness || 0 ;
constraint . angleA = constraint . bodyA ? constraint . bodyA . angle : constraint . angleA ;
constraint . angleB = constraint . bodyB ? constraint . bodyB . angle : constraint . angleB ;
return constraint ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Solves all constraints in a list of collisions .
2014-06-09 14:40:24 -04:00
* @ private
2014-03-30 14:45:30 -04:00
* @ method solveAll
2014-02-28 20:10:08 -05:00
* @ param { constraint [ ] } constraints
2014-05-01 09:09:06 -04:00
* @ param { number } timeScale
2014-02-28 20:10:08 -05:00
* /
2014-05-01 09:09:06 -04:00
Constraint . solveAll = function ( constraints , timeScale ) {
2014-02-19 09:15:05 -05:00
for ( var i = 0 ; i < constraints . length ; i ++ ) {
2014-05-01 09:09:06 -04:00
Constraint . solve ( constraints [ i ] , timeScale ) ;
2014-02-19 09:15:05 -05:00
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Solves a distance constraint with Gauss - Siedel method .
2014-06-09 14:40:24 -04:00
* @ private
2014-03-30 14:45:30 -04:00
* @ method solve
2014-02-28 20:10:08 -05:00
* @ param { constraint } constraint
2014-05-01 09:09:06 -04:00
* @ param { number } timeScale
2014-02-28 20:10:08 -05:00
* /
2014-05-01 09:09:06 -04:00
Constraint . solve = function ( constraint , timeScale ) {
2014-02-19 09:15:05 -05:00
var bodyA = constraint . bodyA ,
bodyB = constraint . bodyB ,
pointA = constraint . pointA ,
pointB = constraint . pointB ;
// update reference angle
if ( bodyA && ! bodyA . isStatic ) {
constraint . pointA = Vector . rotate ( pointA , bodyA . angle - constraint . angleA ) ;
constraint . angleA = bodyA . angle ;
}
// update reference angle
if ( bodyB && ! bodyB . isStatic ) {
constraint . pointB = Vector . rotate ( pointB , bodyB . angle - constraint . angleB ) ;
constraint . angleB = bodyB . angle ;
}
var pointAWorld = pointA ,
pointBWorld = pointB ;
if ( bodyA ) pointAWorld = Vector . add ( bodyA . position , pointA ) ;
if ( bodyB ) pointBWorld = Vector . add ( bodyB . position , pointB ) ;
if ( ! pointAWorld || ! pointBWorld )
return ;
var delta = Vector . sub ( pointAWorld , pointBWorld ) ,
currentLength = Vector . magnitude ( delta ) ;
// prevent singularity
if ( currentLength === 0 )
currentLength = _minLength ;
// solve distance constraint with Gauss-Siedel method
var difference = ( currentLength - constraint . length ) / currentLength ,
normal = Vector . div ( delta , currentLength ) ,
2014-05-01 09:09:06 -04:00
force = Vector . mult ( delta , difference * 0.5 * constraint . stiffness * timeScale * timeScale ) ;
2014-04-01 08:47:17 -04:00
// if difference is very small, we can skip
2014-05-01 09:09:06 -04:00
if ( Math . abs ( 1 - ( currentLength / constraint . length ) ) < _minDifference * timeScale )
2014-04-01 08:47:17 -04:00
return ;
2014-02-19 09:15:05 -05:00
var velocityPointA ,
velocityPointB ,
offsetA ,
offsetB ,
oAn ,
oBn ,
bodyADenom ,
bodyBDenom ;
if ( bodyA && ! bodyA . isStatic ) {
// point body offset
offsetA = {
x : pointAWorld . x - bodyA . position . x + force . x ,
y : pointAWorld . y - bodyA . position . y + force . y
} ;
// update velocity
bodyA . velocity . x = bodyA . position . x - bodyA . positionPrev . x ;
bodyA . velocity . y = bodyA . position . y - bodyA . positionPrev . y ;
bodyA . angularVelocity = bodyA . angle - bodyA . anglePrev ;
// find point velocity and body mass
velocityPointA = Vector . add ( bodyA . velocity , Vector . mult ( Vector . perp ( offsetA ) , bodyA . angularVelocity ) ) ;
oAn = Vector . dot ( offsetA , normal ) ;
bodyADenom = bodyA . inverseMass + bodyA . inverseInertia * oAn * oAn ;
} else {
velocityPointA = { x : 0 , y : 0 } ;
bodyADenom = bodyA ? bodyA . inverseMass : 0 ;
}
if ( bodyB && ! bodyB . isStatic ) {
// point body offset
offsetB = {
x : pointBWorld . x - bodyB . position . x - force . x ,
y : pointBWorld . y - bodyB . position . y - force . y
} ;
// update velocity
bodyB . velocity . x = bodyB . position . x - bodyB . positionPrev . x ;
bodyB . velocity . y = bodyB . position . y - bodyB . positionPrev . y ;
bodyB . angularVelocity = bodyB . angle - bodyB . anglePrev ;
// find point velocity and body mass
velocityPointB = Vector . add ( bodyB . velocity , Vector . mult ( Vector . perp ( offsetB ) , bodyB . angularVelocity ) ) ;
oBn = Vector . dot ( offsetB , normal ) ;
bodyBDenom = bodyB . inverseMass + bodyB . inverseInertia * oBn * oBn ;
} else {
velocityPointB = { x : 0 , y : 0 } ;
bodyBDenom = bodyB ? bodyB . inverseMass : 0 ;
}
var relativeVelocity = Vector . sub ( velocityPointB , velocityPointA ) ,
normalImpulse = Vector . dot ( normal , relativeVelocity ) / ( bodyADenom + bodyBDenom ) ;
if ( normalImpulse > 0 ) normalImpulse = 0 ;
var normalVelocity = {
x : normal . x * normalImpulse ,
y : normal . y * normalImpulse
} ;
var torque ;
if ( bodyA && ! bodyA . isStatic ) {
torque = Vector . cross ( offsetA , normalVelocity ) * bodyA . inverseInertia * ( 1 - constraint . angularStiffness ) ;
2014-03-30 14:45:30 -04:00
// keep track of applied impulses for post solving
bodyA . constraintImpulse . x -= force . x ;
bodyA . constraintImpulse . y -= force . y ;
bodyA . constraintImpulse . angle += torque ;
2014-02-19 09:15:05 -05:00
// apply forces
bodyA . position . x -= force . x ;
bodyA . position . y -= force . y ;
bodyA . angle += torque ;
}
if ( bodyB && ! bodyB . isStatic ) {
torque = Vector . cross ( offsetB , normalVelocity ) * bodyB . inverseInertia * ( 1 - constraint . angularStiffness ) ;
2014-03-30 14:45:30 -04:00
// keep track of applied impulses for post solving
bodyB . constraintImpulse . x += force . x ;
bodyB . constraintImpulse . y += force . y ;
bodyB . constraintImpulse . angle -= torque ;
2014-02-19 09:15:05 -05:00
// apply forces
bodyB . position . x += force . x ;
bodyB . position . y += force . y ;
bodyB . angle -= torque ;
}
} ;
2014-03-30 14:45:30 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Performs body updates required after solving constraints .
2014-06-09 14:40:24 -04:00
* @ private
2014-03-30 14:45:30 -04:00
* @ method postSolveAll
* @ param { body [ ] } bodies
* /
Constraint . postSolveAll = function ( bodies ) {
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ,
impulse = body . constraintImpulse ;
2015-12-05 11:47:50 -05:00
if ( impulse . x === 0 && impulse . y === 0 && impulse . angle === 0 ) {
continue ;
}
2016-01-16 17:43:32 -05:00
Sleeping . set ( body , false ) ;
2014-04-01 08:47:17 -04:00
// update geometry and reset
2015-05-20 15:38:41 -04:00
for ( var j = 0 ; j < body . parts . length ; j ++ ) {
var part = body . parts [ j ] ;
Vertices . translate ( part . vertices , impulse ) ;
2014-04-01 08:47:17 -04:00
2015-05-20 15:38:41 -04:00
if ( j > 0 ) {
part . position . x += impulse . x ;
part . position . y += impulse . y ;
}
if ( impulse . angle !== 0 ) {
Vertices . rotate ( part . vertices , impulse . angle , body . position ) ;
Axes . rotate ( part . axes , impulse . angle ) ;
if ( j > 0 ) {
Vector . rotateAbout ( part . position , impulse . angle , body . position , part . position ) ;
}
}
2014-04-01 08:47:17 -04:00
2015-12-05 11:47:50 -05:00
Bounds . update ( part . bounds , part . vertices , body . velocity ) ;
2015-05-20 15:38:41 -04:00
}
2014-04-01 08:47:17 -04:00
2015-05-20 15:38:41 -04:00
impulse . angle = 0 ;
2014-04-01 08:47:17 -04:00
impulse . x = 0 ;
impulse . y = 0 ;
2014-03-30 14:45:30 -04:00
}
} ;
2014-06-09 14:40:24 -04:00
/ *
*
* Properties Documentation
*
* /
/ * *
* An integer ` Number ` uniquely identifying number generated in ` Composite.create ` by ` Common.nextId ` .
*
* @ property id
* @ type number
* /
/ * *
* A ` String ` denoting the type of object .
*
* @ property type
* @ type string
* @ default "constraint"
* /
/ * *
* An arbitrary ` String ` name to help the user identify and manage bodies .
*
* @ property label
* @ type string
* @ default "Constraint"
* /
/ * *
* An ` Object ` that defines the rendering properties to be consumed by the module ` Matter.Render ` .
*
* @ property render
* @ type object
* /
/ * *
* A flag that indicates if the constraint should be rendered .
*
* @ property render . visible
* @ type boolean
* @ default true
* /
/ * *
* A ` Number ` that defines the line width to use when rendering the constraint outline .
* A value of ` 0 ` means no outline will be rendered .
*
* @ property render . lineWidth
* @ type number
* @ default 2
* /
/ * *
* A ` String ` that defines the stroke style to use when rendering the constraint outline .
* It is the same as when using a canvas , so it accepts CSS style property values .
*
* @ property render . strokeStyle
* @ type string
* @ default a random colour
* /
/ * *
* The first possible ` Body ` that this constraint is attached to .
*
* @ property bodyA
* @ type body
* @ default null
* /
/ * *
* The second possible ` Body ` that this constraint is attached to .
*
* @ property bodyB
* @ type body
* @ default null
* /
/ * *
* A ` Vector ` that specifies the offset of the constraint from center of the ` constraint.bodyA ` if defined , otherwise a world - space position .
*
* @ property pointA
* @ type vector
* @ default { x : 0 , y : 0 }
* /
/ * *
* A ` Vector ` that specifies the offset of the constraint from center of the ` constraint.bodyA ` if defined , otherwise a world - space position .
*
* @ property pointB
* @ type vector
* @ default { x : 0 , y : 0 }
* /
/ * *
* A ` Number ` that specifies the stiffness of the constraint , i . e . the rate at which it returns to its resting ` constraint.length ` .
* A value of ` 1 ` means the constraint should be very stiff .
* A value of ` 0.2 ` means the constraint acts like a soft spring .
*
* @ property stiffness
* @ type number
* @ default 1
* /
/ * *
* A ` Number ` that specifies the target resting length of the constraint .
2015-06-29 15:58:24 -04:00
* It is calculated automatically in ` Constraint.create ` from initial positions of the ` constraint.bodyA ` and ` constraint.bodyB ` .
2014-06-09 14:40:24 -04:00
*
* @ property length
* @ type number
* /
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "../core/Sleeping" : 20 , "../geometry/Axes" : 23 , "../geometry/Bounds" : 24 , "../geometry/Vector" : 26 , "../geometry/Vertices" : 27 } ] , 13 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.MouseConstraint ` module contains methods for creating mouse constraints .
* Mouse constraints are used for allowing user interaction , providing the ability to move bodies via the mouse or touch .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class MouseConstraint
* /
2014-02-19 09:15:05 -05:00
var MouseConstraint = { } ;
2015-08-17 18:50:03 -04:00
module . exports = MouseConstraint ;
var Vertices = require ( '../geometry/Vertices' ) ;
var Sleeping = require ( '../core/Sleeping' ) ;
var Mouse = require ( '../core/Mouse' ) ;
var Events = require ( '../core/Events' ) ;
var Detector = require ( '../collision/Detector' ) ;
var Constraint = require ( './Constraint' ) ;
var Composite = require ( '../body/Composite' ) ;
var Common = require ( '../core/Common' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new mouse constraint .
* All properties have default values , and many are pre - calculated automatically based on other properties .
2015-06-29 15:58:24 -04:00
* See the properties section below for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method create
2014-03-30 14:45:30 -04:00
* @ param { engine } engine
* @ param { } options
2014-02-28 20:10:08 -05:00
* @ return { MouseConstraint } A new MouseConstraint
* /
2014-03-30 14:45:30 -04:00
MouseConstraint . create = function ( engine , options ) {
2015-01-20 19:15:04 -05:00
var mouse = ( engine ? engine . mouse : null ) || ( options ? options . mouse : null ) ;
2015-12-23 08:50:31 -05:00
if ( ! mouse ) {
if ( engine && engine . render && engine . render . canvas ) {
mouse = Mouse . create ( engine . render . canvas ) ;
} else {
mouse = Mouse . create ( ) ;
Common . log ( 'MouseConstraint.create: options.mouse was undefined, engine.render.canvas was undefined, may not function as expected' , 'warn' ) ;
}
2015-01-20 19:15:04 -05:00
}
2014-03-30 14:45:30 -04:00
2014-02-19 09:15:05 -05:00
var constraint = Constraint . create ( {
2014-05-01 09:09:06 -04:00
label : 'Mouse Constraint' ,
2014-02-19 09:15:05 -05:00
pointA : mouse . position ,
pointB : { x : 0 , y : 0 } ,
length : 0.01 ,
stiffness : 0.1 ,
angularStiffness : 1 ,
2014-03-22 13:51:49 -04:00
render : {
strokeStyle : '#90EE90' ,
lineWidth : 3
}
2014-02-19 09:15:05 -05:00
} ) ;
2014-03-30 14:45:30 -04:00
var defaults = {
type : 'mouseConstraint' ,
2014-02-19 09:15:05 -05:00
mouse : mouse ,
2014-12-02 16:40:34 -05:00
body : null ,
2014-07-29 11:26:49 -04:00
constraint : constraint ,
collisionFilter : {
category : 0x0001 ,
mask : 0xFFFFFFFF ,
group : 0
}
2014-02-19 09:15:05 -05:00
} ;
2014-03-30 14:45:30 -04:00
var mouseConstraint = Common . extend ( defaults , options ) ;
2015-01-01 18:10:10 -05:00
Events . on ( engine , 'tick' , function ( ) {
2014-03-30 14:45:30 -04:00
var allBodies = Composite . allBodies ( engine . world ) ;
MouseConstraint . update ( mouseConstraint , allBodies ) ;
2014-07-29 11:26:49 -04:00
_triggerEvents ( mouseConstraint ) ;
2014-03-30 14:45:30 -04:00
} ) ;
return mouseConstraint ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Updates the given mouse constraint .
* @ private
2014-02-28 20:10:08 -05:00
* @ method update
* @ param { MouseConstraint } mouseConstraint
* @ param { body [ ] } bodies
* /
2014-02-19 09:15:05 -05:00
MouseConstraint . update = function ( mouseConstraint , bodies ) {
var mouse = mouseConstraint . mouse ,
2014-12-02 16:40:34 -05:00
constraint = mouseConstraint . constraint ,
body = mouseConstraint . body ;
2014-02-19 09:15:05 -05:00
2014-03-24 16:11:42 -04:00
if ( mouse . button === 0 ) {
2014-02-19 09:15:05 -05:00
if ( ! constraint . bodyB ) {
for ( var i = 0 ; i < bodies . length ; i ++ ) {
2014-12-02 16:40:34 -05:00
body = bodies [ i ] ;
2014-02-19 09:15:05 -05:00
if ( Bounds . contains ( body . bounds , mouse . position )
2014-07-29 11:26:49 -04:00
&& Detector . canCollide ( body . collisionFilter , mouseConstraint . collisionFilter ) ) {
2015-05-20 15:38:41 -04:00
for ( var j = body . parts . length > 1 ? 1 : 0 ; j < body . parts . length ; j ++ ) {
var part = body . parts [ j ] ;
if ( Vertices . contains ( part . vertices , mouse . position ) ) {
constraint . pointA = mouse . position ;
constraint . bodyB = mouseConstraint . body = body ;
constraint . pointB = { x : mouse . position . x - body . position . x , y : mouse . position . y - body . position . y } ;
constraint . angleB = body . angle ;
Sleeping . set ( body , false ) ;
Events . trigger ( mouseConstraint , 'startdrag' , { mouse : mouse , body : body } ) ;
break ;
}
}
2014-02-19 09:15:05 -05:00
}
}
2014-12-02 16:40:34 -05:00
} else {
Sleeping . set ( constraint . bodyB , false ) ;
constraint . pointA = mouse . position ;
2014-02-19 09:15:05 -05:00
}
} else {
2014-12-02 16:40:34 -05:00
constraint . bodyB = mouseConstraint . body = null ;
2014-02-19 09:15:05 -05:00
constraint . pointB = null ;
2014-12-02 16:40:34 -05:00
if ( body )
Events . trigger ( mouseConstraint , 'enddrag' , { mouse : mouse , body : body } ) ;
2014-02-19 09:15:05 -05:00
}
} ;
2014-07-29 11:26:49 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Triggers mouse constraint events .
2014-07-29 11:26:49 -04:00
* @ method _triggerEvents
* @ private
2015-06-29 15:58:24 -04:00
* @ param { mouse } mouseConstraint
2014-07-29 11:26:49 -04:00
* /
var _triggerEvents = function ( mouseConstraint ) {
var mouse = mouseConstraint . mouse ,
mouseEvents = mouse . sourceEvents ;
if ( mouseEvents . mousemove )
Events . trigger ( mouseConstraint , 'mousemove' , { mouse : mouse } ) ;
if ( mouseEvents . mousedown )
Events . trigger ( mouseConstraint , 'mousedown' , { mouse : mouse } ) ;
if ( mouseEvents . mouseup )
Events . trigger ( mouseConstraint , 'mouseup' , { mouse : mouse } ) ;
// reset the mouse state ready for the next step
Mouse . clearSourceEvents ( mouse ) ;
} ;
/ *
*
* Events Documentation
*
* /
/ * *
* Fired when the mouse has moved ( or a touch moves ) during the last step
*
* @ event mousemove
* @ param { } event An event object
* @ param { mouse } event . mouse The engine ' s mouse instance
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired when the mouse is down ( or a touch has started ) during the last step
*
* @ event mousedown
* @ param { } event An event object
* @ param { mouse } event . mouse The engine ' s mouse instance
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired when the mouse is up ( or a touch has ended ) during the last step
*
* @ event mouseup
* @ param { } event An event object
* @ param { mouse } event . mouse The engine ' s mouse instance
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
2014-12-02 16:40:34 -05:00
/ * *
* Fired when the user starts dragging a body
*
* @ event startdrag
* @ param { } event An event object
* @ param { mouse } event . mouse The engine ' s mouse instance
* @ param { body } event . body The body being dragged
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired when the user ends dragging a body
*
* @ event enddrag
* @ param { } event An event object
* @ param { mouse } event . mouse The engine ' s mouse instance
* @ param { body } event . body The body that has stopped being dragged
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
2014-06-09 14:40:24 -04:00
/ *
*
* Properties Documentation
*
* /
/ * *
* A ` String ` denoting the type of object .
*
* @ property type
* @ type string
* @ default "constraint"
* /
/ * *
2014-07-29 11:26:49 -04:00
* The ` Mouse ` instance in use . If not supplied in ` MouseConstraint.create ` , one will be created .
2014-06-09 14:40:24 -04:00
*
* @ property mouse
* @ type mouse
2014-07-29 11:26:49 -04:00
* @ default mouse
2014-06-09 14:40:24 -04:00
* /
/ * *
* The ` Body ` that is currently being moved by the user , or ` null ` if no body .
*
2014-12-02 16:40:34 -05:00
* @ property body
2014-06-09 14:40:24 -04:00
* @ type body
* @ default null
* /
/ * *
* The ` Constraint ` object that is used to move the body during interaction .
*
* @ property constraint
* @ type constraint
* /
2014-07-29 11:26:49 -04:00
/ * *
* An ` Object ` that specifies the collision filter properties .
* The collision filter allows the user to define which types of body this mouse constraint can interact with .
* See ` body.collisionFilter ` for more information .
*
* @ property collisionFilter
* @ type object
* /
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../body/Composite" : 2 , "../collision/Detector" : 5 , "../core/Common" : 14 , "../core/Events" : 16 , "../core/Mouse" : 18 , "../core/Sleeping" : 20 , "../geometry/Bounds" : 24 , "../geometry/Vertices" : 27 , "./Constraint" : 12 } ] , 14 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Common ` module contains utility functions that are common to all modules .
2014-02-28 20:10:08 -05:00
*
* @ class Common
* /
2014-02-19 09:15:05 -05:00
var Common = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Common ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-05-01 09:09:06 -04:00
Common . _nextId = 0 ;
2014-06-09 14:40:24 -04:00
Common . _seed = 0 ;
2014-05-01 09:09:06 -04:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Extends the object in the first argument using the object in the second argument .
2014-02-28 20:10:08 -05:00
* @ method extend
2014-03-11 06:29:14 -04:00
* @ param { } obj
* @ param { boolean } deep
2014-02-28 20:10:08 -05:00
* @ return { } obj extended
* /
2014-03-11 06:29:14 -04:00
Common . extend = function ( obj , deep ) {
var argsStart ,
args ,
deepClone ;
if ( typeof deep === 'boolean' ) {
argsStart = 2 ;
deepClone = deep ;
} else {
argsStart = 1 ;
deepClone = true ;
}
args = Array . prototype . slice . call ( arguments , argsStart ) ;
2014-02-19 09:15:05 -05:00
for ( var i = 0 ; i < args . length ; i ++ ) {
var source = args [ i ] ;
if ( source ) {
for ( var prop in source ) {
2014-03-22 13:51:49 -04:00
if ( deepClone && source [ prop ] && source [ prop ] . constructor === Object ) {
2014-02-19 09:15:05 -05:00
if ( ! obj [ prop ] || obj [ prop ] . constructor === Object ) {
obj [ prop ] = obj [ prop ] || { } ;
2014-03-11 06:29:14 -04:00
Common . extend ( obj [ prop ] , deepClone , source [ prop ] ) ;
2014-02-19 09:15:05 -05:00
} else {
obj [ prop ] = source [ prop ] ;
}
} else {
obj [ prop ] = source [ prop ] ;
}
}
}
}
return obj ;
} ;
2014-03-11 06:29:14 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a new clone of the object , if deep is true references will also be cloned .
2014-03-11 06:29:14 -04:00
* @ method clone
* @ param { } obj
* @ param { bool } deep
* @ return { } obj cloned
* /
Common . clone = function ( obj , deep ) {
return Common . extend ( { } , deep , obj ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns the list of keys for the given object .
2014-02-28 20:10:08 -05:00
* @ method keys
* @ param { } obj
* @ return { string [ ] } keys
* /
2014-02-19 09:15:05 -05:00
Common . keys = function ( obj ) {
if ( Object . keys )
return Object . keys ( obj ) ;
// avoid hasOwnProperty for performance
var keys = [ ] ;
for ( var key in obj )
keys . push ( key ) ;
return keys ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns the list of values for the given object .
2014-02-28 20:10:08 -05:00
* @ method values
* @ param { } obj
* @ return { array } Array of the objects property values
* /
2014-02-19 09:15:05 -05:00
Common . values = function ( obj ) {
var values = [ ] ;
if ( Object . keys ) {
var keys = Object . keys ( obj ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
values . push ( obj [ keys [ i ] ] ) ;
}
return values ;
}
// avoid hasOwnProperty for performance
for ( var key in obj )
values . push ( obj [ key ] ) ;
return values ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns a hex colour string made by lightening or darkening color by percent .
2014-02-28 20:10:08 -05:00
* @ method shadeColor
* @ param { string } color
* @ param { number } percent
2016-01-16 17:43:32 -05:00
* @ return { string } A hex colour
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
Common . shadeColor = function ( color , percent ) {
// http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color
var colorInteger = parseInt ( color . slice ( 1 ) , 16 ) ,
amount = Math . round ( 2.55 * percent ) ,
R = ( colorInteger >> 16 ) + amount ,
B = ( colorInteger >> 8 & 0x00FF ) + amount ,
G = ( colorInteger & 0x0000FF ) + amount ;
return "#" + ( 0x1000000 + ( R < 255 ? R < 1 ? 0 : R : 255 ) * 0x10000
+ ( B < 255 ? B < 1 ? 0 : B : 255 ) * 0x100
+ ( G < 255 ? G < 1 ? 0 : G : 255 ) ) . toString ( 16 ) . slice ( 1 ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Shuffles the given array in - place .
* The function uses a seeded random generator .
2014-02-28 20:10:08 -05:00
* @ method shuffle
* @ param { array } array
* @ return { array } array shuffled randomly
* /
2014-02-19 09:15:05 -05:00
Common . shuffle = function ( array ) {
for ( var i = array . length - 1 ; i > 0 ; i -- ) {
2014-06-09 14:40:24 -04:00
var j = Math . floor ( Common . random ( ) * ( i + 1 ) ) ;
2014-02-19 09:15:05 -05:00
var temp = array [ i ] ;
array [ i ] = array [ j ] ;
array [ j ] = temp ;
}
return array ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Randomly chooses a value from a list with equal probability .
* The function uses a seeded random generator .
2014-02-28 20:10:08 -05:00
* @ method choose
* @ param { array } choices
* @ return { object } A random choice object from the array
* /
2014-02-19 09:15:05 -05:00
Common . choose = function ( choices ) {
2014-06-09 14:40:24 -04:00
return choices [ Math . floor ( Common . random ( ) * choices . length ) ] ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns true if the object is a HTMLElement , otherwise false .
2014-02-28 20:10:08 -05:00
* @ method isElement
* @ param { object } obj
* @ return { boolean } True if the object is a HTMLElement , otherwise false
* /
2014-02-19 09:15:05 -05:00
Common . isElement = function ( obj ) {
// http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
try {
return obj instanceof HTMLElement ;
}
catch ( e ) {
return ( typeof obj === "object" ) &&
( obj . nodeType === 1 ) && ( typeof obj . style === "object" ) &&
( typeof obj . ownerDocument === "object" ) ;
}
} ;
2015-05-20 15:38:41 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns true if the object is an array .
2015-05-20 15:38:41 -04:00
* @ method isArray
* @ param { object } obj
* @ return { boolean } True if the object is an array , otherwise false
* /
Common . isArray = function ( obj ) {
return Object . prototype . toString . call ( obj ) === '[object Array]' ;
} ;
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns the given value clamped between a minimum and maximum value .
2014-02-28 20:10:08 -05:00
* @ method clamp
* @ param { number } value
* @ param { number } min
* @ param { number } max
* @ return { number } The value clamped between min and max inclusive
* /
2014-02-19 09:15:05 -05:00
Common . clamp = function ( value , min , max ) {
if ( value < min )
return min ;
if ( value > max )
return max ;
return value ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns the sign of the given value .
2014-02-28 20:10:08 -05:00
* @ method sign
* @ param { number } value
* @ return { number } - 1 if negative , + 1 if 0 or positive
* /
2014-02-19 09:15:05 -05:00
Common . sign = function ( value ) {
return value < 0 ? - 1 : 1 ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns the current timestamp ( high - res if available ) .
2014-02-28 20:10:08 -05:00
* @ method now
2015-06-29 15:58:24 -04:00
* @ return { number } the current timestamp ( high - res if available )
2014-02-28 20:10:08 -05:00
* /
2014-03-22 13:51:49 -04:00
Common . now = function ( ) {
2014-02-19 09:15:05 -05:00
// http://stackoverflow.com/questions/221294/how-do-you-get-a-timestamp-in-javascript
2014-03-22 13:51:49 -04:00
// https://gist.github.com/davidwaterston/2982531
2015-05-21 19:33:26 -04:00
var performance = window . performance || { } ;
performance . now = ( function ( ) {
return performance . now ||
performance . webkitNow ||
performance . msNow ||
performance . oNow ||
performance . mozNow ||
function ( ) { return + ( new Date ( ) ) ; } ;
} ) ( ) ;
return performance . now ( ) ;
2014-02-19 09:15:05 -05:00
} ;
2014-03-22 13:51:49 -04:00
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns a random value between a minimum and a maximum value inclusive .
* The function uses a seeded random generator .
2014-02-28 20:10:08 -05:00
* @ method random
* @ param { number } min
* @ param { number } max
* @ return { number } A random number between min and max inclusive
* /
2014-02-19 09:15:05 -05:00
Common . random = function ( min , max ) {
2014-06-09 14:40:24 -04:00
min = ( typeof min !== "undefined" ) ? min : 0 ;
max = ( typeof max !== "undefined" ) ? max : 1 ;
return min + _seededRandom ( ) * ( max - min ) ;
2014-02-19 09:15:05 -05:00
} ;
2014-03-22 13:51:49 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Converts a CSS hex colour string into an integer .
2014-03-22 13:51:49 -04:00
* @ method colorToNumber
* @ param { string } colorString
* @ return { number } An integer representing the CSS hex string
* /
Common . colorToNumber = function ( colorString ) {
colorString = colorString . replace ( '#' , '' ) ;
if ( colorString . length == 3 ) {
colorString = colorString . charAt ( 0 ) + colorString . charAt ( 0 )
+ colorString . charAt ( 1 ) + colorString . charAt ( 1 )
+ colorString . charAt ( 2 ) + colorString . charAt ( 2 ) ;
}
return parseInt ( colorString , 16 ) ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* A wrapper for console . log , for providing errors and warnings .
2014-03-22 13:51:49 -04:00
* @ method log
* @ param { string } message
* @ param { string } type
* /
Common . log = function ( message , type ) {
2015-01-20 19:15:04 -05:00
if ( ! console || ! console . log || ! console . warn )
2014-03-22 13:51:49 -04:00
return ;
switch ( type ) {
case 'warn' :
2015-01-20 19:15:04 -05:00
console . warn ( 'Matter.js:' , message ) ;
2014-03-22 13:51:49 -04:00
break ;
case 'error' :
2015-01-20 19:15:04 -05:00
console . log ( 'Matter.js:' , message ) ;
2014-03-22 13:51:49 -04:00
break ;
}
} ;
2014-05-01 09:09:06 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns the next unique sequential ID .
2014-05-01 09:09:06 -04:00
* @ method nextId
* @ return { Number } Unique sequential ID
* /
Common . nextId = function ( ) {
return Common . _nextId ++ ;
} ;
2014-07-29 11:26:49 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* A cross browser compatible indexOf implementation .
2014-07-29 11:26:49 -04:00
* @ method indexOf
* @ param { array } haystack
* @ param { object } needle
* /
Common . indexOf = function ( haystack , needle ) {
if ( haystack . indexOf )
return haystack . indexOf ( needle ) ;
for ( var i = 0 ; i < haystack . length ; i ++ ) {
if ( haystack [ i ] === needle )
return i ;
}
return - 1 ;
} ;
2014-06-09 14:40:24 -04:00
var _seededRandom = function ( ) {
// https://gist.github.com/ngryman/3830489
Common . _seed = ( Common . _seed * 9301 + 49297 ) % 233280 ;
return Common . _seed / 233280 ;
} ;
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { } ] , 15 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Engine ` module contains methods for creating and manipulating engines .
2015-08-12 19:38:20 -04:00
* An engine is a controller that manages updating the simulation of the world .
2014-07-29 11:26:49 -04:00
* See ` Matter.Runner ` for an optional game loop utility .
2014-06-09 14:40:24 -04:00
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class Engine
* /
2014-02-19 09:15:05 -05:00
var Engine = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Engine ;
var World = require ( '../body/World' ) ;
var Sleeping = require ( './Sleeping' ) ;
var Resolver = require ( '../collision/Resolver' ) ;
var Render = require ( '../render/Render' ) ;
var Pairs = require ( '../collision/Pairs' ) ;
var Metrics = require ( './Metrics' ) ;
var Grid = require ( '../collision/Grid' ) ;
var Events = require ( './Events' ) ;
var Composite = require ( '../body/Composite' ) ;
var Constraint = require ( '../constraint/Constraint' ) ;
var Common = require ( './Common' ) ;
var Body = require ( '../body/Body' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new engine . The options parameter is an object that specifies any properties you wish to override the defaults .
* All properties have default values , and many are pre - calculated automatically based on other properties .
2015-06-29 15:58:24 -04:00
* See the properties section below for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method create
* @ param { HTMLElement } element
2014-06-09 14:40:24 -04:00
* @ param { object } [ options ]
2014-02-28 20:10:08 -05:00
* @ return { engine } engine
* /
2014-02-19 09:15:05 -05:00
Engine . create = function ( element , options ) {
2014-03-22 13:51:49 -04:00
// options may be passed as the first (and only) argument
options = Common . isElement ( element ) ? options : element ;
element = Common . isElement ( element ) ? element : null ;
2014-02-19 09:15:05 -05:00
var defaults = {
positionIterations : 6 ,
velocityIterations : 4 ,
2014-03-30 14:45:30 -04:00
constraintIterations : 2 ,
2014-02-19 09:15:05 -05:00
enableSleeping : false ,
2014-03-11 06:29:14 -04:00
events : [ ] ,
2014-02-19 09:15:05 -05:00
timing : {
timestamp : 0 ,
2015-08-12 19:38:20 -04:00
timeScale : 1
2014-03-22 13:51:49 -04:00
} ,
2014-07-29 11:26:49 -04:00
broadphase : {
controller : Grid
2014-02-19 09:15:05 -05:00
}
} ;
2015-07-05 10:57:31 -04:00
2014-02-19 09:15:05 -05:00
var engine = Common . extend ( defaults , options ) ;
2015-07-05 10:57:31 -04:00
if ( element || engine . render ) {
var renderDefaults = {
2015-06-29 15:58:24 -04:00
element : element ,
controller : Render
} ;
2015-07-05 10:57:31 -04:00
engine . render = Common . extend ( renderDefaults , engine . render ) ;
2015-06-29 15:58:24 -04:00
}
if ( engine . render && engine . render . controller ) {
engine . render = engine . render . controller . create ( engine . render ) ;
}
2014-02-19 09:15:05 -05:00
engine . world = World . create ( engine . world ) ;
2014-03-24 16:11:42 -04:00
engine . pairs = Pairs . create ( ) ;
2014-07-29 11:26:49 -04:00
engine . broadphase = engine . broadphase . controller . create ( engine . broadphase ) ;
2015-05-20 15:38:41 -04:00
engine . metrics = engine . metrics || { extended : false } ;
2014-02-19 09:15:05 -05:00
2015-12-05 11:47:50 -05:00
2014-02-19 09:15:05 -05:00
return engine ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2015-08-12 19:38:20 -04:00
* Moves the simulation forward in time by ` delta ` ms .
* The ` correction ` argument is an optional ` Number ` that specifies the time correction factor to apply to the update .
* This can help improve the accuracy of the simulation in cases where ` delta ` is changing between updates .
* The value of ` correction ` is defined as ` delta / lastDelta ` , i . e . the percentage change of ` delta ` over the last step .
* Therefore the value is always ` 1 ` ( no correction ) when ` delta ` constant ( or when no correction is desired , which is the default ) .
* See the paper on < a href = "http://lonesock.net/article/verlet.html" > Time Corrected Verlet < / a > f o r m o r e i n f o r m a t i o n .
*
2014-07-29 11:26:49 -04:00
* Triggers ` beforeUpdate ` and ` afterUpdate ` events .
* Triggers ` collisionStart ` , ` collisionActive ` and ` collisionEnd ` events .
* @ method update
2014-02-28 20:10:08 -05:00
* @ param { engine } engine
2016-02-15 16:24:17 -05:00
* @ param { number } [ delta = 16.666 ]
* @ param { number } [ correction = 1 ]
2014-02-28 20:10:08 -05:00
* /
2014-07-29 11:26:49 -04:00
Engine . update = function ( engine , delta , correction ) {
2016-02-15 16:24:17 -05:00
delta = delta || 1000 / 60 ;
correction = correction || 1 ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
var world = engine . world ,
timing = engine . timing ,
broadphase = engine . broadphase ,
broadphasePairs = [ ] ,
i ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
// increment timestamp
timing . timestamp += delta * timing . timeScale ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
// create an event object
var event = {
2015-08-12 19:38:20 -04:00
timestamp : timing . timestamp
2014-07-29 11:26:49 -04:00
} ;
2014-03-22 13:51:49 -04:00
2014-07-29 11:26:49 -04:00
Events . trigger ( engine , 'beforeUpdate' , event ) ;
2014-03-11 06:29:14 -04:00
2014-07-29 11:26:49 -04:00
// get lists of all bodies and constraints, no matter what composites they are in
var allBodies = Composite . allBodies ( world ) ,
allConstraints = Composite . allConstraints ( world ) ;
2014-03-11 06:29:14 -04:00
2015-12-05 11:47:50 -05:00
2014-03-24 16:11:42 -04:00
// if sleeping enabled, call the sleeping controller
2014-03-11 06:29:14 -04:00
if ( engine . enableSleeping )
2014-07-29 11:26:49 -04:00
Sleeping . update ( allBodies , timing . timeScale ) ;
2014-03-11 06:29:14 -04:00
2014-03-24 16:11:42 -04:00
// applies gravity to all bodies
2015-01-20 19:15:04 -05:00
_bodiesApplyGravity ( allBodies , world . gravity ) ;
2014-03-11 06:29:14 -04:00
2014-03-24 16:11:42 -04:00
// update all body position and rotation by integration
2015-01-20 19:15:04 -05:00
_bodiesUpdate ( allBodies , delta , timing . timeScale , correction , world . bounds ) ;
2014-02-19 09:15:05 -05:00
2014-03-11 06:29:14 -04:00
// update all constraints
2014-02-19 09:15:05 -05:00
for ( i = 0 ; i < engine . constraintIterations ; i ++ ) {
2014-05-01 09:09:06 -04:00
Constraint . solveAll ( allConstraints , timing . timeScale ) ;
2014-02-19 09:15:05 -05:00
}
2014-03-30 14:45:30 -04:00
Constraint . postSolveAll ( allBodies ) ;
2014-02-19 09:15:05 -05:00
2014-03-11 06:29:14 -04:00
// broadphase pass: find potential collision pairs
2014-02-19 09:15:05 -05:00
if ( broadphase . controller ) {
2014-03-24 16:11:42 -04:00
// if world is dirty, we must flush the whole grid
if ( world . isModified )
2014-07-29 11:26:49 -04:00
broadphase . controller . clear ( broadphase ) ;
2014-03-24 16:11:42 -04:00
// update the grid buckets based on current bodies
2014-07-29 11:26:49 -04:00
broadphase . controller . update ( broadphase , allBodies , engine , world . isModified ) ;
broadphasePairs = broadphase . pairsList ;
2014-02-19 09:15:05 -05:00
} else {
2014-03-24 16:11:42 -04:00
// if no broadphase set, we just pass all bodies
broadphasePairs = allBodies ;
2014-02-19 09:15:05 -05:00
}
2014-03-22 13:51:49 -04:00
2014-03-11 06:29:14 -04:00
// narrowphase pass: find actual collisions, then create or update collision pairs
2014-03-22 13:51:49 -04:00
var collisions = broadphase . detector ( broadphasePairs , engine ) ;
2014-03-11 06:29:14 -04:00
2014-03-24 16:11:42 -04:00
// update collision pairs
2014-03-22 13:51:49 -04:00
var pairs = engine . pairs ,
2014-05-01 09:09:06 -04:00
timestamp = timing . timestamp ;
2014-03-24 16:11:42 -04:00
Pairs . update ( pairs , collisions , timestamp ) ;
Pairs . removeOld ( pairs , timestamp ) ;
2014-02-19 09:15:05 -05:00
// wake up bodies involved in collisions
if ( engine . enableSleeping )
2014-07-29 11:26:49 -04:00
Sleeping . afterCollisions ( pairs . list , timing . timeScale ) ;
// trigger collision events
if ( pairs . collisionStart . length > 0 )
Events . trigger ( engine , 'collisionStart' , { pairs : pairs . collisionStart } ) ;
2014-02-19 09:15:05 -05:00
// iteratively resolve position between collisions
2015-05-20 15:38:41 -04:00
Resolver . preSolvePosition ( pairs . list ) ;
2014-02-19 09:15:05 -05:00
for ( i = 0 ; i < engine . positionIterations ; i ++ ) {
2014-05-01 09:09:06 -04:00
Resolver . solvePosition ( pairs . list , timing . timeScale ) ;
2014-02-19 09:15:05 -05:00
}
2014-03-24 16:11:42 -04:00
Resolver . postSolvePosition ( allBodies ) ;
2014-02-19 09:15:05 -05:00
2015-05-20 15:38:41 -04:00
// iteratively resolve velocity between collisions
Resolver . preSolveVelocity ( pairs . list ) ;
for ( i = 0 ; i < engine . velocityIterations ; i ++ ) {
Resolver . solveVelocity ( pairs . list , timing . timeScale ) ;
}
2014-07-29 11:26:49 -04:00
// trigger collision events
if ( pairs . collisionActive . length > 0 )
Events . trigger ( engine , 'collisionActive' , { pairs : pairs . collisionActive } ) ;
if ( pairs . collisionEnd . length > 0 )
Events . trigger ( engine , 'collisionEnd' , { pairs : pairs . collisionEnd } ) ;
2015-12-05 11:47:50 -05:00
2014-03-11 06:29:14 -04:00
// clear force buffers
2015-01-20 19:15:04 -05:00
_bodiesClearForces ( allBodies ) ;
2014-03-24 16:11:42 -04:00
// clear all composite modified flags
if ( world . isModified )
Composite . setModified ( world , false , false , true ) ;
2014-03-11 06:29:14 -04:00
2014-05-05 14:32:51 -04:00
Events . trigger ( engine , 'afterUpdate' , event ) ;
2014-02-19 09:15:05 -05:00
return engine ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Merges two engines by keeping the configuration of ` engineA ` but replacing the world with the one from ` engineB ` .
2014-02-28 20:10:08 -05:00
* @ method merge
* @ param { engine } engineA
* @ param { engine } engineB
* /
2014-02-19 09:15:05 -05:00
Engine . merge = function ( engineA , engineB ) {
Common . extend ( engineA , engineB ) ;
if ( engineB . world ) {
engineA . world = engineB . world ;
Engine . clear ( engineA ) ;
2014-03-24 16:11:42 -04:00
var bodies = Composite . allBodies ( engineA . world ) ;
2014-02-19 09:15:05 -05:00
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
Sleeping . set ( body , false ) ;
2014-05-01 09:09:06 -04:00
body . id = Common . nextId ( ) ;
2014-02-19 09:15:05 -05:00
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Clears the engine including the world , pairs and broadphase .
2014-02-28 20:10:08 -05:00
* @ method clear
* @ param { engine } engine
* /
2014-02-19 09:15:05 -05:00
Engine . clear = function ( engine ) {
var world = engine . world ;
2014-03-24 16:11:42 -04:00
Pairs . clear ( engine . pairs ) ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
var broadphase = engine . broadphase ;
2014-02-19 09:15:05 -05:00
if ( broadphase . controller ) {
2014-03-24 16:11:42 -04:00
var bodies = Composite . allBodies ( world ) ;
2014-07-29 11:26:49 -04:00
broadphase . controller . clear ( broadphase ) ;
broadphase . controller . update ( broadphase , bodies , engine , true ) ;
2014-02-19 09:15:05 -05:00
}
} ;
2015-01-20 19:15:04 -05:00
/ * *
* Zeroes the ` body.force ` and ` body.torque ` force buffers .
* @ method bodiesClearForces
* @ private
* @ param { body [ ] } bodies
* /
var _bodiesClearForces = function ( bodies ) {
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
// reset force buffers
body . force . x = 0 ;
body . force . y = 0 ;
body . torque = 0 ;
}
} ;
/ * *
* Applys a mass dependant force to all given bodies .
* @ method bodiesApplyGravity
* @ private
* @ param { body [ ] } bodies
* @ param { vector } gravity
* /
var _bodiesApplyGravity = function ( bodies , gravity ) {
2016-01-16 17:43:32 -05:00
var gravityScale = typeof gravity . scale !== 'undefined' ? gravity . scale : 0.001 ;
if ( ( gravity . x === 0 && gravity . y === 0 ) || gravityScale === 0 ) {
return ;
}
2015-01-20 19:15:04 -05:00
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
if ( body . isStatic || body . isSleeping )
continue ;
// apply gravity
2016-01-16 17:43:32 -05:00
body . force . y += body . mass * gravity . y * gravityScale ;
body . force . x += body . mass * gravity . x * gravityScale ;
2015-01-20 19:15:04 -05:00
}
} ;
/ * *
* Applys ` Body.update ` to all given ` bodies ` .
* @ method updateAll
* @ private
* @ param { body [ ] } bodies
* @ param { number } deltaTime
* The amount of time elapsed between updates
* @ param { number } timeScale
* @ param { number } correction
* The Verlet correction factor ( deltaTime / lastDeltaTime )
* @ param { bounds } worldBounds
* /
var _bodiesUpdate = function ( bodies , deltaTime , timeScale , correction , worldBounds ) {
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
if ( body . isStatic || body . isSleeping )
continue ;
Body . update ( body , deltaTime , timeScale , correction ) ;
}
} ;
2014-03-22 13:51:49 -04:00
/ * *
2014-07-29 11:26:49 -04:00
* An alias for ` Runner.run ` , see ` Matter.Runner ` for more information .
* @ method run
2014-03-22 13:51:49 -04:00
* @ param { engine } engine
* /
2014-05-01 09:09:06 -04:00
/ * *
* Fired just before an update
*
* @ event beforeUpdate
* @ param { } event An event object
2015-08-12 19:38:20 -04:00
* @ param { number } event . timestamp The engine . timing . timestamp of the event
2014-05-01 09:09:06 -04:00
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after engine update and all collision events
*
* @ event afterUpdate
* @ param { } event An event object
2015-08-12 19:38:20 -04:00
* @ param { number } event . timestamp The engine . timing . timestamp of the event
2014-05-01 09:09:06 -04:00
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after engine update , provides a list of all pairs that have started to collide in the current tick ( if any )
*
* @ event collisionStart
* @ param { } event An event object
* @ param { } event . pairs List of affected pairs
2015-08-12 19:38:20 -04:00
* @ param { number } event . timestamp The engine . timing . timestamp of the event
2014-05-01 09:09:06 -04:00
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after engine update , provides a list of all pairs that are colliding in the current tick ( if any )
*
* @ event collisionActive
* @ param { } event An event object
* @ param { } event . pairs List of affected pairs
2015-08-12 19:38:20 -04:00
* @ param { number } event . timestamp The engine . timing . timestamp of the event
2014-05-01 09:09:06 -04:00
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after engine update , provides a list of all pairs that have ended collision in the current tick ( if any )
*
* @ event collisionEnd
* @ param { } event An event object
* @ param { } event . pairs List of affected pairs
2015-08-12 19:38:20 -04:00
* @ param { number } event . timestamp The engine . timing . timestamp of the event
2014-05-01 09:09:06 -04:00
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
2014-06-09 14:40:24 -04:00
/ *
*
* Properties Documentation
*
* /
/ * *
* An integer ` Number ` that specifies the number of position iterations to perform each update .
* The higher the value , the higher quality the simulation will be at the expense of performance .
*
* @ property positionIterations
* @ type number
* @ default 6
* /
/ * *
* An integer ` Number ` that specifies the number of velocity iterations to perform each update .
* The higher the value , the higher quality the simulation will be at the expense of performance .
*
* @ property velocityIterations
* @ type number
* @ default 4
* /
/ * *
* An integer ` Number ` that specifies the number of constraint iterations to perform each update .
* The higher the value , the higher quality the simulation will be at the expense of performance .
* The default value of ` 2 ` is usually very adequate .
*
* @ property constraintIterations
* @ type number
* @ default 2
* /
/ * *
* A flag that specifies whether the engine should allow sleeping via the ` Matter.Sleeping ` module .
* Sleeping can improve stability and performance , but often at the expense of accuracy .
*
* @ property enableSleeping
* @ type boolean
* @ default false
* /
/ * *
* An ` Object ` containing properties regarding the timing systems of the engine .
*
* @ property timing
* @ type object
* /
/ * *
* A ` Number ` that specifies the global scaling factor of time for all bodies .
* A value of ` 0 ` freezes the simulation .
* A value of ` 0.1 ` gives a slow - motion effect .
* A value of ` 1.2 ` gives a speed - up effect .
*
* @ property timing . timeScale
* @ type number
* @ default 1
* /
/ * *
* A ` Number ` that specifies the current simulation - time in milliseconds starting from ` 0 ` .
2015-08-12 19:38:20 -04:00
* It is incremented on every ` Engine.update ` by the given ` delta ` argument .
2014-06-09 14:40:24 -04:00
*
* @ property timing . timestamp
* @ type number
* @ default 0
* /
/ * *
* An instance of a ` Render ` controller . The default value is a ` Matter.Render ` instance created by ` Engine.create ` .
* One may also develop a custom renderer module based on ` Matter.Render ` and pass an instance of it to ` Engine.create ` via ` options.render ` .
*
* A minimal custom renderer object must define at least three functions : ` create ` , ` clear ` and ` world ` ( see ` Matter.Render ` ) .
* It is also possible to instead pass the _module _ reference via ` options.render.controller ` and ` Engine.create ` will instantiate one for you .
*
* @ property render
* @ type render
* @ default a Matter . Render instance
* /
2014-07-29 11:26:49 -04:00
/ * *
* An instance of a broadphase controller . The default value is a ` Matter.Grid ` instance created by ` Engine.create ` .
*
* @ property broadphase
* @ type grid
* @ default a Matter . Grid instance
* /
2014-06-09 14:40:24 -04:00
/ * *
* A ` World ` composite object that will contain all simulated bodies and constraints .
*
* @ property world
* @ type world
* @ default a Matter . World instance
* /
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../body/Body" : 1 , "../body/Composite" : 2 , "../body/World" : 3 , "../collision/Grid" : 6 , "../collision/Pairs" : 8 , "../collision/Resolver" : 10 , "../constraint/Constraint" : 12 , "../render/Render" : 29 , "./Common" : 14 , "./Events" : 16 , "./Metrics" : 17 , "./Sleeping" : 20 } ] , 16 : [ function ( require , module , exports ) {
2014-03-11 06:29:14 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Events ` module contains methods to fire and listen to events on other objects .
*
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-03-11 06:29:14 -04:00
*
* @ class Events
* /
var Events = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Events ;
var Common = require ( './Common' ) ;
2014-03-11 06:29:14 -04:00
( function ( ) {
/ * *
2014-06-09 14:40:24 -04:00
* Subscribes a callback function to the given object ' s ` eventName ` .
2014-03-11 06:29:14 -04:00
* @ method on
* @ param { } object
* @ param { string } eventNames
* @ param { function } callback
* /
Events . on = function ( object , eventNames , callback ) {
var names = eventNames . split ( ' ' ) ,
name ;
for ( var i = 0 ; i < names . length ; i ++ ) {
name = names [ i ] ;
object . events = object . events || { } ;
object . events [ name ] = object . events [ name ] || [ ] ;
object . events [ name ] . push ( callback ) ;
}
2014-05-01 09:09:06 -04:00
return callback ;
2014-03-11 06:29:14 -04:00
} ;
2014-03-24 16:11:42 -04:00
/ * *
2014-06-09 14:40:24 -04:00
* Removes the given event callback . If no callback , clears all callbacks in ` eventNames ` . If no ` eventNames ` , clears all events .
2014-03-24 16:11:42 -04:00
* @ method off
* @ param { } object
* @ param { string } eventNames
2014-05-01 09:09:06 -04:00
* @ param { function } callback
2014-03-24 16:11:42 -04:00
* /
2014-05-01 09:09:06 -04:00
Events . off = function ( object , eventNames , callback ) {
2014-03-24 16:11:42 -04:00
if ( ! eventNames ) {
object . events = { } ;
return ;
}
2014-05-01 09:09:06 -04:00
// handle Events.off(object, callback)
if ( typeof eventNames === 'function' ) {
callback = eventNames ;
eventNames = Common . keys ( object . events ) . join ( ' ' ) ;
}
2014-03-24 16:11:42 -04:00
var names = eventNames . split ( ' ' ) ;
2014-05-01 09:09:06 -04:00
2014-03-24 16:11:42 -04:00
for ( var i = 0 ; i < names . length ; i ++ ) {
2014-05-01 09:09:06 -04:00
var callbacks = object . events [ names [ i ] ] ,
newCallbacks = [ ] ;
2015-08-17 18:50:03 -04:00
if ( callback && callbacks ) {
2014-05-01 09:09:06 -04:00
for ( var j = 0 ; j < callbacks . length ; j ++ ) {
if ( callbacks [ j ] !== callback )
newCallbacks . push ( callbacks [ j ] ) ;
}
}
object . events [ names [ i ] ] = newCallbacks ;
2014-03-24 16:11:42 -04:00
}
} ;
2014-03-11 06:29:14 -04:00
/ * *
2014-06-09 14:40:24 -04:00
* Fires all the callbacks subscribed to the given object ' s ` eventName ` , in the order they subscribed , if any .
2014-03-24 16:11:42 -04:00
* @ method trigger
2014-03-11 06:29:14 -04:00
* @ param { } object
* @ param { string } eventNames
* @ param { } event
* /
Events . trigger = function ( object , eventNames , event ) {
var names ,
name ,
callbacks ,
eventClone ;
if ( object . events ) {
2014-03-22 13:51:49 -04:00
if ( ! event )
event = { } ;
2014-03-11 06:29:14 -04:00
names = eventNames . split ( ' ' ) ;
for ( var i = 0 ; i < names . length ; i ++ ) {
name = names [ i ] ;
2014-03-30 14:45:30 -04:00
callbacks = object . events [ name ] ;
2014-03-11 06:29:14 -04:00
2014-03-30 14:45:30 -04:00
if ( callbacks ) {
2014-03-11 06:29:14 -04:00
eventClone = Common . clone ( event , false ) ;
eventClone . name = name ;
eventClone . source = object ;
for ( var j = 0 ; j < callbacks . length ; j ++ ) {
callbacks [ j ] . apply ( object , [ eventClone ] ) ;
}
}
}
}
} ;
} ) ( ) ;
2016-01-16 17:43:32 -05:00
2015-08-17 18:50:03 -04:00
} , { "./Common" : 14 } ] , 17 : [ function ( require , module , exports ) {
2016-01-16 17:43:32 -05:00
2015-08-17 18:50:03 -04:00
} , { "../body/Composite" : 2 , "./Common" : 14 } ] , 18 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Mouse ` module contains methods for creating and manipulating mouse inputs .
2014-02-28 20:10:08 -05:00
*
* @ class Mouse
* /
2014-07-29 11:26:49 -04:00
var Mouse = { } ;
2014-02-19 09:15:05 -05:00
2015-08-17 18:50:03 -04:00
module . exports = Mouse ;
var Common = require ( '../core/Common' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-07-29 11:26:49 -04:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a mouse input .
2014-07-29 11:26:49 -04:00
* @ method create
2014-02-28 20:10:08 -05:00
* @ param { HTMLElement } element
2014-07-29 11:26:49 -04:00
* @ return { mouse } A new mouse
2014-02-28 20:10:08 -05:00
* /
2014-07-29 11:26:49 -04:00
Mouse . create = function ( element ) {
var mouse = { } ;
2015-01-20 19:15:04 -05:00
if ( ! element ) {
Common . log ( 'Mouse.create: element was undefined, defaulting to document.body' , 'warn' ) ;
}
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
mouse . element = element || document . body ;
mouse . absolute = { x : 0 , y : 0 } ;
mouse . position = { x : 0 , y : 0 } ;
mouse . mousedownPosition = { x : 0 , y : 0 } ;
mouse . mouseupPosition = { x : 0 , y : 0 } ;
mouse . offset = { x : 0 , y : 0 } ;
mouse . scale = { x : 1 , y : 1 } ;
mouse . wheelDelta = 0 ;
mouse . button = - 1 ;
2015-01-20 19:15:04 -05:00
mouse . pixelRatio = mouse . element . getAttribute ( 'data-pixel-ratio' ) || 1 ;
2014-07-29 11:26:49 -04:00
mouse . sourceEvents = {
2014-03-22 13:51:49 -04:00
mousemove : null ,
mousedown : null ,
2014-05-05 14:32:51 -04:00
mouseup : null ,
mousewheel : null
2014-03-22 13:51:49 -04:00
} ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
mouse . mousemove = function ( event ) {
2014-12-28 13:37:43 -05:00
var position = _getRelativeMousePosition ( event , mouse . element , mouse . pixelRatio ) ,
2014-02-19 09:15:05 -05:00
touches = event . changedTouches ;
if ( touches ) {
mouse . button = 0 ;
event . preventDefault ( ) ;
}
2014-05-05 14:32:51 -04:00
mouse . absolute . x = position . x ;
mouse . absolute . y = position . y ;
mouse . position . x = mouse . absolute . x * mouse . scale . x + mouse . offset . x ;
mouse . position . y = mouse . absolute . y * mouse . scale . y + mouse . offset . y ;
2014-03-22 13:51:49 -04:00
mouse . sourceEvents . mousemove = event ;
2014-02-19 09:15:05 -05:00
} ;
2014-07-29 11:26:49 -04:00
mouse . mousedown = function ( event ) {
2014-12-28 13:37:43 -05:00
var position = _getRelativeMousePosition ( event , mouse . element , mouse . pixelRatio ) ,
2014-02-19 09:15:05 -05:00
touches = event . changedTouches ;
if ( touches ) {
mouse . button = 0 ;
event . preventDefault ( ) ;
} else {
mouse . button = event . button ;
}
2014-05-05 14:32:51 -04:00
mouse . absolute . x = position . x ;
mouse . absolute . y = position . y ;
mouse . position . x = mouse . absolute . x * mouse . scale . x + mouse . offset . x ;
mouse . position . y = mouse . absolute . y * mouse . scale . y + mouse . offset . y ;
mouse . mousedownPosition . x = mouse . position . x ;
mouse . mousedownPosition . y = mouse . position . y ;
2014-03-22 13:51:49 -04:00
mouse . sourceEvents . mousedown = event ;
2014-02-19 09:15:05 -05:00
} ;
2014-07-29 11:26:49 -04:00
mouse . mouseup = function ( event ) {
2014-12-28 13:37:43 -05:00
var position = _getRelativeMousePosition ( event , mouse . element , mouse . pixelRatio ) ,
2014-02-19 09:15:05 -05:00
touches = event . changedTouches ;
if ( touches ) {
event . preventDefault ( ) ;
}
mouse . button = - 1 ;
2014-05-05 14:32:51 -04:00
mouse . absolute . x = position . x ;
mouse . absolute . y = position . y ;
mouse . position . x = mouse . absolute . x * mouse . scale . x + mouse . offset . x ;
mouse . position . y = mouse . absolute . y * mouse . scale . y + mouse . offset . y ;
mouse . mouseupPosition . x = mouse . position . x ;
mouse . mouseupPosition . y = mouse . position . y ;
2014-03-22 13:51:49 -04:00
mouse . sourceEvents . mouseup = event ;
2014-02-19 09:15:05 -05:00
} ;
2014-03-30 14:45:30 -04:00
2014-07-29 11:26:49 -04:00
mouse . mousewheel = function ( event ) {
2014-05-05 14:32:51 -04:00
mouse . wheelDelta = Math . max ( - 1 , Math . min ( 1 , event . wheelDelta || - event . detail ) ) ;
event . preventDefault ( ) ;
} ;
2014-03-30 14:45:30 -04:00
Mouse . setElement ( mouse , mouse . element ) ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
return mouse ;
2014-02-19 09:15:05 -05:00
} ;
2014-03-22 13:51:49 -04:00
2014-03-30 14:45:30 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Sets the element the mouse is bound to ( and relative to ) .
2014-03-30 14:45:30 -04:00
* @ method setElement
* @ param { mouse } mouse
* @ param { HTMLElement } element
* /
Mouse . setElement = function ( mouse , element ) {
mouse . element = element ;
element . addEventListener ( 'mousemove' , mouse . mousemove ) ;
element . addEventListener ( 'mousedown' , mouse . mousedown ) ;
element . addEventListener ( 'mouseup' , mouse . mouseup ) ;
2016-01-16 17:43:32 -05:00
element . addEventListener ( 'mousewheel' , mouse . mousewheel ) ;
element . addEventListener ( 'DOMMouseScroll' , mouse . mousewheel ) ;
2014-05-05 14:32:51 -04:00
2014-03-30 14:45:30 -04:00
element . addEventListener ( 'touchmove' , mouse . mousemove ) ;
element . addEventListener ( 'touchstart' , mouse . mousedown ) ;
element . addEventListener ( 'touchend' , mouse . mouseup ) ;
} ;
2014-03-22 13:51:49 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Clears all captured source events .
2014-04-01 08:47:17 -04:00
* @ method clearSourceEvents
2014-03-22 13:51:49 -04:00
* @ param { mouse } mouse
* /
Mouse . clearSourceEvents = function ( mouse ) {
mouse . sourceEvents . mousemove = null ;
mouse . sourceEvents . mousedown = null ;
mouse . sourceEvents . mouseup = null ;
2014-05-05 14:32:51 -04:00
mouse . sourceEvents . mousewheel = null ;
mouse . wheelDelta = 0 ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Sets the mouse position offset .
2014-05-05 14:32:51 -04:00
* @ method setOffset
* @ param { mouse } mouse
2015-06-29 15:58:24 -04:00
* @ param { vector } offset
2014-05-05 14:32:51 -04:00
* /
Mouse . setOffset = function ( mouse , offset ) {
mouse . offset . x = offset . x ;
mouse . offset . y = offset . y ;
mouse . position . x = mouse . absolute . x * mouse . scale . x + mouse . offset . x ;
mouse . position . y = mouse . absolute . y * mouse . scale . y + mouse . offset . y ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Sets the mouse position scale .
2014-05-05 14:32:51 -04:00
* @ method setScale
* @ param { mouse } mouse
2015-06-29 15:58:24 -04:00
* @ param { vector } scale
2014-05-05 14:32:51 -04:00
* /
Mouse . setScale = function ( mouse , scale ) {
mouse . scale . x = scale . x ;
mouse . scale . y = scale . y ;
mouse . position . x = mouse . absolute . x * mouse . scale . x + mouse . offset . x ;
mouse . position . y = mouse . absolute . y * mouse . scale . y + mouse . offset . y ;
2014-03-22 13:51:49 -04:00
} ;
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Gets the mouse position relative to an element given a screen pixel ratio .
2014-02-28 20:10:08 -05:00
* @ method _getRelativeMousePosition
* @ private
* @ param { } event
* @ param { } element
2014-12-28 13:37:43 -05:00
* @ param { number } pixelRatio
* @ return { }
2014-02-28 20:10:08 -05:00
* /
2014-12-28 13:37:43 -05:00
var _getRelativeMousePosition = function ( event , element , pixelRatio ) {
2014-02-19 09:15:05 -05:00
var elementBounds = element . getBoundingClientRect ( ) ,
2014-05-05 14:32:51 -04:00
rootNode = ( document . documentElement || document . body . parentNode || document . body ) ,
scrollX = ( window . pageXOffset !== undefined ) ? window . pageXOffset : rootNode . scrollLeft ,
scrollY = ( window . pageYOffset !== undefined ) ? window . pageYOffset : rootNode . scrollTop ,
2014-02-19 09:15:05 -05:00
touches = event . changedTouches ,
x , y ;
if ( touches ) {
x = touches [ 0 ] . pageX - elementBounds . left - scrollX ;
y = touches [ 0 ] . pageY - elementBounds . top - scrollY ;
} else {
x = event . pageX - elementBounds . left - scrollX ;
y = event . pageY - elementBounds . top - scrollY ;
}
2014-12-28 13:37:43 -05:00
2014-02-19 09:15:05 -05:00
return {
2014-12-28 13:37:43 -05:00
x : x / ( element . clientWidth / element . width * pixelRatio ) ,
y : y / ( element . clientHeight / element . height * pixelRatio )
2014-02-19 09:15:05 -05:00
} ;
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 } ] , 19 : [ function ( require , module , exports ) {
2014-07-29 11:26:49 -04:00
/ * *
* The ` Matter.Runner ` module is an optional utility which provides a game loop ,
* that handles updating and rendering a ` Matter.Engine ` for you within a browser .
2015-08-12 19:38:20 -04:00
* It is intended for demo and testing purposes , but may be adequate for simple games .
* If you are using your own game loop instead , then you do not need the ` Matter.Runner ` module .
* Instead just call ` Engine.update(engine, delta) ` in your own loop .
2014-07-29 11:26:49 -04:00
* Note that the method ` Engine.run ` is an alias for ` Runner.run ` .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-07-29 11:26:49 -04:00
*
* @ class Runner
* /
var Runner = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Runner ;
var Events = require ( './Events' ) ;
var Engine = require ( './Engine' ) ;
var Common = require ( './Common' ) ;
2014-07-29 11:26:49 -04:00
( function ( ) {
2015-08-17 18:50:03 -04:00
var _requestAnimationFrame ,
_cancelAnimationFrame ;
2015-06-29 15:58:24 -04:00
2015-08-17 18:50:03 -04:00
if ( typeof window !== 'undefined' ) {
_requestAnimationFrame = window . requestAnimationFrame || window . webkitRequestAnimationFrame
2014-07-29 11:26:49 -04:00
|| window . mozRequestAnimationFrame || window . msRequestAnimationFrame
2015-08-12 19:38:20 -04:00
|| function ( callback ) { window . setTimeout ( function ( ) { callback ( Common . now ( ) ) ; } , 1000 / 60 ) ; } ;
2014-07-29 11:26:49 -04:00
2015-08-17 18:50:03 -04:00
_cancelAnimationFrame = window . cancelAnimationFrame || window . mozCancelAnimationFrame
2014-07-29 11:26:49 -04:00
|| window . webkitCancelAnimationFrame || window . msCancelAnimationFrame ;
2015-08-17 18:50:03 -04:00
}
2014-07-29 11:26:49 -04:00
/ * *
2015-08-12 19:38:20 -04:00
* Creates a new Runner . The options parameter is an object that specifies any properties you wish to override the defaults .
* @ method create
* @ param { } options
* /
Runner . create = function ( options ) {
var defaults = {
fps : 60 ,
correction : 1 ,
deltaSampleSize : 60 ,
counterTimestamp : 0 ,
frameCounter : 0 ,
deltaHistory : [ ] ,
timePrev : null ,
timeScalePrev : 1 ,
frameRequestId : null ,
isFixed : false ,
enabled : true
} ;
var runner = Common . extend ( defaults , options ) ;
runner . delta = runner . delta || 1000 / runner . fps ;
runner . deltaMin = runner . deltaMin || 1000 / runner . fps ;
runner . deltaMax = runner . deltaMax || 1000 / ( runner . fps * 0.5 ) ;
runner . fps = 1000 / runner . delta ;
return runner ;
} ;
/ * *
* Continuously ticks a ` Matter.Engine ` by calling ` Runner.tick ` on the ` requestAnimationFrame ` event .
2014-07-29 11:26:49 -04:00
* @ method run
* @ param { engine } engine
* /
2015-08-12 19:38:20 -04:00
Runner . run = function ( runner , engine ) {
// create runner if engine is first argument
if ( typeof runner . positionIterations !== 'undefined' ) {
engine = runner ;
runner = Runner . create ( ) ;
}
2014-07-29 11:26:49 -04:00
( function render ( time ) {
2015-08-12 19:38:20 -04:00
runner . frameRequestId = _requestAnimationFrame ( render ) ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
if ( time && runner . enabled ) {
Runner . tick ( runner , engine , time ) ;
}
} ) ( ) ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
return runner ;
} ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
/ * *
* A game loop utility that updates the engine and renderer by one step ( a 'tick' ) .
* Features delta smoothing , time correction and fixed or dynamic timing .
* Triggers ` beforeTick ` , ` tick ` and ` afterTick ` events on the engine .
* Consider just ` Engine.update(engine, delta) ` if you ' re using your own loop .
* @ method tick
* @ param { runner } runner
* @ param { engine } engine
* @ param { number } time
* /
Runner . tick = function ( runner , engine , time ) {
var timing = engine . timing ,
correction = 1 ,
delta ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
// create an event object
var event = {
timestamp : timing . timestamp
} ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
Events . trigger ( runner , 'beforeTick' , event ) ;
Events . trigger ( engine , 'beforeTick' , event ) ; // @deprecated
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
if ( runner . isFixed ) {
// fixed timestep
delta = runner . delta ;
} else {
// dynamic timestep based on wall clock between calls
delta = ( time - runner . timePrev ) || runner . delta ;
runner . timePrev = time ;
// optimistically filter delta over a few frames, to improve stability
runner . deltaHistory . push ( delta ) ;
runner . deltaHistory = runner . deltaHistory . slice ( - runner . deltaSampleSize ) ;
delta = Math . min . apply ( null , runner . deltaHistory ) ;
// limit delta
delta = delta < runner . deltaMin ? runner . deltaMin : delta ;
delta = delta > runner . deltaMax ? runner . deltaMax : delta ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
// correction for delta
correction = delta / runner . delta ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
// update engine timing object
runner . delta = delta ;
}
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
// time correction for time scaling
if ( runner . timeScalePrev !== 0 )
correction *= timing . timeScale / runner . timeScalePrev ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
if ( timing . timeScale === 0 )
correction = 0 ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
runner . timeScalePrev = timing . timeScale ;
runner . correction = correction ;
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
// fps counter
runner . frameCounter += 1 ;
if ( time - runner . counterTimestamp >= 1000 ) {
runner . fps = runner . frameCounter * ( ( time - runner . counterTimestamp ) / 1000 ) ;
runner . counterTimestamp = time ;
runner . frameCounter = 0 ;
}
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
Events . trigger ( runner , 'tick' , event ) ;
Events . trigger ( engine , 'tick' , event ) ; // @deprecated
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
// if world has been modified, clear the render scene graph
if ( engine . world . isModified
&& engine . render
&& engine . render . controller
&& engine . render . controller . clear ) {
engine . render . controller . clear ( engine . render ) ;
}
2014-07-29 11:26:49 -04:00
2015-08-12 19:38:20 -04:00
// update
Events . trigger ( runner , 'beforeUpdate' , event ) ;
Engine . update ( engine , delta , correction ) ;
Events . trigger ( runner , 'afterUpdate' , event ) ;
// render
2015-08-17 18:50:03 -04:00
if ( engine . render && engine . render . controller ) {
2015-08-12 19:38:20 -04:00
Events . trigger ( runner , 'beforeRender' , event ) ;
Events . trigger ( engine , 'beforeRender' , event ) ; // @deprecated
engine . render . controller . world ( engine ) ;
Events . trigger ( runner , 'afterRender' , event ) ;
Events . trigger ( engine , 'afterRender' , event ) ; // @deprecated
}
Events . trigger ( runner , 'afterTick' , event ) ;
Events . trigger ( engine , 'afterTick' , event ) ; // @deprecated
2014-07-29 11:26:49 -04:00
} ;
/ * *
2015-08-12 19:38:20 -04:00
* Ends execution of ` Runner.run ` on the given ` runner ` , by canceling the animation frame request event loop .
2014-07-29 11:26:49 -04:00
* If you wish to only temporarily pause the engine , see ` engine.enabled ` instead .
* @ method stop
2015-08-12 19:38:20 -04:00
* @ param { runner } runner
2014-07-29 11:26:49 -04:00
* /
2015-08-12 19:38:20 -04:00
Runner . stop = function ( runner ) {
_cancelAnimationFrame ( runner . frameRequestId ) ;
2014-07-29 11:26:49 -04:00
} ;
2015-12-05 11:47:50 -05:00
/ * *
* Alias for ` Runner.run ` .
* @ method start
* @ param { runner } runner
* @ param { engine } engine
* /
Runner . start = function ( runner , engine ) {
Runner . run ( runner , engine ) ;
} ;
2015-08-12 19:38:20 -04:00
/ *
*
* Events Documentation
*
* /
/ * *
* Fired at the start of a tick , before any updates to the engine or timing
*
* @ event beforeTick
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after engine timing updated , but just before update
*
* @ event tick
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired at the end of a tick , after engine update and after rendering
*
* @ event afterTick
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired before update
*
* @ event beforeUpdate
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after update
*
* @ event afterUpdate
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired before rendering
*
* @ event beforeRender
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after rendering
*
* @ event afterRender
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ *
*
* Properties Documentation
*
* /
/ * *
* A flag that specifies whether the runner is running or not .
*
* @ property enabled
* @ type boolean
* @ default true
* /
/ * *
* A ` Boolean ` that specifies if the runner should use a fixed timestep ( otherwise it is variable ) .
* If timing is fixed , then the apparent simulation speed will change depending on the frame rate ( but behaviour will be deterministic ) .
* If the timing is variable , then the apparent simulation speed will be constant ( approximately , but at the cost of determininism ) .
*
* @ property isFixed
* @ type boolean
* @ default false
* /
/ * *
* A ` Number ` that specifies the time step between updates in milliseconds .
* If ` engine.timing.isFixed ` is set to ` true ` , then ` delta ` is fixed .
* If it is ` false ` , then ` delta ` can dynamically change to maintain the correct apparent simulation speed .
*
* @ property delta
* @ type number
* @ default 1000 / 60
* /
2014-07-29 11:26:49 -04:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "./Common" : 14 , "./Engine" : 15 , "./Events" : 16 } ] , 20 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Sleeping ` module contains methods to manage the sleeping state of bodies .
2014-02-28 20:10:08 -05:00
*
* @ class Sleeping
* /
2014-02-19 09:15:05 -05:00
var Sleeping = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Sleeping ;
var Events = require ( './Events' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-07-29 11:26:49 -04:00
Sleeping . _motionWakeThreshold = 0.18 ;
Sleeping . _motionSleepThreshold = 0.08 ;
Sleeping . _minBias = 0.9 ;
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2014-07-29 11:26:49 -04:00
* Puts bodies to sleep or wakes them up depending on their motion .
2014-02-28 20:10:08 -05:00
* @ method update
* @ param { body [ ] } bodies
2014-07-29 11:26:49 -04:00
* @ param { number } timeScale
2014-02-28 20:10:08 -05:00
* /
2014-07-29 11:26:49 -04:00
Sleeping . update = function ( bodies , timeScale ) {
var timeFactor = timeScale * timeScale * timeScale ;
2014-02-19 09:15:05 -05:00
// update bodies sleeping status
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ,
motion = body . speed * body . speed + body . angularSpeed * body . angularSpeed ;
2014-03-11 06:29:14 -04:00
// wake up bodies if they have a force applied
2015-05-21 19:33:26 -04:00
if ( body . force . x !== 0 || body . force . y !== 0 ) {
2014-03-11 06:29:14 -04:00
Sleeping . set ( body , false ) ;
continue ;
}
2014-02-19 09:15:05 -05:00
var minMotion = Math . min ( body . motion , motion ) ,
maxMotion = Math . max ( body . motion , motion ) ;
// biased average motion estimation between frames
2014-07-29 11:26:49 -04:00
body . motion = Sleeping . _minBias * minMotion + ( 1 - Sleeping . _minBias ) * maxMotion ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
if ( body . sleepThreshold > 0 && body . motion < Sleeping . _motionSleepThreshold * timeFactor ) {
2014-02-19 09:15:05 -05:00
body . sleepCounter += 1 ;
if ( body . sleepCounter >= body . sleepThreshold )
Sleeping . set ( body , true ) ;
} else if ( body . sleepCounter > 0 ) {
body . sleepCounter -= 1 ;
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-07-29 11:26:49 -04:00
* Given a set of colliding pairs , wakes the sleeping bodies involved .
2014-02-28 20:10:08 -05:00
* @ method afterCollisions
* @ param { pair [ ] } pairs
2014-07-29 11:26:49 -04:00
* @ param { number } timeScale
2014-02-28 20:10:08 -05:00
* /
2014-07-29 11:26:49 -04:00
Sleeping . afterCollisions = function ( pairs , timeScale ) {
var timeFactor = timeScale * timeScale * timeScale ;
2014-02-19 09:15:05 -05:00
// wake up bodies involved in collisions
for ( var i = 0 ; i < pairs . length ; i ++ ) {
2014-03-11 06:29:14 -04:00
var pair = pairs [ i ] ;
// don't wake inactive pairs
if ( ! pair . isActive )
continue ;
var collision = pair . collision ,
2015-05-20 15:38:41 -04:00
bodyA = collision . bodyA . parent ,
bodyB = collision . bodyB . parent ;
2014-02-19 09:15:05 -05:00
2014-03-11 06:29:14 -04:00
// don't wake if at least one body is static
2014-02-19 09:15:05 -05:00
if ( ( bodyA . isSleeping && bodyB . isSleeping ) || bodyA . isStatic || bodyB . isStatic )
continue ;
if ( bodyA . isSleeping || bodyB . isSleeping ) {
var sleepingBody = ( bodyA . isSleeping && ! bodyA . isStatic ) ? bodyA : bodyB ,
movingBody = sleepingBody === bodyA ? bodyB : bodyA ;
2014-07-29 11:26:49 -04:00
if ( ! sleepingBody . isStatic && movingBody . motion > Sleeping . _motionWakeThreshold * timeFactor ) {
2014-02-19 09:15:05 -05:00
Sleeping . set ( sleepingBody , false ) ;
}
}
}
} ;
2015-05-21 19:33:26 -04:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Set a body as sleeping or awake .
2014-02-28 20:10:08 -05:00
* @ method set
* @ param { body } body
* @ param { boolean } isSleeping
* /
2014-02-19 09:15:05 -05:00
Sleeping . set = function ( body , isSleeping ) {
2015-06-29 15:58:24 -04:00
var wasSleeping = body . isSleeping ;
2014-02-19 09:15:05 -05:00
if ( isSleeping ) {
body . isSleeping = true ;
body . sleepCounter = body . sleepThreshold ;
body . positionImpulse . x = 0 ;
body . positionImpulse . y = 0 ;
body . positionPrev . x = body . position . x ;
body . positionPrev . y = body . position . y ;
body . anglePrev = body . angle ;
body . speed = 0 ;
body . angularSpeed = 0 ;
body . motion = 0 ;
2015-06-29 15:58:24 -04:00
if ( ! wasSleeping ) {
Events . trigger ( body , 'sleepStart' ) ;
}
2014-02-19 09:15:05 -05:00
} else {
body . isSleeping = false ;
body . sleepCounter = 0 ;
2015-06-29 15:58:24 -04:00
if ( wasSleeping ) {
Events . trigger ( body , 'sleepEnd' ) ;
}
2014-02-19 09:15:05 -05:00
}
} ;
} ) ( ) ;
2016-01-16 17:43:32 -05:00
2015-08-17 18:50:03 -04:00
} , { "./Events" : 16 } ] , 21 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Bodies ` module contains factory methods for creating rigid body models
* with commonly used body configurations ( such as rectangles , circles and other polygons ) .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class Bodies
* /
2014-02-19 09:15:05 -05:00
// TODO: true circle bodies
var Bodies = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Bodies ;
var Vertices = require ( '../geometry/Vertices' ) ;
var Common = require ( '../core/Common' ) ;
var Body = require ( '../body/Body' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
var Vector = require ( '../geometry/Vector' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new rigid body model with a rectangle hull .
* The options parameter is an object that specifies any properties you wish to override the defaults .
2015-01-01 18:10:10 -05:00
* See the properties section of the ` Matter.Body ` module for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method rectangle
* @ param { number } x
* @ param { number } y
* @ param { number } width
* @ param { number } height
2014-06-09 14:40:24 -04:00
* @ param { object } [ options ]
2014-02-28 20:10:08 -05:00
* @ return { body } A new rectangle body
* /
2014-02-19 09:15:05 -05:00
Bodies . rectangle = function ( x , y , width , height , options ) {
options = options || { } ;
var rectangle = {
2014-05-01 09:09:06 -04:00
label : 'Rectangle Body' ,
2014-03-22 13:51:49 -04:00
position : { x : x , y : y } ,
2014-05-05 14:32:51 -04:00
vertices : Vertices . fromPath ( 'L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height )
2014-03-22 13:51:49 -04:00
} ;
2014-02-19 09:15:05 -05:00
2014-05-05 14:32:51 -04:00
if ( options . chamfer ) {
var chamfer = options . chamfer ;
rectangle . vertices = Vertices . chamfer ( rectangle . vertices , chamfer . radius ,
chamfer . quality , chamfer . qualityMin , chamfer . qualityMax ) ;
delete options . chamfer ;
}
2014-02-19 09:15:05 -05:00
return Body . create ( Common . extend ( { } , rectangle , options ) ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new rigid body model with a trapezoid hull .
* The options parameter is an object that specifies any properties you wish to override the defaults .
2015-01-01 18:10:10 -05:00
* See the properties section of the ` Matter.Body ` module for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method trapezoid
* @ param { number } x
* @ param { number } y
* @ param { number } width
* @ param { number } height
* @ param { number } slope
2014-06-09 14:40:24 -04:00
* @ param { object } [ options ]
2014-02-28 20:10:08 -05:00
* @ return { body } A new trapezoid body
* /
2014-02-19 09:15:05 -05:00
Bodies . trapezoid = function ( x , y , width , height , slope , options ) {
options = options || { } ;
slope *= 0.5 ;
var roof = ( 1 - ( slope * 2 ) ) * width ;
var x1 = width * slope ,
x2 = x1 + roof ,
2015-12-23 08:08:54 -05:00
x3 = x2 + x1 ,
verticesPath ;
if ( slope < 0.5 ) {
verticesPath = 'L 0 0 L ' + x1 + ' ' + ( - height ) + ' L ' + x2 + ' ' + ( - height ) + ' L ' + x3 + ' 0' ;
} else {
verticesPath = 'L 0 0 L ' + x2 + ' ' + ( - height ) + ' L ' + x3 + ' 0' ;
}
2014-02-19 09:15:05 -05:00
var trapezoid = {
2014-05-01 09:09:06 -04:00
label : 'Trapezoid Body' ,
2014-03-22 13:51:49 -04:00
position : { x : x , y : y } ,
2015-12-23 08:08:54 -05:00
vertices : Vertices . fromPath ( verticesPath )
2014-03-22 13:51:49 -04:00
} ;
2014-02-19 09:15:05 -05:00
2014-05-05 14:32:51 -04:00
if ( options . chamfer ) {
var chamfer = options . chamfer ;
trapezoid . vertices = Vertices . chamfer ( trapezoid . vertices , chamfer . radius ,
chamfer . quality , chamfer . qualityMin , chamfer . qualityMax ) ;
delete options . chamfer ;
}
2014-02-19 09:15:05 -05:00
return Body . create ( Common . extend ( { } , trapezoid , options ) ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new rigid body model with a circle hull .
* The options parameter is an object that specifies any properties you wish to override the defaults .
2015-01-01 18:10:10 -05:00
* See the properties section of the ` Matter.Body ` module for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method circle
* @ param { number } x
* @ param { number } y
* @ param { number } radius
2014-06-09 14:40:24 -04:00
* @ param { object } [ options ]
2015-05-20 15:38:41 -04:00
* @ param { number } [ maxSides ]
2014-02-28 20:10:08 -05:00
* @ return { body } A new circle body
* /
2014-02-19 09:15:05 -05:00
Bodies . circle = function ( x , y , radius , options , maxSides ) {
options = options || { } ;
2016-02-15 16:24:17 -05:00
var circle = {
label : 'Circle Body' ,
circleRadius : radius
} ;
2014-02-19 09:15:05 -05:00
// approximate circles with polygons until true circles implemented in SAT
maxSides = maxSides || 25 ;
var sides = Math . ceil ( Math . max ( 10 , Math . min ( maxSides , radius ) ) ) ;
// optimisation: always use even number of sides (half the number of unique axes)
if ( sides % 2 === 1 )
sides += 1 ;
2016-02-15 16:24:17 -05:00
return Bodies . polygon ( x , y , sides , radius , Common . extend ( { } , circle , options ) ) ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new rigid body model with a regular polygon hull with the given number of sides .
* The options parameter is an object that specifies any properties you wish to override the defaults .
2015-01-01 18:10:10 -05:00
* See the properties section of the ` Matter.Body ` module for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method polygon
* @ param { number } x
* @ param { number } y
* @ param { number } sides
* @ param { number } radius
2014-06-09 14:40:24 -04:00
* @ param { object } [ options ]
2014-02-28 20:10:08 -05:00
* @ return { body } A new regular polygon body
* /
2014-02-19 09:15:05 -05:00
Bodies . polygon = function ( x , y , sides , radius , options ) {
options = options || { } ;
if ( sides < 3 )
return Bodies . circle ( x , y , radius , options ) ;
var theta = 2 * Math . PI / sides ,
path = '' ,
offset = theta * 0.5 ;
for ( var i = 0 ; i < sides ; i += 1 ) {
var angle = offset + ( i * theta ) ,
xx = Math . cos ( angle ) * radius ,
yy = Math . sin ( angle ) * radius ;
path += 'L ' + xx . toFixed ( 3 ) + ' ' + yy . toFixed ( 3 ) + ' ' ;
}
var polygon = {
2014-05-01 09:09:06 -04:00
label : 'Polygon Body' ,
2014-03-22 13:51:49 -04:00
position : { x : x , y : y } ,
2014-05-05 14:32:51 -04:00
vertices : Vertices . fromPath ( path )
2014-03-22 13:51:49 -04:00
} ;
2014-02-19 09:15:05 -05:00
2014-05-05 14:32:51 -04:00
if ( options . chamfer ) {
var chamfer = options . chamfer ;
polygon . vertices = Vertices . chamfer ( polygon . vertices , chamfer . radius ,
chamfer . quality , chamfer . qualityMin , chamfer . qualityMax ) ;
delete options . chamfer ;
}
2014-02-19 09:15:05 -05:00
return Body . create ( Common . extend ( { } , polygon , options ) ) ;
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Creates a body using the supplied vertices ( or an array containing multiple sets of vertices ) .
* If the vertices are convex , they will pass through as supplied .
* Otherwise if the vertices are concave , they will be decomposed if [ poly - decomp . js ] ( https : //github.com/schteppe/poly-decomp.js) is available.
* Note that this process is not guaranteed to support complex sets of vertices ( e . g . those with holes may fail ) .
* By default the decomposition will discard collinear edges ( to improve performance ) .
* It can also optionally discard any parts that have an area less than ` minimumArea ` .
* If the vertices can not be decomposed , the result will fall back to using the convex hull .
* The options parameter is an object that specifies any ` Matter.Body ` properties you wish to override the defaults .
* See the properties section of the ` Matter.Body ` module for detailed information on what you can pass via the ` options ` object .
* @ method fromVertices
* @ param { number } x
* @ param { number } y
* @ param [ [ vector ] ] vertexSets
* @ param { object } [ options ]
* @ param { bool } [ flagInternal = false ]
* @ param { number } [ removeCollinear = 0.01 ]
* @ param { number } [ minimumArea = 10 ]
* @ return { body }
* /
Bodies . fromVertices = function ( x , y , vertexSets , options , flagInternal , removeCollinear , minimumArea ) {
var body ,
parts ,
isConvex ,
vertices ,
i ,
j ,
k ,
v ,
z ;
options = options || { } ;
parts = [ ] ;
flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false ;
removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01 ;
minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10 ;
if ( ! window . decomp ) {
Common . log ( 'Bodies.fromVertices: poly-decomp.js required. Could not decompose vertices. Fallback to convex hull.' , 'warn' ) ;
}
// ensure vertexSets is an array of arrays
if ( ! Common . isArray ( vertexSets [ 0 ] ) ) {
vertexSets = [ vertexSets ] ;
}
for ( v = 0 ; v < vertexSets . length ; v += 1 ) {
vertices = vertexSets [ v ] ;
isConvex = Vertices . isConvex ( vertices ) ;
if ( isConvex || ! window . decomp ) {
if ( isConvex ) {
vertices = Vertices . clockwiseSort ( vertices ) ;
} else {
// fallback to convex hull when decomposition is not possible
vertices = Vertices . hull ( vertices ) ;
}
parts . push ( {
position : { x : x , y : y } ,
vertices : vertices
} ) ;
} else {
// initialise a decomposition
var concave = new decomp . Polygon ( ) ;
for ( i = 0 ; i < vertices . length ; i ++ ) {
concave . vertices . push ( [ vertices [ i ] . x , vertices [ i ] . y ] ) ;
}
// vertices are concave and simple, we can decompose into parts
concave . makeCCW ( ) ;
if ( removeCollinear !== false )
concave . removeCollinearPoints ( removeCollinear ) ;
// use the quick decomposition algorithm (Bayazit)
var decomposed = concave . quickDecomp ( ) ;
// for each decomposed chunk
for ( i = 0 ; i < decomposed . length ; i ++ ) {
var chunk = decomposed [ i ] ,
chunkVertices = [ ] ;
// convert vertices into the correct structure
for ( j = 0 ; j < chunk . vertices . length ; j ++ ) {
chunkVertices . push ( { x : chunk . vertices [ j ] [ 0 ] , y : chunk . vertices [ j ] [ 1 ] } ) ;
}
// skip small chunks
if ( minimumArea > 0 && Vertices . area ( chunkVertices ) < minimumArea )
continue ;
// create a compound part
parts . push ( {
position : Vertices . centre ( chunkVertices ) ,
vertices : chunkVertices
} ) ;
}
}
}
// create body parts
for ( i = 0 ; i < parts . length ; i ++ ) {
parts [ i ] = Body . create ( Common . extend ( parts [ i ] , options ) ) ;
}
// flag internal edges (coincident part edges)
if ( flagInternal ) {
var coincident _max _dist = 5 ;
for ( i = 0 ; i < parts . length ; i ++ ) {
var partA = parts [ i ] ;
for ( j = i + 1 ; j < parts . length ; j ++ ) {
var partB = parts [ j ] ;
if ( Bounds . overlaps ( partA . bounds , partB . bounds ) ) {
var pav = partA . vertices ,
pbv = partB . vertices ;
// iterate vertices of both parts
for ( k = 0 ; k < partA . vertices . length ; k ++ ) {
for ( z = 0 ; z < partB . vertices . length ; z ++ ) {
// find distances between the vertices
var da = Vector . magnitudeSquared ( Vector . sub ( pav [ ( k + 1 ) % pav . length ] , pbv [ z ] ) ) ,
db = Vector . magnitudeSquared ( Vector . sub ( pav [ k ] , pbv [ ( z + 1 ) % pbv . length ] ) ) ;
// if both vertices are very close, consider the edge concident (internal)
if ( da < coincident _max _dist && db < coincident _max _dist ) {
pav [ k ] . isInternal = true ;
pbv [ z ] . isInternal = true ;
}
}
}
}
}
}
}
if ( parts . length > 1 ) {
// create the parent body to be returned, that contains generated compound parts
body = Body . create ( Common . extend ( { parts : parts . slice ( 0 ) } , options ) ) ;
Body . setPosition ( body , { x : x , y : y } ) ;
return body ;
} else {
return parts [ 0 ] ;
}
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../body/Body" : 1 , "../core/Common" : 14 , "../geometry/Bounds" : 24 , "../geometry/Vector" : 26 , "../geometry/Vertices" : 27 } ] , 22 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Composites ` module contains factory methods for creating composite bodies
* with commonly used configurations ( such as stacks and chains ) .
*
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class Composites
* /
2014-02-19 09:15:05 -05:00
var Composites = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Composites ;
var Composite = require ( '../body/Composite' ) ;
var Constraint = require ( '../constraint/Constraint' ) ;
var Common = require ( '../core/Common' ) ;
var Body = require ( '../body/Body' ) ;
var Bodies = require ( './Bodies' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Create a new composite containing bodies created in the callback in a grid arrangement .
* This function uses the body ' s bounds to prevent overlaps .
2014-02-28 20:10:08 -05:00
* @ method stack
* @ param { number } xx
* @ param { number } yy
* @ param { number } columns
* @ param { number } rows
* @ param { number } columnGap
* @ param { number } rowGap
* @ param { function } callback
* @ return { composite } A new composite containing objects created in the callback
* /
2014-02-19 09:15:05 -05:00
Composites . stack = function ( xx , yy , columns , rows , columnGap , rowGap , callback ) {
2014-05-01 09:09:06 -04:00
var stack = Composite . create ( { label : 'Stack' } ) ,
2014-02-19 09:15:05 -05:00
x = xx ,
y = yy ,
lastBody ,
i = 0 ;
for ( var row = 0 ; row < rows ; row ++ ) {
var maxHeight = 0 ;
for ( var column = 0 ; column < columns ; column ++ ) {
var body = callback ( x , y , column , row , lastBody , i ) ;
if ( body ) {
var bodyHeight = body . bounds . max . y - body . bounds . min . y ,
bodyWidth = body . bounds . max . x - body . bounds . min . x ;
if ( bodyHeight > maxHeight )
maxHeight = bodyHeight ;
Body . translate ( body , { x : bodyWidth * 0.5 , y : bodyHeight * 0.5 } ) ;
x = body . bounds . max . x + columnGap ;
Composite . addBody ( stack , body ) ;
lastBody = body ;
i += 1 ;
2015-05-20 15:38:41 -04:00
} else {
x += columnGap ;
2014-02-19 09:15:05 -05:00
}
}
y += maxHeight + rowGap ;
x = xx ;
}
return stack ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Chains all bodies in the given composite together using constraints .
2014-02-28 20:10:08 -05:00
* @ method chain
* @ param { composite } composite
* @ param { number } xOffsetA
* @ param { number } yOffsetA
* @ param { number } xOffsetB
* @ param { number } yOffsetB
* @ param { object } options
* @ return { composite } A new composite containing objects chained together with constraints
* /
2014-02-19 09:15:05 -05:00
Composites . chain = function ( composite , xOffsetA , yOffsetA , xOffsetB , yOffsetB , options ) {
var bodies = composite . bodies ;
for ( var i = 1 ; i < bodies . length ; i ++ ) {
var bodyA = bodies [ i - 1 ] ,
bodyB = bodies [ i ] ,
bodyAHeight = bodyA . bounds . max . y - bodyA . bounds . min . y ,
bodyAWidth = bodyA . bounds . max . x - bodyA . bounds . min . x ,
bodyBHeight = bodyB . bounds . max . y - bodyB . bounds . min . y ,
bodyBWidth = bodyB . bounds . max . x - bodyB . bounds . min . x ;
var defaults = {
bodyA : bodyA ,
pointA : { x : bodyAWidth * xOffsetA , y : bodyAHeight * yOffsetA } ,
bodyB : bodyB ,
pointB : { x : bodyBWidth * xOffsetB , y : bodyBHeight * yOffsetB }
} ;
var constraint = Common . extend ( defaults , options ) ;
Composite . addConstraint ( composite , Constraint . create ( constraint ) ) ;
}
2014-05-01 09:09:06 -04:00
composite . label += ' Chain' ;
2014-02-19 09:15:05 -05:00
return composite ;
} ;
2014-03-30 14:45:30 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Connects bodies in the composite with constraints in a grid pattern , with optional cross braces .
2014-03-30 14:45:30 -04:00
* @ method mesh
* @ param { composite } composite
* @ param { number } columns
* @ param { number } rows
* @ param { boolean } crossBrace
* @ param { object } options
* @ return { composite } The composite containing objects meshed together with constraints
* /
Composites . mesh = function ( composite , columns , rows , crossBrace , options ) {
var bodies = composite . bodies ,
row ,
col ,
bodyA ,
bodyB ,
bodyC ;
for ( row = 0 ; row < rows ; row ++ ) {
2015-05-21 19:33:26 -04:00
for ( col = 1 ; col < columns ; col ++ ) {
bodyA = bodies [ ( col - 1 ) + ( row * columns ) ] ;
bodyB = bodies [ col + ( row * columns ) ] ;
Composite . addConstraint ( composite , Constraint . create ( Common . extend ( { bodyA : bodyA , bodyB : bodyB } , options ) ) ) ;
2014-03-30 14:45:30 -04:00
}
2015-05-21 19:33:26 -04:00
if ( row > 0 ) {
for ( col = 0 ; col < columns ; col ++ ) {
2014-03-30 14:45:30 -04:00
bodyA = bodies [ col + ( ( row - 1 ) * columns ) ] ;
bodyB = bodies [ col + ( row * columns ) ] ;
Composite . addConstraint ( composite , Constraint . create ( Common . extend ( { bodyA : bodyA , bodyB : bodyB } , options ) ) ) ;
if ( crossBrace && col > 0 ) {
bodyC = bodies [ ( col - 1 ) + ( ( row - 1 ) * columns ) ] ;
Composite . addConstraint ( composite , Constraint . create ( Common . extend ( { bodyA : bodyC , bodyB : bodyB } , options ) ) ) ;
}
if ( crossBrace && col < columns - 1 ) {
bodyC = bodies [ ( col + 1 ) + ( ( row - 1 ) * columns ) ] ;
Composite . addConstraint ( composite , Constraint . create ( Common . extend ( { bodyA : bodyC , bodyB : bodyB } , options ) ) ) ;
}
}
}
}
2014-05-01 09:09:06 -04:00
composite . label += ' Mesh' ;
2014-03-30 14:45:30 -04:00
return composite ;
} ;
2014-02-19 09:15:05 -05:00
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Create a new composite containing bodies created in the callback in a pyramid arrangement .
* This function uses the body ' s bounds to prevent overlaps .
2014-02-28 20:10:08 -05:00
* @ method pyramid
* @ param { number } xx
* @ param { number } yy
* @ param { number } columns
* @ param { number } rows
* @ param { number } columnGap
* @ param { number } rowGap
* @ param { function } callback
* @ return { composite } A new composite containing objects created in the callback
* /
2014-02-19 09:15:05 -05:00
Composites . pyramid = function ( xx , yy , columns , rows , columnGap , rowGap , callback ) {
return Composites . stack ( xx , yy , columns , rows , columnGap , rowGap , function ( x , y , column , row , lastBody , i ) {
var actualRows = Math . min ( rows , Math . ceil ( columns / 2 ) ) ,
lastBodyWidth = lastBody ? lastBody . bounds . max . x - lastBody . bounds . min . x : 0 ;
if ( row > actualRows )
return ;
// reverse row order
row = actualRows - row ;
var start = row ,
end = columns - 1 - row ;
if ( column < start || column > end )
return ;
// retroactively fix the first body's position, since width was unknown
if ( i === 1 ) {
Body . translate ( lastBody , { x : ( column + ( columns % 2 === 1 ? 1 : - 1 ) ) * lastBodyWidth , y : 0 } ) ;
}
var xOffset = lastBody ? column * lastBodyWidth : 0 ;
return callback ( xx + xOffset + column * columnGap , y , column , row , lastBody , i ) ;
} ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a composite with a Newton ' s Cradle setup of bodies and constraints .
2014-02-28 20:10:08 -05:00
* @ method newtonsCradle
* @ param { number } xx
* @ param { number } yy
* @ param { number } number
* @ param { number } size
* @ param { number } length
* @ return { composite } A new composite newtonsCradle body
* /
2014-02-19 09:15:05 -05:00
Composites . newtonsCradle = function ( xx , yy , number , size , length ) {
2014-05-01 09:09:06 -04:00
var newtonsCradle = Composite . create ( { label : 'Newtons Cradle' } ) ;
2014-02-19 09:15:05 -05:00
for ( var i = 0 ; i < number ; i ++ ) {
var separation = 1.9 ,
circle = Bodies . circle ( xx + i * ( size * separation ) , yy + length , size ,
2015-12-23 08:08:54 -05:00
{ inertia : Infinity , restitution : 1 , friction : 0 , frictionAir : 0.0001 , slop : 1 } ) ,
2014-02-19 09:15:05 -05:00
constraint = Constraint . create ( { pointA : { x : xx + i * ( size * separation ) , y : yy } , bodyB : circle } ) ;
Composite . addBody ( newtonsCradle , circle ) ;
Composite . addConstraint ( newtonsCradle , constraint ) ;
}
return newtonsCradle ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a composite with simple car setup of bodies and constraints .
2014-02-28 20:10:08 -05:00
* @ method car
* @ param { number } xx
* @ param { number } yy
* @ param { number } width
* @ param { number } height
* @ param { number } wheelSize
* @ return { composite } A new composite car body
* /
2014-02-19 09:15:05 -05:00
Composites . car = function ( xx , yy , width , height , wheelSize ) {
2014-07-29 11:26:49 -04:00
var group = Body . nextGroup ( true ) ,
2014-02-19 09:15:05 -05:00
wheelBase = - 20 ,
wheelAOffset = - width * 0.5 + wheelBase ,
wheelBOffset = width * 0.5 - wheelBase ,
wheelYOffset = 0 ;
2014-05-01 09:09:06 -04:00
var car = Composite . create ( { label : 'Car' } ) ,
2014-05-05 14:32:51 -04:00
body = Bodies . trapezoid ( xx , yy , width , height , 0.3 , {
2014-07-29 11:26:49 -04:00
collisionFilter : {
group : group
} ,
2014-05-05 14:32:51 -04:00
friction : 0.01 ,
chamfer : {
radius : 10
}
} ) ;
2014-02-19 09:15:05 -05:00
var wheelA = Bodies . circle ( xx + wheelAOffset , yy + wheelYOffset , wheelSize , {
2014-07-29 11:26:49 -04:00
collisionFilter : {
group : group
} ,
2016-01-16 17:43:32 -05:00
friction : 0.8 ,
2014-02-19 09:15:05 -05:00
density : 0.01
} ) ;
var wheelB = Bodies . circle ( xx + wheelBOffset , yy + wheelYOffset , wheelSize , {
2014-07-29 11:26:49 -04:00
collisionFilter : {
group : group
} ,
2016-01-16 17:43:32 -05:00
friction : 0.8 ,
2014-02-19 09:15:05 -05:00
density : 0.01
} ) ;
var axelA = Constraint . create ( {
bodyA : body ,
pointA : { x : wheelAOffset , y : wheelYOffset } ,
bodyB : wheelA ,
2016-01-16 17:43:32 -05:00
stiffness : 0.2
2014-02-19 09:15:05 -05:00
} ) ;
var axelB = Constraint . create ( {
bodyA : body ,
pointA : { x : wheelBOffset , y : wheelYOffset } ,
bodyB : wheelB ,
2016-01-16 17:43:32 -05:00
stiffness : 0.2
2014-02-19 09:15:05 -05:00
} ) ;
Composite . addBody ( car , body ) ;
Composite . addBody ( car , wheelA ) ;
Composite . addBody ( car , wheelB ) ;
Composite . addConstraint ( car , axelA ) ;
Composite . addConstraint ( car , axelB ) ;
return car ;
} ;
2014-03-30 14:45:30 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a simple soft body like object .
2014-03-30 14:45:30 -04:00
* @ method softBody
* @ param { number } xx
* @ param { number } yy
* @ param { number } columns
* @ param { number } rows
* @ param { number } columnGap
* @ param { number } rowGap
* @ param { boolean } crossBrace
* @ param { number } particleRadius
* @ param { } particleOptions
* @ param { } constraintOptions
* @ return { composite } A new composite softBody
* /
Composites . softBody = function ( xx , yy , columns , rows , columnGap , rowGap , crossBrace , particleRadius , particleOptions , constraintOptions ) {
particleOptions = Common . extend ( { inertia : Infinity } , particleOptions ) ;
constraintOptions = Common . extend ( { stiffness : 0.4 } , constraintOptions ) ;
2015-01-01 18:10:10 -05:00
var softBody = Composites . stack ( xx , yy , columns , rows , columnGap , rowGap , function ( x , y ) {
2014-03-30 14:45:30 -04:00
return Bodies . circle ( x , y , particleRadius , particleOptions ) ;
} ) ;
Composites . mesh ( softBody , columns , rows , crossBrace , constraintOptions ) ;
2014-05-01 09:09:06 -04:00
softBody . label = 'Soft Body' ;
2014-03-30 14:45:30 -04:00
return softBody ;
} ;
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../body/Body" : 1 , "../body/Composite" : 2 , "../constraint/Constraint" : 12 , "../core/Common" : 14 , "./Bodies" : 21 } ] , 23 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Axes ` module contains methods for creating and manipulating sets of axes .
2014-02-28 20:10:08 -05:00
*
* @ class Axes
* /
2014-02-19 09:15:05 -05:00
var Axes = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Axes ;
var Vector = require ( '../geometry/Vector' ) ;
var Common = require ( '../core/Common' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a new set of axes from the given vertices .
2014-02-28 20:10:08 -05:00
* @ method fromVertices
* @ param { vertices } vertices
* @ return { axes } A new axes from the given vertices
* /
2014-02-19 09:15:05 -05:00
Axes . fromVertices = function ( vertices ) {
var axes = { } ;
// find the unique axes, using edge normal gradients
for ( var i = 0 ; i < vertices . length ; i ++ ) {
var j = ( i + 1 ) % vertices . length ,
normal = Vector . normalise ( {
x : vertices [ j ] . y - vertices [ i ] . y ,
y : vertices [ i ] . x - vertices [ j ] . x
} ) ,
gradient = ( normal . y === 0 ) ? Infinity : ( normal . x / normal . y ) ;
// limit precision
gradient = gradient . toFixed ( 3 ) . toString ( ) ;
axes [ gradient ] = normal ;
}
return Common . values ( axes ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Rotates a set of axes by the given angle .
2014-02-28 20:10:08 -05:00
* @ method rotate
* @ param { axes } axes
* @ param { number } angle
* /
2014-02-19 09:15:05 -05:00
Axes . rotate = function ( axes , angle ) {
if ( angle === 0 )
return ;
var cos = Math . cos ( angle ) ,
sin = Math . sin ( angle ) ;
for ( var i = 0 ; i < axes . length ; i ++ ) {
var axis = axes [ i ] ,
xx ;
xx = axis . x * cos - axis . y * sin ;
axis . y = axis . x * sin + axis . y * cos ;
axis . x = xx ;
}
} ;
} ) ( ) ;
2016-01-16 17:43:32 -05:00
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "../geometry/Vector" : 26 } ] , 24 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* The ` Matter.Bounds ` module contains methods for creating and manipulating axis - aligned bounding boxes ( AABB ) .
2014-02-28 20:10:08 -05:00
*
* @ class Bounds
* /
2014-02-19 09:15:05 -05:00
var Bounds = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Bounds ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Creates a new axis - aligned bounding box ( AABB ) for the given vertices .
2014-02-28 20:10:08 -05:00
* @ method create
* @ param { vertices } vertices
* @ return { bounds } A new bounds object
* /
2014-02-19 09:15:05 -05:00
Bounds . create = function ( vertices ) {
var bounds = {
min : { x : 0 , y : 0 } ,
max : { x : 0 , y : 0 }
} ;
2014-05-01 09:09:06 -04:00
if ( vertices )
Bounds . update ( bounds , vertices ) ;
2014-02-19 09:15:05 -05:00
return bounds ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Updates bounds using the given vertices and extends the bounds given a velocity .
2014-02-28 20:10:08 -05:00
* @ method update
* @ param { bounds } bounds
* @ param { vertices } vertices
* @ param { vector } velocity
* /
2014-02-19 09:15:05 -05:00
Bounds . update = function ( bounds , vertices , velocity ) {
2016-02-07 10:53:07 -05:00
bounds . min . x = Infinity ;
bounds . max . x = - Infinity ;
bounds . min . y = Infinity ;
bounds . max . y = - Infinity ;
2014-02-19 09:15:05 -05:00
for ( var i = 0 ; i < vertices . length ; i ++ ) {
var vertex = vertices [ i ] ;
if ( vertex . x > bounds . max . x ) bounds . max . x = vertex . x ;
if ( vertex . x < bounds . min . x ) bounds . min . x = vertex . x ;
if ( vertex . y > bounds . max . y ) bounds . max . y = vertex . y ;
if ( vertex . y < bounds . min . y ) bounds . min . y = vertex . y ;
}
if ( velocity ) {
if ( velocity . x > 0 ) {
bounds . max . x += velocity . x ;
} else {
bounds . min . x += velocity . x ;
}
if ( velocity . y > 0 ) {
bounds . max . y += velocity . y ;
} else {
bounds . min . y += velocity . y ;
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns true if the bounds contains the given point .
2014-02-28 20:10:08 -05:00
* @ method contains
* @ param { bounds } bounds
* @ param { vector } point
* @ return { boolean } True if the bounds contain the point , otherwise false
* /
2014-02-19 09:15:05 -05:00
Bounds . contains = function ( bounds , point ) {
return point . x >= bounds . min . x && point . x <= bounds . max . x
&& point . y >= bounds . min . y && point . y <= bounds . max . y ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2016-01-16 17:43:32 -05:00
* Returns true if the two bounds intersect .
2014-02-28 20:10:08 -05:00
* @ method overlaps
* @ param { bounds } boundsA
* @ param { bounds } boundsB
* @ return { boolean } True if the bounds overlap , otherwise false
* /
2014-02-19 09:15:05 -05:00
Bounds . overlaps = function ( boundsA , boundsB ) {
return ( boundsA . min . x <= boundsB . max . x && boundsA . max . x >= boundsB . min . x
&& boundsA . max . y >= boundsB . min . y && boundsA . min . y <= boundsB . max . y ) ;
} ;
2014-05-01 09:09:06 -04:00
/ * *
2016-01-16 17:43:32 -05:00
* Translates the bounds by the given vector .
2014-05-01 09:09:06 -04:00
* @ method translate
* @ param { bounds } bounds
* @ param { vector } vector
* /
Bounds . translate = function ( bounds , vector ) {
bounds . min . x += vector . x ;
bounds . max . x += vector . x ;
bounds . min . y += vector . y ;
bounds . max . y += vector . y ;
} ;
/ * *
2016-01-16 17:43:32 -05:00
* Shifts the bounds to the given position .
2014-05-01 09:09:06 -04:00
* @ method shift
* @ param { bounds } bounds
* @ param { vector } position
* /
Bounds . shift = function ( bounds , position ) {
var deltaX = bounds . max . x - bounds . min . x ,
deltaY = bounds . max . y - bounds . min . y ;
bounds . min . x = position . x ;
bounds . max . x = position . x + deltaX ;
bounds . min . y = position . y ;
bounds . max . y = position . y + deltaY ;
} ;
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2016-01-16 17:43:32 -05:00
2015-08-17 18:50:03 -04:00
} , { } ] , 25 : [ function ( require , module , exports ) {
2015-05-20 15:38:41 -04:00
/ * *
* The ` Matter.Svg ` module contains methods for converting SVG images into an array of vector points .
*
2016-02-07 10:53:07 -05:00
* To use this module you also need the SVGPathSeg polyfill : https : //github.com/progers/pathseg
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2015-05-20 15:38:41 -04:00
*
* @ class Svg
* /
var Svg = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Svg ;
var Bounds = require ( '../geometry/Bounds' ) ;
2015-05-20 15:38:41 -04:00
( function ( ) {
/ * *
* Converts an SVG path into an array of vector points .
* If the input path forms a concave shape , you must decompose the result into convex parts before use .
* See ` Bodies.fromVertices ` which provides support for this .
* Note that this function is not guaranteed to support complex paths ( such as those with holes ) .
* @ method pathToVertices
* @ param { SVGPathElement } path
* @ param { Number } [ sampleLength = 15 ]
* @ return { Vector [ ] } points
* /
Svg . pathToVertices = function ( path , sampleLength ) {
// https://github.com/wout/svg.topoly.js/blob/master/svg.topoly.js
var i , il , total , point , segment , segments ,
segmentsQueue , lastSegment ,
lastPoint , segmentIndex , points = [ ] ,
2015-07-02 15:17:03 -04:00
lx , ly , length = 0 , x = 0 , y = 0 ;
2015-05-20 15:38:41 -04:00
sampleLength = sampleLength || 15 ;
var addPoint = function ( px , py , pathSegType ) {
// all odd-numbered path types are relative except PATHSEG_CLOSEPATH (1)
var isRelative = pathSegType % 2 === 1 && pathSegType > 1 ;
// when the last point doesn't equal the current point add the current point
if ( ! lastPoint || px != lastPoint . x || py != lastPoint . y ) {
if ( lastPoint && isRelative ) {
lx = lastPoint . x ;
ly = lastPoint . y ;
} else {
lx = 0 ;
ly = 0 ;
}
var point = {
x : lx + px ,
y : ly + py
} ;
// set last point
if ( isRelative || ! lastPoint ) {
lastPoint = point ;
}
points . push ( point ) ;
x = lx + px ;
y = ly + py ;
}
} ;
var addSegmentPoint = function ( segment ) {
var segType = segment . pathSegTypeAsLetter . toUpperCase ( ) ;
// skip path ends
if ( segType === 'Z' )
return ;
// map segment to x and y
switch ( segType ) {
case 'M' :
case 'L' :
case 'T' :
case 'C' :
case 'S' :
case 'Q' :
x = segment . x ;
y = segment . y ;
break ;
case 'H' :
x = segment . x ;
break ;
case 'V' :
y = segment . y ;
break ;
}
addPoint ( x , y , segment . pathSegType ) ;
} ;
// ensure path is absolute
_svgPathToAbsolute ( path ) ;
// get total length
total = path . getTotalLength ( ) ;
// queue segments
segments = [ ] ;
for ( i = 0 ; i < path . pathSegList . numberOfItems ; i += 1 )
segments . push ( path . pathSegList . getItem ( i ) ) ;
segmentsQueue = segments . concat ( ) ;
// sample through path
while ( length < total ) {
// get segment at position
segmentIndex = path . getPathSegAtLength ( length ) ;
segment = segments [ segmentIndex ] ;
// new segment
if ( segment != lastSegment ) {
while ( segmentsQueue . length && segmentsQueue [ 0 ] != segment )
addSegmentPoint ( segmentsQueue . shift ( ) ) ;
lastSegment = segment ;
}
// add points in between when curving
// TODO: adaptive sampling
switch ( segment . pathSegTypeAsLetter . toUpperCase ( ) ) {
case 'C' :
case 'T' :
case 'S' :
case 'Q' :
case 'A' :
point = path . getPointAtLength ( length ) ;
addPoint ( point . x , point . y , 0 ) ;
break ;
}
// increment by sample value
length += sampleLength ;
}
// add remaining segments not passed by sampling
for ( i = 0 , il = segmentsQueue . length ; i < il ; ++ i )
addSegmentPoint ( segmentsQueue [ i ] ) ;
return points ;
} ;
var _svgPathToAbsolute = function ( path ) {
// http://phrogz.net/convert-svg-path-to-all-absolute-commands
var x0 , y0 , x1 , y1 , x2 , y2 , segs = path . pathSegList ,
x = 0 , y = 0 , len = segs . numberOfItems ;
for ( var i = 0 ; i < len ; ++ i ) {
var seg = segs . getItem ( i ) ,
segType = seg . pathSegTypeAsLetter ;
if ( /[MLHVCSQTA]/ . test ( segType ) ) {
if ( 'x' in seg ) x = seg . x ;
if ( 'y' in seg ) y = seg . y ;
} else {
if ( 'x1' in seg ) x1 = x + seg . x1 ;
if ( 'x2' in seg ) x2 = x + seg . x2 ;
if ( 'y1' in seg ) y1 = y + seg . y1 ;
if ( 'y2' in seg ) y2 = y + seg . y2 ;
if ( 'x' in seg ) x += seg . x ;
if ( 'y' in seg ) y += seg . y ;
switch ( segType ) {
case 'm' :
segs . replaceItem ( path . createSVGPathSegMovetoAbs ( x , y ) , i ) ;
break ;
case 'l' :
segs . replaceItem ( path . createSVGPathSegLinetoAbs ( x , y ) , i ) ;
break ;
case 'h' :
segs . replaceItem ( path . createSVGPathSegLinetoHorizontalAbs ( x ) , i ) ;
break ;
case 'v' :
segs . replaceItem ( path . createSVGPathSegLinetoVerticalAbs ( y ) , i ) ;
break ;
case 'c' :
segs . replaceItem ( path . createSVGPathSegCurvetoCubicAbs ( x , y , x1 , y1 , x2 , y2 ) , i ) ;
break ;
case 's' :
segs . replaceItem ( path . createSVGPathSegCurvetoCubicSmoothAbs ( x , y , x2 , y2 ) , i ) ;
break ;
case 'q' :
segs . replaceItem ( path . createSVGPathSegCurvetoQuadraticAbs ( x , y , x1 , y1 ) , i ) ;
break ;
case 't' :
segs . replaceItem ( path . createSVGPathSegCurvetoQuadraticSmoothAbs ( x , y ) , i ) ;
break ;
case 'a' :
segs . replaceItem ( path . createSVGPathSegArcAbs ( x , y , seg . r1 , seg . r2 , seg . angle , seg . largeArcFlag , seg . sweepFlag ) , i ) ;
break ;
case 'z' :
case 'Z' :
x = x0 ;
y = y0 ;
break ;
}
}
if ( segType == 'M' || segType == 'm' ) {
x0 = x ;
y0 = y ;
}
}
} ;
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../geometry/Bounds" : 24 } ] , 26 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Vector ` module contains methods for creating and manipulating vectors .
* Vectors are the basis of all the geometry related operations in the engine .
* A ` Matter.Vector ` object is of the form ` { x: 0, y: 0 } ` .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class Vector
* /
2014-02-19 09:15:05 -05:00
// TODO: consider params for reusing vector objects
var Vector = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Vector ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2015-05-20 15:38:41 -04:00
/ * *
* Creates a new vector .
* @ method create
* @ param { number } x
* @ param { number } y
* @ return { vector } A new vector
* /
Vector . create = function ( x , y ) {
return { x : x || 0 , y : y || 0 } ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns a new vector with ` x ` and ` y ` copied from the given ` vector ` .
* @ method clone
* @ param { vector } vector
* @ return { vector } A new cloned vector
* /
Vector . clone = function ( vector ) {
return { x : vector . x , y : vector . y } ;
} ;
/ * *
* Returns the magnitude ( length ) of a vector .
2014-02-28 20:10:08 -05:00
* @ method magnitude
* @ param { vector } vector
* @ return { number } The magnitude of the vector
* /
2014-02-19 09:15:05 -05:00
Vector . magnitude = function ( vector ) {
return Math . sqrt ( ( vector . x * vector . x ) + ( vector . y * vector . y ) ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the magnitude ( length ) of a vector ( therefore saving a ` sqrt ` operation ) .
2014-02-28 20:10:08 -05:00
* @ method magnitudeSquared
* @ param { vector } vector
* @ return { number } The squared magnitude of the vector
* /
2014-02-19 09:15:05 -05:00
Vector . magnitudeSquared = function ( vector ) {
return ( vector . x * vector . x ) + ( vector . y * vector . y ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Rotates the vector about ( 0 , 0 ) by specified angle .
2014-02-28 20:10:08 -05:00
* @ method rotate
* @ param { vector } vector
* @ param { number } angle
2014-06-09 14:40:24 -04:00
* @ return { vector } A new vector rotated about ( 0 , 0 )
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
Vector . rotate = function ( vector , angle ) {
var cos = Math . cos ( angle ) , sin = Math . sin ( angle ) ;
return {
x : vector . x * cos - vector . y * sin ,
y : vector . x * sin + vector . y * cos
} ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Rotates the vector about a specified point by specified angle .
2014-02-28 20:10:08 -05:00
* @ method rotateAbout
* @ param { vector } vector
* @ param { number } angle
* @ param { vector } point
2015-05-20 15:38:41 -04:00
* @ param { vector } [ output ]
2014-02-28 20:10:08 -05:00
* @ return { vector } A new vector rotated about the point
* /
2015-05-20 15:38:41 -04:00
Vector . rotateAbout = function ( vector , angle , point , output ) {
2014-02-19 09:15:05 -05:00
var cos = Math . cos ( angle ) , sin = Math . sin ( angle ) ;
2015-05-20 15:38:41 -04:00
if ( ! output ) output = { } ;
var x = point . x + ( ( vector . x - point . x ) * cos - ( vector . y - point . y ) * sin ) ;
output . y = point . y + ( ( vector . x - point . x ) * sin + ( vector . y - point . y ) * cos ) ;
output . x = x ;
return output ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Normalises a vector ( such that its magnitude is ` 1 ` ) .
2014-02-28 20:10:08 -05:00
* @ method normalise
* @ param { vector } vector
* @ return { vector } A new vector normalised
* /
2014-02-19 09:15:05 -05:00
Vector . normalise = function ( vector ) {
var magnitude = Vector . magnitude ( vector ) ;
if ( magnitude === 0 )
return { x : 0 , y : 0 } ;
return { x : vector . x / magnitude , y : vector . y / magnitude } ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the dot - product of two vectors .
2014-02-28 20:10:08 -05:00
* @ method dot
* @ param { vector } vectorA
* @ param { vector } vectorB
* @ return { number } The dot product of the two vectors
* /
2014-02-19 09:15:05 -05:00
Vector . dot = function ( vectorA , vectorB ) {
return ( vectorA . x * vectorB . x ) + ( vectorA . y * vectorB . y ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the cross - product of two vectors .
2014-02-28 20:10:08 -05:00
* @ method cross
* @ param { vector } vectorA
* @ param { vector } vectorB
* @ return { number } The cross product of the two vectors
* /
2014-02-19 09:15:05 -05:00
Vector . cross = function ( vectorA , vectorB ) {
return ( vectorA . x * vectorB . y ) - ( vectorA . y * vectorB . x ) ;
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Returns the cross - product of three vectors .
* @ method cross3
* @ param { vector } vectorA
* @ param { vector } vectorB
* @ param { vector } vectorC
* @ return { number } The cross product of the three vectors
* /
Vector . cross3 = function ( vectorA , vectorB , vectorC ) {
return ( vectorB . x - vectorA . x ) * ( vectorC . y - vectorA . y ) - ( vectorB . y - vectorA . y ) * ( vectorC . x - vectorA . x ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Adds the two vectors .
2014-02-28 20:10:08 -05:00
* @ method add
* @ param { vector } vectorA
* @ param { vector } vectorB
2015-05-20 15:38:41 -04:00
* @ param { vector } [ output ]
2014-06-09 14:40:24 -04:00
* @ return { vector } A new vector of vectorA and vectorB added
2014-02-28 20:10:08 -05:00
* /
2015-05-20 15:38:41 -04:00
Vector . add = function ( vectorA , vectorB , output ) {
if ( ! output ) output = { } ;
output . x = vectorA . x + vectorB . x ;
output . y = vectorA . y + vectorB . y ;
return output ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Subtracts the two vectors .
2014-02-28 20:10:08 -05:00
* @ method sub
* @ param { vector } vectorA
* @ param { vector } vectorB
2015-05-20 15:38:41 -04:00
* @ param { vector } [ output ]
2014-06-09 14:40:24 -04:00
* @ return { vector } A new vector of vectorA and vectorB subtracted
2014-02-28 20:10:08 -05:00
* /
2015-05-20 15:38:41 -04:00
Vector . sub = function ( vectorA , vectorB , output ) {
if ( ! output ) output = { } ;
output . x = vectorA . x - vectorB . x ;
output . y = vectorA . y - vectorB . y ;
return output ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Multiplies a vector and a scalar .
2014-02-28 20:10:08 -05:00
* @ method mult
* @ param { vector } vector
* @ param { number } scalar
* @ return { vector } A new vector multiplied by scalar
* /
2014-02-19 09:15:05 -05:00
Vector . mult = function ( vector , scalar ) {
return { x : vector . x * scalar , y : vector . y * scalar } ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Divides a vector and a scalar .
2014-02-28 20:10:08 -05:00
* @ method div
* @ param { vector } vector
* @ param { number } scalar
* @ return { vector } A new vector divided by scalar
* /
2014-02-19 09:15:05 -05:00
Vector . div = function ( vector , scalar ) {
return { x : vector . x / scalar , y : vector . y / scalar } ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the perpendicular vector . Set ` negate ` to true for the perpendicular in the opposite direction .
2014-02-28 20:10:08 -05:00
* @ method perp
* @ param { vector } vector
2014-06-09 14:40:24 -04:00
* @ param { bool } [ negate = false ]
2014-02-28 20:10:08 -05:00
* @ return { vector } The perpendicular vector
* /
2014-02-19 09:15:05 -05:00
Vector . perp = function ( vector , negate ) {
negate = negate === true ? - 1 : 1 ;
return { x : negate * - vector . y , y : negate * vector . x } ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Negates both components of a vector such that it points in the opposite direction .
2014-02-28 20:10:08 -05:00
* @ method neg
* @ param { vector } vector
* @ return { vector } The negated vector
* /
2014-02-19 09:15:05 -05:00
Vector . neg = function ( vector ) {
return { x : - vector . x , y : - vector . y } ;
} ;
2014-05-01 09:09:06 -04:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the angle in radians between the two vectors relative to the x - axis .
2014-05-01 09:09:06 -04:00
* @ method angle
* @ param { vector } vectorA
* @ param { vector } vectorB
* @ return { number } The angle in radians
* /
Vector . angle = function ( vectorA , vectorB ) {
return Math . atan2 ( vectorB . y - vectorA . y , vectorB . x - vectorA . x ) ;
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Temporary vector pool ( not thread - safe ) .
* @ property _temp
* @ type { vector [ ] }
* @ private
* /
Vector . _temp = [ Vector . create ( ) , Vector . create ( ) ,
Vector . create ( ) , Vector . create ( ) ,
Vector . create ( ) , Vector . create ( ) ] ;
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { } ] , 27 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Vertices ` module contains methods for creating and manipulating sets of vertices .
* A set of vertices is an array of ` Matter.Vector ` with additional indexing properties inserted by ` Vertices.create ` .
* A ` Matter.Body ` maintains a set of vertices to represent the shape of the object ( its convex hull ) .
*
2016-01-16 17:43:32 -05:00
* See the included usage [ examples ] ( https : //github.com/liabru/matter-js/tree/master/examples).
2014-02-28 20:10:08 -05:00
*
* @ class Vertices
* /
2014-02-19 09:15:05 -05:00
var Vertices = { } ;
2015-08-17 18:50:03 -04:00
module . exports = Vertices ;
var Vector = require ( '../geometry/Vector' ) ;
var Common = require ( '../core/Common' ) ;
2014-02-19 09:15:05 -05:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new set of ` Matter.Body ` compatible vertices .
* The ` points ` argument accepts an array of ` Matter.Vector ` points orientated around the origin ` (0, 0) ` , for example :
*
* [ { x : 0 , y : 0 } , { x : 25 , y : 50 } , { x : 50 , y : 0 } ]
*
* The ` Vertices.create ` method returns a new array of vertices , which are similar to Matter . Vector objects ,
* but with some additional references required for efficient collision detection routines .
*
* Note that the ` body ` argument is not optional , a ` Matter.Body ` reference must be provided .
*
2014-02-28 20:10:08 -05:00
* @ method create
2014-06-09 14:40:24 -04:00
* @ param { vector [ ] } points
2014-02-28 20:10:08 -05:00
* @ param { body } body
* /
2014-06-09 14:40:24 -04:00
Vertices . create = function ( points , body ) {
var vertices = [ ] ;
for ( var i = 0 ; i < points . length ; i ++ ) {
var point = points [ i ] ,
2015-05-20 15:38:41 -04:00
vertex = {
x : point . x ,
y : point . y ,
index : i ,
body : body ,
isInternal : false
} ;
2014-06-09 14:40:24 -04:00
vertices . push ( vertex ) ;
2014-02-19 09:15:05 -05:00
}
2014-06-09 14:40:24 -04:00
return vertices ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2015-05-20 15:38:41 -04:00
* Parses a string containing ordered x y pairs separated by spaces ( and optionally commas ) ,
* into a ` Matter.Vertices ` object for the given ` Matter.Body ` .
* For parsing SVG paths , see ` Svg.pathToVertices ` .
2014-02-28 20:10:08 -05:00
* @ method fromPath
* @ param { string } path
2014-06-09 14:40:24 -04:00
* @ param { body } body
2014-02-28 20:10:08 -05:00
* @ return { vertices } vertices
* /
2014-06-09 14:40:24 -04:00
Vertices . fromPath = function ( path , body ) {
2015-05-20 15:38:41 -04:00
var pathPattern = /L?\s*([\-\d\.e]+)[\s,]*([\-\d\.e]+)*/ig ,
2014-06-09 14:40:24 -04:00
points = [ ] ;
2014-02-19 09:15:05 -05:00
path . replace ( pathPattern , function ( match , x , y ) {
2015-01-01 18:10:10 -05:00
points . push ( { x : parseFloat ( x ) , y : parseFloat ( y ) } ) ;
2014-02-19 09:15:05 -05:00
} ) ;
2014-06-09 14:40:24 -04:00
return Vertices . create ( points , body ) ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the centre ( centroid ) of the set of vertices .
2014-02-28 20:10:08 -05:00
* @ method centre
* @ param { vertices } vertices
* @ return { vector } The centre point
* /
2014-02-19 09:15:05 -05:00
Vertices . centre = function ( vertices ) {
2014-05-05 14:32:51 -04:00
var area = Vertices . area ( vertices , true ) ,
centre = { x : 0 , y : 0 } ,
cross ,
temp ,
j ;
2014-02-19 09:15:05 -05:00
for ( var i = 0 ; i < vertices . length ; i ++ ) {
2014-05-05 14:32:51 -04:00
j = ( i + 1 ) % vertices . length ;
cross = Vector . cross ( vertices [ i ] , vertices [ j ] ) ;
temp = Vector . mult ( Vector . add ( vertices [ i ] , vertices [ j ] ) , cross ) ;
centre = Vector . add ( centre , temp ) ;
2014-02-19 09:15:05 -05:00
}
2014-05-05 14:32:51 -04:00
return Vector . div ( centre , 6 * area ) ;
2014-02-19 09:15:05 -05:00
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Returns the average ( mean ) of the set of vertices .
* @ method mean
* @ param { vertices } vertices
* @ return { vector } The average point
* /
Vertices . mean = function ( vertices ) {
var average = { x : 0 , y : 0 } ;
for ( var i = 0 ; i < vertices . length ; i ++ ) {
average . x += vertices [ i ] . x ;
average . y += vertices [ i ] . y ;
}
return Vector . div ( average , vertices . length ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the area of the set of vertices .
2014-02-28 20:10:08 -05:00
* @ method area
* @ param { vertices } vertices
2014-05-05 14:32:51 -04:00
* @ param { bool } signed
2014-02-28 20:10:08 -05:00
* @ return { number } The area
* /
2014-05-05 14:32:51 -04:00
Vertices . area = function ( vertices , signed ) {
2014-02-19 09:15:05 -05:00
var area = 0 ,
j = vertices . length - 1 ;
for ( var i = 0 ; i < vertices . length ; i ++ ) {
area += ( vertices [ j ] . x - vertices [ i ] . x ) * ( vertices [ j ] . y + vertices [ i ] . y ) ;
j = i ;
}
2014-05-05 14:32:51 -04:00
if ( signed )
return area / 2 ;
2014-02-19 09:15:05 -05:00
return Math . abs ( area ) / 2 ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns the moment of inertia ( second moment of area ) of the set of vertices given the total mass .
2014-02-28 20:10:08 -05:00
* @ method inertia
* @ param { vertices } vertices
* @ param { number } mass
2014-06-09 14:40:24 -04:00
* @ return { number } The polygon ' s moment of inertia
2014-02-28 20:10:08 -05:00
* /
2014-02-19 09:15:05 -05:00
Vertices . inertia = function ( vertices , mass ) {
var numerator = 0 ,
denominator = 0 ,
v = vertices ,
cross ,
j ;
// find the polygon's moment of inertia, using second moment of area
// http://www.physicsforums.com/showthread.php?t=25293
for ( var n = 0 ; n < v . length ; n ++ ) {
j = ( n + 1 ) % v . length ;
cross = Math . abs ( Vector . cross ( v [ j ] , v [ n ] ) ) ;
numerator += cross * ( Vector . dot ( v [ j ] , v [ j ] ) + Vector . dot ( v [ j ] , v [ n ] ) + Vector . dot ( v [ n ] , v [ n ] ) ) ;
denominator += cross ;
}
return ( mass / 6 ) * ( numerator / denominator ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Translates the set of vertices in - place .
2014-02-28 20:10:08 -05:00
* @ method translate
* @ param { vertices } vertices
* @ param { vector } vector
* @ param { number } scalar
* /
2014-02-19 09:15:05 -05:00
Vertices . translate = function ( vertices , vector , scalar ) {
var i ;
if ( scalar ) {
for ( i = 0 ; i < vertices . length ; i ++ ) {
vertices [ i ] . x += vector . x * scalar ;
vertices [ i ] . y += vector . y * scalar ;
}
} else {
for ( i = 0 ; i < vertices . length ; i ++ ) {
vertices [ i ] . x += vector . x ;
vertices [ i ] . y += vector . y ;
}
2014-06-09 14:40:24 -04:00
}
return vertices ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Rotates the set of vertices in - place .
2014-02-28 20:10:08 -05:00
* @ method rotate
* @ param { vertices } vertices
* @ param { number } angle
* @ param { vector } point
* /
2014-02-19 09:15:05 -05:00
Vertices . rotate = function ( vertices , angle , point ) {
if ( angle === 0 )
return ;
var cos = Math . cos ( angle ) ,
sin = Math . sin ( angle ) ;
for ( var i = 0 ; i < vertices . length ; i ++ ) {
var vertice = vertices [ i ] ,
dx = vertice . x - point . x ,
dy = vertice . y - point . y ;
vertice . x = point . x + ( dx * cos - dy * sin ) ;
vertice . y = point . y + ( dx * sin + dy * cos ) ;
}
2014-06-09 14:40:24 -04:00
return vertices ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Returns ` true ` if the ` point ` is inside the set of ` vertices ` .
2014-02-28 20:10:08 -05:00
* @ method contains
* @ param { vertices } vertices
* @ param { vector } point
* @ return { boolean } True if the vertices contains point , otherwise false
* /
2014-02-19 09:15:05 -05:00
Vertices . contains = function ( vertices , point ) {
for ( var i = 0 ; i < vertices . length ; i ++ ) {
var vertice = vertices [ i ] ,
nextVertice = vertices [ ( i + 1 ) % vertices . length ] ;
if ( ( point . x - vertice . x ) * ( nextVertice . y - vertice . y ) + ( point . y - vertice . y ) * ( vertice . x - nextVertice . x ) > 0 ) {
return false ;
}
}
return true ;
} ;
2014-05-01 09:09:06 -04:00
/ * *
2014-06-09 14:40:24 -04:00
* Scales the vertices from a point ( default is centre ) in - place .
2014-05-01 09:09:06 -04:00
* @ method scale
* @ param { vertices } vertices
* @ param { number } scaleX
* @ param { number } scaleY
* @ param { vector } point
* /
Vertices . scale = function ( vertices , scaleX , scaleY , point ) {
if ( scaleX === 1 && scaleY === 1 )
return vertices ;
point = point || Vertices . centre ( vertices ) ;
var vertex ,
delta ;
for ( var i = 0 ; i < vertices . length ; i ++ ) {
vertex = vertices [ i ] ;
delta = Vector . sub ( vertex , point ) ;
vertices [ i ] . x = point . x + delta . x * scaleX ;
vertices [ i ] . y = point . y + delta . y * scaleY ;
}
return vertices ;
} ;
2014-05-05 14:32:51 -04:00
/ * *
* Chamfers a set of vertices by giving them rounded corners , returns a new set of vertices .
* The radius parameter is a single number or an array to specify the radius for each vertex .
* @ method chamfer
* @ param { vertices } vertices
* @ param { number [ ] } radius
* @ param { number } quality
* @ param { number } qualityMin
* @ param { number } qualityMax
* /
Vertices . chamfer = function ( vertices , radius , quality , qualityMin , qualityMax ) {
radius = radius || [ 8 ] ;
if ( ! radius . length )
radius = [ radius ] ;
// quality defaults to -1, which is auto
quality = ( typeof quality !== 'undefined' ) ? quality : - 1 ;
qualityMin = qualityMin || 2 ;
qualityMax = qualityMax || 14 ;
2015-01-01 18:10:10 -05:00
var newVertices = [ ] ;
2014-05-05 14:32:51 -04:00
for ( var i = 0 ; i < vertices . length ; i ++ ) {
var prevVertex = vertices [ i - 1 >= 0 ? i - 1 : vertices . length - 1 ] ,
vertex = vertices [ i ] ,
nextVertex = vertices [ ( i + 1 ) % vertices . length ] ,
currentRadius = radius [ i < radius . length ? i : radius . length - 1 ] ;
if ( currentRadius === 0 ) {
newVertices . push ( vertex ) ;
continue ;
}
var prevNormal = Vector . normalise ( {
x : vertex . y - prevVertex . y ,
y : prevVertex . x - vertex . x
} ) ;
var nextNormal = Vector . normalise ( {
x : nextVertex . y - vertex . y ,
y : vertex . x - nextVertex . x
} ) ;
var diagonalRadius = Math . sqrt ( 2 * Math . pow ( currentRadius , 2 ) ) ,
radiusVector = Vector . mult ( Common . clone ( prevNormal ) , currentRadius ) ,
midNormal = Vector . normalise ( Vector . mult ( Vector . add ( prevNormal , nextNormal ) , 0.5 ) ) ,
scaledVertex = Vector . sub ( vertex , Vector . mult ( midNormal , diagonalRadius ) ) ;
var precision = quality ;
if ( quality === - 1 ) {
// automatically decide precision
precision = Math . pow ( currentRadius , 0.32 ) * 1.75 ;
}
precision = Common . clamp ( precision , qualityMin , qualityMax ) ;
// use an even value for precision, more likely to reduce axes by using symmetry
if ( precision % 2 === 1 )
precision += 1 ;
var alpha = Math . acos ( Vector . dot ( prevNormal , nextNormal ) ) ,
theta = alpha / precision ;
for ( var j = 0 ; j < precision ; j ++ ) {
newVertices . push ( Vector . add ( Vector . rotate ( radiusVector , theta * j ) , scaledVertex ) ) ;
}
}
return newVertices ;
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Sorts the input vertices into clockwise order in place .
* @ method clockwiseSort
* @ param { vertices } vertices
* @ return { vertices } vertices
* /
Vertices . clockwiseSort = function ( vertices ) {
var centre = Vertices . mean ( vertices ) ;
vertices . sort ( function ( vertexA , vertexB ) {
return Vector . angle ( centre , vertexA ) - Vector . angle ( centre , vertexB ) ;
} ) ;
return vertices ;
} ;
/ * *
* Returns true if the vertices form a convex shape ( vertices must be in clockwise order ) .
* @ method isConvex
* @ param { vertices } vertices
* @ return { bool } ` true ` if the ` vertices ` are convex , ` false ` if not ( or ` null ` if not computable ) .
* /
Vertices . isConvex = function ( vertices ) {
// http://paulbourke.net/geometry/polygonmesh/
var flag = 0 ,
n = vertices . length ,
i ,
j ,
k ,
z ;
if ( n < 3 )
return null ;
for ( i = 0 ; i < n ; i ++ ) {
j = ( i + 1 ) % n ;
k = ( i + 2 ) % n ;
z = ( vertices [ j ] . x - vertices [ i ] . x ) * ( vertices [ k ] . y - vertices [ j ] . y ) ;
z -= ( vertices [ j ] . y - vertices [ i ] . y ) * ( vertices [ k ] . x - vertices [ j ] . x ) ;
if ( z < 0 ) {
flag |= 1 ;
} else if ( z > 0 ) {
flag |= 2 ;
}
if ( flag === 3 ) {
return false ;
}
}
if ( flag !== 0 ) {
return true ;
} else {
return null ;
}
} ;
/ * *
* Returns the convex hull of the input vertices as a new array of points .
* @ method hull
* @ param { vertices } vertices
* @ return [ vertex ] vertices
* /
Vertices . hull = function ( vertices ) {
// http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
var upper = [ ] ,
lower = [ ] ,
vertex ,
i ;
// sort vertices on x-axis (y-axis for ties)
vertices = vertices . slice ( 0 ) ;
vertices . sort ( function ( vertexA , vertexB ) {
var dx = vertexA . x - vertexB . x ;
return dx !== 0 ? dx : vertexA . y - vertexB . y ;
} ) ;
// build lower hull
for ( i = 0 ; i < vertices . length ; i ++ ) {
vertex = vertices [ i ] ;
while ( lower . length >= 2
&& Vector . cross3 ( lower [ lower . length - 2 ] , lower [ lower . length - 1 ] , vertex ) <= 0 ) {
lower . pop ( ) ;
}
lower . push ( vertex ) ;
}
// build upper hull
for ( i = vertices . length - 1 ; i >= 0 ; i -- ) {
vertex = vertices [ i ] ;
while ( upper . length >= 2
&& Vector . cross3 ( upper [ upper . length - 2 ] , upper [ upper . length - 1 ] , vertex ) <= 0 ) {
upper . pop ( ) ;
}
upper . push ( vertex ) ;
}
// concatenation of the lower and upper hulls gives the convex hull
// omit last points because they are repeated at the beginning of the other list
upper . pop ( ) ;
lower . pop ( ) ;
return upper . concat ( lower ) ;
} ;
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-08-17 18:50:03 -04:00
} , { "../core/Common" : 14 , "../geometry/Vector" : 26 } ] , 28 : [ function ( require , module , exports ) {
var Matter = module . exports = { } ;
2015-12-05 11:47:50 -05:00
Matter . version = 'master' ;
2015-08-17 18:50:03 -04:00
Matter . Body = require ( '../body/Body' ) ;
Matter . Composite = require ( '../body/Composite' ) ;
Matter . World = require ( '../body/World' ) ;
2015-01-01 18:10:10 -05:00
2015-08-17 18:50:03 -04:00
Matter . Contact = require ( '../collision/Contact' ) ;
Matter . Detector = require ( '../collision/Detector' ) ;
Matter . Grid = require ( '../collision/Grid' ) ;
Matter . Pairs = require ( '../collision/Pairs' ) ;
Matter . Pair = require ( '../collision/Pair' ) ;
Matter . Query = require ( '../collision/Query' ) ;
Matter . Resolver = require ( '../collision/Resolver' ) ;
Matter . SAT = require ( '../collision/SAT' ) ;
2014-02-19 09:15:05 -05:00
2015-08-17 18:50:03 -04:00
Matter . Constraint = require ( '../constraint/Constraint' ) ;
Matter . MouseConstraint = require ( '../constraint/MouseConstraint' ) ;
2014-02-19 09:15:05 -05:00
2015-08-17 18:50:03 -04:00
Matter . Common = require ( '../core/Common' ) ;
Matter . Engine = require ( '../core/Engine' ) ;
Matter . Events = require ( '../core/Events' ) ;
Matter . Mouse = require ( '../core/Mouse' ) ;
Matter . Runner = require ( '../core/Runner' ) ;
Matter . Sleeping = require ( '../core/Sleeping' ) ;
2014-02-19 09:15:05 -05:00
2015-12-05 11:47:50 -05:00
2015-08-17 18:50:03 -04:00
Matter . Bodies = require ( '../factory/Bodies' ) ;
Matter . Composites = require ( '../factory/Composites' ) ;
Matter . Axes = require ( '../geometry/Axes' ) ;
Matter . Bounds = require ( '../geometry/Bounds' ) ;
Matter . Svg = require ( '../geometry/Svg' ) ;
Matter . Vector = require ( '../geometry/Vector' ) ;
Matter . Vertices = require ( '../geometry/Vertices' ) ;
Matter . Render = require ( '../render/Render' ) ;
Matter . RenderPixi = require ( '../render/RenderPixi' ) ;
// aliases
Matter . World . add = Matter . Composite . add ;
Matter . World . remove = Matter . Composite . remove ;
Matter . World . addComposite = Matter . Composite . addComposite ;
Matter . World . addBody = Matter . Composite . addBody ;
Matter . World . addConstraint = Matter . Composite . addConstraint ;
Matter . World . clear = Matter . Composite . clear ;
Matter . Engine . run = Matter . Runner . run ;
2015-12-05 11:47:50 -05:00
2015-08-17 18:50:03 -04:00
} , { "../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/Metrics" : 17 , "../core/Mouse" : 18 , "../core/Runner" : 19 , "../core/Sleeping" : 20 , "../factory/Bodies" : 21 , "../factory/Composites" : 22 , "../geometry/Axes" : 23 , "../geometry/Bounds" : 24 , "../geometry/Svg" : 25 , "../geometry/Vector" : 26 , "../geometry/Vertices" : 27 , "../render/Render" : 29 , "../render/RenderPixi" : 30 } ] , 29 : [ function ( require , module , exports ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* The ` Matter.Render ` module is the default ` render.controller ` used by a ` Matter.Engine ` .
* This renderer is HTML5 canvas based and supports a number of drawing options including sprites and viewports .
*
* It is possible develop a custom renderer module based on ` Matter.Render ` and pass an instance of it to ` Engine.create ` via ` options.render ` .
* A minimal custom renderer object must define at least three functions : ` create ` , ` clear ` and ` world ` ( see ` Matter.Render ` ) .
*
* See also ` Matter.RenderPixi ` for an alternate WebGL , scene - graph based renderer .
2014-02-28 20:10:08 -05:00
*
2014-05-01 09:09:06 -04:00
* @ class Render
2014-02-28 20:10:08 -05:00
* /
2014-05-01 09:09:06 -04:00
var Render = { } ;
2014-02-19 09:15:05 -05:00
2015-08-17 18:50:03 -04:00
module . exports = Render ;
var Common = require ( '../core/Common' ) ;
var Composite = require ( '../body/Composite' ) ;
var Bounds = require ( '../geometry/Bounds' ) ;
var Events = require ( '../core/Events' ) ;
var Grid = require ( '../collision/Grid' ) ;
2015-12-05 11:47:50 -05:00
var Vector = require ( '../geometry/Vector' ) ;
2015-08-17 18:50:03 -04:00
2014-05-01 09:09:06 -04:00
( function ( ) {
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Creates a new renderer . The options parameter is an object that specifies any properties you wish to override the defaults .
* All properties have default values , and many are pre - calculated automatically based on other properties .
2015-06-29 15:58:24 -04:00
* See the properties section below for detailed information on what you can pass via the ` options ` object .
2014-02-28 20:10:08 -05:00
* @ method create
2014-06-09 14:40:24 -04:00
* @ param { object } [ options ]
2014-05-01 09:09:06 -04:00
* @ return { render } A new renderer
2014-02-28 20:10:08 -05:00
* /
2014-05-01 09:09:06 -04:00
Render . create = function ( options ) {
var defaults = {
controller : Render ,
element : null ,
canvas : null ,
2015-12-05 11:47:50 -05:00
mouse : null ,
2014-05-01 09:09:06 -04:00
options : {
width : 800 ,
height : 600 ,
2014-12-28 13:37:43 -05:00
pixelRatio : 1 ,
2014-05-01 09:09:06 -04:00
background : '#fafafa' ,
wireframeBackground : '#222' ,
2016-04-07 15:03:37 -04:00
hasBounds : ! ! options . bounds ,
2014-05-01 09:09:06 -04:00
enabled : true ,
wireframes : true ,
showSleeping : true ,
showDebug : false ,
showBroadphase : false ,
showBounds : false ,
showVelocity : false ,
showCollisions : false ,
2015-05-20 15:38:41 -04:00
showSeparations : false ,
2014-05-01 09:09:06 -04:00
showAxes : false ,
showPositions : false ,
showAngleIndicator : false ,
showIds : false ,
2015-05-20 15:38:41 -04:00
showShadows : false ,
showVertexNumbers : false ,
showConvexHulls : false ,
2015-12-05 11:47:50 -05:00
showInternalEdges : false ,
showMousePosition : false
2014-05-01 09:09:06 -04:00
}
2014-02-19 09:15:05 -05:00
} ;
2014-05-01 09:09:06 -04:00
var render = Common . extend ( defaults , options ) ;
2014-02-19 09:15:05 -05:00
2015-12-23 08:08:54 -05:00
if ( render . canvas ) {
render . canvas . width = render . options . width || render . canvas . width ;
render . canvas . height = render . options . height || render . canvas . height ;
}
2014-05-01 09:09:06 -04:00
render . canvas = render . canvas || _createCanvas ( render . options . width , render . options . height ) ;
render . context = render . canvas . getContext ( '2d' ) ;
render . textures = { } ;
2014-02-19 09:15:05 -05:00
2014-05-01 09:09:06 -04:00
render . bounds = render . bounds || {
min : {
x : 0 ,
y : 0
} ,
max : {
2015-12-23 08:08:54 -05:00
x : render . canvas . width ,
y : render . canvas . height
2014-05-01 09:09:06 -04:00
}
} ;
2014-03-30 14:45:30 -04:00
2014-12-28 13:37:43 -05:00
if ( render . options . pixelRatio !== 1 ) {
Render . setPixelRatio ( render , render . options . pixelRatio ) ;
}
2014-03-22 13:51:49 -04:00
if ( Common . isElement ( render . element ) ) {
render . element . appendChild ( render . canvas ) ;
} else {
2015-01-20 19:15:04 -05:00
Common . log ( 'Render.create: options.element was undefined, render.canvas was created but not appended' , 'warn' ) ;
2014-03-22 13:51:49 -04:00
}
2014-02-19 09:15:05 -05:00
return render ;
} ;
2014-12-28 13:37:43 -05:00
/ * *
* Sets the pixel ratio of the renderer and updates the canvas .
* To automatically detect the correct ratio , pass the string ` 'auto' ` for ` pixelRatio ` .
* @ method setPixelRatio
* @ param { render } render
* @ param { number } pixelRatio
* /
Render . setPixelRatio = function ( render , pixelRatio ) {
var options = render . options ,
canvas = render . canvas ;
if ( pixelRatio === 'auto' ) {
pixelRatio = _getPixelRatio ( canvas ) ;
}
options . pixelRatio = pixelRatio ;
canvas . setAttribute ( 'data-pixel-ratio' , pixelRatio ) ;
canvas . width = options . width * pixelRatio ;
canvas . height = options . height * pixelRatio ;
canvas . style . width = options . width + 'px' ;
canvas . style . height = options . height + 'px' ;
render . context . scale ( pixelRatio , pixelRatio ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
2014-06-09 14:40:24 -04:00
* Renders the given ` engine ` ' s ` Matter.World ` object .
* This is the entry point for all rendering and should be called every time the scene changes .
2014-02-28 20:10:08 -05:00
* @ method world
* @ param { engine } engine
* /
2014-02-19 09:15:05 -05:00
Render . world = function ( engine ) {
var render = engine . render ,
world = engine . world ,
canvas = render . canvas ,
context = render . context ,
options = render . options ,
2014-05-01 09:09:06 -04:00
allBodies = Composite . allBodies ( world ) ,
allConstraints = Composite . allConstraints ( world ) ,
2015-01-20 19:15:04 -05:00
background = options . wireframes ? options . wireframeBackground : options . background ,
2014-05-01 09:09:06 -04:00
bodies = [ ] ,
constraints = [ ] ,
2014-02-19 09:15:05 -05:00
i ;
2015-08-12 19:38:20 -04:00
var event = {
timestamp : engine . timing . timestamp
} ;
Events . trigger ( render , 'beforeRender' , event ) ;
2015-01-20 19:15:04 -05:00
// apply background if it has changed
if ( render . currentBackground !== background )
_applyBackground ( render , background ) ;
2014-03-22 13:51:49 -04:00
// clear the canvas with a transparent fill, to allow the canvas background to show
context . globalCompositeOperation = 'source-in' ;
context . fillStyle = "transparent" ;
2014-02-19 09:15:05 -05:00
context . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
2014-03-22 13:51:49 -04:00
context . globalCompositeOperation = 'source-over' ;
2014-02-19 09:15:05 -05:00
2014-05-01 09:09:06 -04:00
// handle bounds
if ( options . hasBounds ) {
2014-12-28 13:37:43 -05:00
var boundsWidth = render . bounds . max . x - render . bounds . min . x ,
boundsHeight = render . bounds . max . y - render . bounds . min . y ,
boundsScaleX = boundsWidth / options . width ,
boundsScaleY = boundsHeight / options . height ;
2014-05-01 09:09:06 -04:00
// filter out bodies that are not in view
for ( i = 0 ; i < allBodies . length ; i ++ ) {
var body = allBodies [ i ] ;
if ( Bounds . overlaps ( body . bounds , render . bounds ) )
bodies . push ( body ) ;
}
// filter out constraints that are not in view
for ( i = 0 ; i < allConstraints . length ; i ++ ) {
var constraint = allConstraints [ i ] ,
bodyA = constraint . bodyA ,
bodyB = constraint . bodyB ,
pointAWorld = constraint . pointA ,
pointBWorld = constraint . pointB ;
if ( bodyA ) pointAWorld = Vector . add ( bodyA . position , constraint . pointA ) ;
if ( bodyB ) pointBWorld = Vector . add ( bodyB . position , constraint . pointB ) ;
if ( ! pointAWorld || ! pointBWorld )
continue ;
if ( Bounds . contains ( render . bounds , pointAWorld ) || Bounds . contains ( render . bounds , pointBWorld ) )
constraints . push ( constraint ) ;
}
2014-05-05 14:32:51 -04:00
// transform the view
context . scale ( 1 / boundsScaleX , 1 / boundsScaleY ) ;
2014-05-01 09:09:06 -04:00
context . translate ( - render . bounds . min . x , - render . bounds . min . y ) ;
} else {
constraints = allConstraints ;
bodies = allBodies ;
}
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( ! options . wireframes || ( engine . enableSleeping && options . showSleeping ) ) {
// fully featured rendering of bodies
2014-03-24 16:11:42 -04:00
Render . bodies ( engine , bodies , context ) ;
2014-03-22 13:51:49 -04:00
} else {
2015-05-20 15:38:41 -04:00
if ( options . showConvexHulls )
Render . bodyConvexHulls ( engine , bodies , context ) ;
2014-03-22 13:51:49 -04:00
// optimised method for wireframes only
2014-03-24 16:11:42 -04:00
Render . bodyWireframes ( engine , bodies , context ) ;
2014-03-22 13:51:49 -04:00
}
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( options . showBounds )
2014-03-24 16:11:42 -04:00
Render . bodyBounds ( engine , bodies , context ) ;
2014-03-22 13:51:49 -04:00
if ( options . showAxes || options . showAngleIndicator )
2014-03-24 16:11:42 -04:00
Render . bodyAxes ( engine , bodies , context ) ;
2014-03-22 13:51:49 -04:00
if ( options . showPositions )
2014-03-24 16:11:42 -04:00
Render . bodyPositions ( engine , bodies , context ) ;
2014-03-22 13:51:49 -04:00
if ( options . showVelocity )
2014-03-24 16:11:42 -04:00
Render . bodyVelocity ( engine , bodies , context ) ;
2014-03-22 13:51:49 -04:00
if ( options . showIds )
2014-03-24 16:11:42 -04:00
Render . bodyIds ( engine , bodies , context ) ;
2014-02-19 09:15:05 -05:00
2015-05-20 15:38:41 -04:00
if ( options . showSeparations )
Render . separations ( engine , engine . pairs . list , context ) ;
2014-02-19 09:15:05 -05:00
if ( options . showCollisions )
2014-03-22 13:51:49 -04:00
Render . collisions ( engine , engine . pairs . list , context ) ;
2015-05-20 15:38:41 -04:00
if ( options . showVertexNumbers )
Render . vertexNumbers ( engine , bodies , context ) ;
2015-12-05 11:47:50 -05:00
if ( options . showMousePosition )
Render . mousePosition ( engine , render . mouse , context ) ;
2014-03-24 16:11:42 -04:00
Render . constraints ( constraints , context ) ;
2014-02-19 09:15:05 -05:00
2014-07-29 11:26:49 -04:00
if ( options . showBroadphase && engine . broadphase . controller === Grid )
Render . grid ( engine , engine . broadphase , context ) ;
2014-02-19 09:15:05 -05:00
if ( options . showDebug )
Render . debug ( engine , context ) ;
2014-05-01 09:09:06 -04:00
2014-05-05 14:32:51 -04:00
if ( options . hasBounds ) {
// revert view transforms
2014-12-28 13:37:43 -05:00
context . setTransform ( options . pixelRatio , 0 , 0 , options . pixelRatio , 0 , 0 ) ;
2014-05-05 14:32:51 -04:00
}
2015-08-12 19:38:20 -04:00
Events . trigger ( render , 'afterRender' , event ) ;
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
* Description
2014-06-09 14:40:24 -04:00
* @ private
2014-02-28 20:10:08 -05:00
* @ method debug
* @ param { engine } engine
* @ param { RenderingContext } context
* /
2014-02-19 09:15:05 -05:00
Render . debug = function ( engine , context ) {
var c = context ,
world = engine . world ,
render = engine . render ,
2015-09-17 13:47:56 -04:00
metrics = engine . metrics ,
2014-02-19 09:15:05 -05:00
options = render . options ,
2014-03-24 16:11:42 -04:00
bodies = Composite . allBodies ( world ) ,
2014-02-19 09:15:05 -05:00
space = " " ;
if ( engine . timing . timestamp - ( render . debugTimestamp || 0 ) >= 500 ) {
var text = "" ;
2015-12-05 11:47:50 -05:00
if ( metrics . timing ) {
text += "fps: " + Math . round ( metrics . timing . fps ) + space ;
}
2014-02-19 09:15:05 -05:00
render . debugString = text ;
render . debugTimestamp = engine . timing . timestamp ;
}
if ( render . debugString ) {
c . font = "12px Arial" ;
if ( options . wireframes ) {
c . fillStyle = 'rgba(255,255,255,0.5)' ;
} else {
c . fillStyle = 'rgba(0,0,0,0.5)' ;
}
var split = render . debugString . split ( '\n' ) ;
for ( var i = 0 ; i < split . length ; i ++ ) {
c . fillText ( split [ i ] , 50 , 50 + i * 18 ) ;
}
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
* Description
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method constraints
* @ param { constraint [ ] } constraints
2014-02-28 20:10:08 -05:00
* @ param { RenderingContext } context
* /
2014-03-22 13:51:49 -04:00
Render . constraints = function ( constraints , context ) {
var c = context ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
for ( var i = 0 ; i < constraints . length ; i ++ ) {
var constraint = constraints [ i ] ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( ! constraint . render . visible || ! constraint . pointA || ! constraint . pointB )
continue ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
var bodyA = constraint . bodyA ,
bodyB = constraint . bodyB ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
if ( bodyA ) {
c . beginPath ( ) ;
c . moveTo ( bodyA . position . x + constraint . pointA . x , bodyA . position . y + constraint . pointA . y ) ;
} else {
c . beginPath ( ) ;
c . moveTo ( constraint . pointA . x , constraint . pointA . y ) ;
}
if ( bodyB ) {
c . lineTo ( bodyB . position . x + constraint . pointB . x , bodyB . position . y + constraint . pointB . y ) ;
} else {
c . lineTo ( constraint . pointB . x , constraint . pointB . y ) ;
}
c . lineWidth = constraint . render . lineWidth ;
c . strokeStyle = constraint . render . strokeStyle ;
c . stroke ( ) ;
}
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
* Description
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodyShadows
2014-02-28 20:10:08 -05:00
* @ param { engine } engine
2014-03-22 13:51:49 -04:00
* @ param { body [ ] } bodies
2014-02-28 20:10:08 -05:00
* @ param { RenderingContext } context
* /
2014-03-22 13:51:49 -04:00
Render . bodyShadows = function ( engine , bodies , context ) {
2014-02-19 09:15:05 -05:00
var c = context ,
2015-01-01 18:10:10 -05:00
render = engine . render ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
if ( ! body . render . visible )
continue ;
if ( body . circleRadius ) {
c . beginPath ( ) ;
c . arc ( body . position . x , body . position . y , body . circleRadius , 0 , 2 * Math . PI ) ;
c . closePath ( ) ;
} else {
c . beginPath ( ) ;
c . moveTo ( body . vertices [ 0 ] . x , body . vertices [ 0 ] . y ) ;
for ( var j = 1 ; j < body . vertices . length ; j ++ ) {
c . lineTo ( body . vertices [ j ] . x , body . vertices [ j ] . y ) ;
}
c . closePath ( ) ;
}
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
var distanceX = body . position . x - render . options . width * 0.5 ,
distanceY = body . position . y - render . options . height * 0.2 ,
distance = Math . abs ( distanceX ) + Math . abs ( distanceY ) ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
c . shadowColor = 'rgba(0,0,0,0.15)' ;
c . shadowOffsetX = 0.05 * distanceX ;
c . shadowOffsetY = 0.05 * distanceY ;
c . shadowBlur = 1 + 12 * Math . min ( 1 , distance / 1000 ) ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
c . fill ( ) ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
c . shadowColor = null ;
c . shadowOffsetX = null ;
c . shadowOffsetY = null ;
c . shadowBlur = null ;
}
2014-02-19 09:15:05 -05:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
* Description
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodies
2014-02-28 20:10:08 -05:00
* @ param { engine } engine
2014-03-22 13:51:49 -04:00
* @ param { body [ ] } bodies
2014-02-28 20:10:08 -05:00
* @ param { RenderingContext } context
* /
2014-03-22 13:51:49 -04:00
Render . bodies = function ( engine , bodies , context ) {
2014-02-19 09:15:05 -05:00
var c = context ,
render = engine . render ,
2014-03-22 13:51:49 -04:00
options = render . options ,
2016-02-07 10:53:07 -05:00
showInternalEdges = options . showInternalEdges || ! options . wireframes ,
2015-05-20 15:38:41 -04:00
body ,
part ,
2015-07-02 15:17:03 -04:00
i ,
k ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
for ( i = 0 ; i < bodies . length ; i ++ ) {
2015-05-20 15:38:41 -04:00
body = bodies [ i ] ;
2014-03-22 13:51:49 -04:00
if ( ! body . render . visible )
continue ;
2015-05-20 15:38:41 -04:00
// handle compound parts
for ( k = body . parts . length > 1 ? 1 : 0 ; k < body . parts . length ; k ++ ) {
part = body . parts [ k ] ;
2014-03-22 13:51:49 -04:00
2015-12-23 08:08:54 -05:00
if ( ! part . render . visible )
continue ;
2016-02-07 10:53:07 -05:00
if ( options . showSleeping && body . isSleeping ) {
c . globalAlpha = 0.5 * part . render . opacity ;
} else if ( part . render . opacity !== 1 ) {
c . globalAlpha = part . render . opacity ;
}
2015-05-20 15:38:41 -04:00
if ( part . render . sprite && part . render . sprite . texture && ! options . wireframes ) {
// part sprite
var sprite = part . render . sprite ,
texture = _getTexture ( render , sprite . texture ) ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
c . translate ( part . position . x , part . position . y ) ;
c . rotate ( part . angle ) ;
2014-03-22 13:51:49 -04:00
2015-12-23 08:08:54 -05:00
c . drawImage (
texture ,
texture . width * - sprite . xOffset * sprite . xScale ,
texture . height * - sprite . yOffset * sprite . yScale ,
texture . width * sprite . xScale ,
texture . height * sprite . yScale
) ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
// revert translation, hopefully faster than save / restore
c . rotate ( - part . angle ) ;
c . translate ( - part . position . x , - part . position . y ) ;
2014-03-22 13:51:49 -04:00
} else {
2015-05-20 15:38:41 -04:00
// part polygon
if ( part . circleRadius ) {
c . beginPath ( ) ;
c . arc ( part . position . x , part . position . y , part . circleRadius , 0 , 2 * Math . PI ) ;
} else {
c . beginPath ( ) ;
c . moveTo ( part . vertices [ 0 ] . x , part . vertices [ 0 ] . y ) ;
2016-02-07 10:53:07 -05:00
2015-05-20 15:38:41 -04:00
for ( var j = 1 ; j < part . vertices . length ; j ++ ) {
2016-02-07 10:53:07 -05:00
if ( ! part . vertices [ j - 1 ] . isInternal || showInternalEdges ) {
c . lineTo ( part . vertices [ j ] . x , part . vertices [ j ] . y ) ;
} else {
c . moveTo ( part . vertices [ j ] . x , part . vertices [ j ] . y ) ;
}
if ( part . vertices [ j ] . isInternal && ! showInternalEdges ) {
c . moveTo ( part . vertices [ ( j + 1 ) % part . vertices . length ] . x , part . vertices [ ( j + 1 ) % part . vertices . length ] . y ) ;
}
2015-05-20 15:38:41 -04:00
}
2016-02-07 10:53:07 -05:00
c . lineTo ( part . vertices [ 0 ] . x , part . vertices [ 0 ] . y ) ;
2015-05-20 15:38:41 -04:00
c . closePath ( ) ;
2014-03-22 13:51:49 -04:00
}
2015-05-20 15:38:41 -04:00
if ( ! options . wireframes ) {
2016-02-07 10:53:07 -05:00
c . fillStyle = part . render . fillStyle ;
2015-05-20 15:38:41 -04:00
c . lineWidth = part . render . lineWidth ;
c . strokeStyle = part . render . strokeStyle ;
c . fill ( ) ;
2014-03-22 13:51:49 -04:00
} else {
2015-05-20 15:38:41 -04:00
c . lineWidth = 1 ;
c . strokeStyle = '#bbb' ;
2014-03-22 13:51:49 -04:00
}
2016-02-07 10:53:07 -05:00
c . stroke ( ) ;
2014-03-22 13:51:49 -04:00
}
2016-02-07 10:53:07 -05:00
c . globalAlpha = 1 ;
2014-02-19 09:15:05 -05:00
}
}
2014-03-22 13:51:49 -04:00
} ;
/ * *
* Optimised method for drawing body wireframes in one pass
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodyWireframes
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . bodyWireframes = function ( engine , bodies , context ) {
var c = context ,
2015-05-20 15:38:41 -04:00
showInternalEdges = engine . render . options . showInternalEdges ,
body ,
part ,
2014-03-22 13:51:49 -04:00
i ,
2015-05-20 15:38:41 -04:00
j ,
k ;
2014-03-22 13:51:49 -04:00
c . beginPath ( ) ;
2015-05-20 15:38:41 -04:00
// render all bodies
2014-03-22 13:51:49 -04:00
for ( i = 0 ; i < bodies . length ; i ++ ) {
2015-05-20 15:38:41 -04:00
body = bodies [ i ] ;
2014-03-22 13:51:49 -04:00
if ( ! body . render . visible )
continue ;
2015-05-20 15:38:41 -04:00
// handle compound parts
for ( k = body . parts . length > 1 ? 1 : 0 ; k < body . parts . length ; k ++ ) {
part = body . parts [ k ] ;
c . moveTo ( part . vertices [ 0 ] . x , part . vertices [ 0 ] . y ) ;
for ( j = 1 ; j < part . vertices . length ; j ++ ) {
if ( ! part . vertices [ j - 1 ] . isInternal || showInternalEdges ) {
c . lineTo ( part . vertices [ j ] . x , part . vertices [ j ] . y ) ;
} else {
c . moveTo ( part . vertices [ j ] . x , part . vertices [ j ] . y ) ;
}
if ( part . vertices [ j ] . isInternal && ! showInternalEdges ) {
c . moveTo ( part . vertices [ ( j + 1 ) % part . vertices . length ] . x , part . vertices [ ( j + 1 ) % part . vertices . length ] . y ) ;
}
}
c . lineTo ( part . vertices [ 0 ] . x , part . vertices [ 0 ] . y ) ;
}
}
c . lineWidth = 1 ;
c . strokeStyle = '#bbb' ;
c . stroke ( ) ;
} ;
/ * *
* Optimised method for drawing body convex hull wireframes in one pass
* @ private
* @ method bodyConvexHulls
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . bodyConvexHulls = function ( engine , bodies , context ) {
var c = context ,
body ,
part ,
i ,
j ,
k ;
c . beginPath ( ) ;
// render convex hulls
for ( i = 0 ; i < bodies . length ; i ++ ) {
body = bodies [ i ] ;
if ( ! body . render . visible || body . parts . length === 1 )
continue ;
2014-02-19 09:15:05 -05:00
c . moveTo ( body . vertices [ 0 ] . x , body . vertices [ 0 ] . y ) ;
2014-03-22 13:51:49 -04:00
for ( j = 1 ; j < body . vertices . length ; j ++ ) {
2014-02-19 09:15:05 -05:00
c . lineTo ( body . vertices [ j ] . x , body . vertices [ j ] . y ) ;
}
2014-03-22 13:51:49 -04:00
c . lineTo ( body . vertices [ 0 ] . x , body . vertices [ 0 ] . y ) ;
2014-02-19 09:15:05 -05:00
}
2014-03-22 13:51:49 -04:00
c . lineWidth = 1 ;
2015-05-20 15:38:41 -04:00
c . strokeStyle = 'rgba(255,255,255,0.2)' ;
2014-03-22 13:51:49 -04:00
c . stroke ( ) ;
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Renders body vertex numbers .
* @ private
* @ method vertexNumbers
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . vertexNumbers = function ( engine , bodies , context ) {
var c = context ,
i ,
j ,
k ;
for ( i = 0 ; i < bodies . length ; i ++ ) {
var parts = bodies [ i ] . parts ;
for ( k = parts . length > 1 ? 1 : 0 ; k < parts . length ; k ++ ) {
var part = parts [ k ] ;
for ( j = 0 ; j < part . vertices . length ; j ++ ) {
c . fillStyle = 'rgba(255,255,255,0.2)' ;
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 ) ;
}
}
}
} ;
2015-12-05 11:47:50 -05:00
/ * *
* Renders mouse position .
* @ private
* @ method mousePosition
* @ param { engine } engine
* @ param { mouse } mouse
* @ param { RenderingContext } context
* /
Render . mousePosition = function ( engine , mouse , context ) {
var c = context ;
c . fillStyle = 'rgba(255,255,255,0.8)' ;
c . fillText ( mouse . position . x + ' ' + mouse . position . y , mouse . position . x + 5 , mouse . position . y - 5 ) ;
} ;
2014-03-22 13:51:49 -04:00
/ * *
* Draws body bounds
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodyBounds
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . bodyBounds = function ( engine , bodies , context ) {
var c = context ,
render = engine . render ,
options = render . options ;
c . beginPath ( ) ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
2015-05-20 15:38:41 -04:00
if ( body . render . visible ) {
var parts = bodies [ i ] . parts ;
for ( var j = parts . length > 1 ? 1 : 0 ; j < parts . length ; j ++ ) {
var part = parts [ j ] ;
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 ) ;
}
}
2014-03-22 13:51:49 -04:00
}
if ( options . wireframes ) {
c . strokeStyle = 'rgba(255,255,255,0.08)' ;
2014-02-19 09:15:05 -05:00
} else {
2014-03-22 13:51:49 -04:00
c . strokeStyle = 'rgba(0,0,0,0.1)' ;
2014-02-19 09:15:05 -05:00
}
2014-03-22 13:51:49 -04:00
c . lineWidth = 1 ;
c . stroke ( ) ;
} ;
/ * *
* Draws body angle indicators and axes
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodyAxes
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . bodyAxes = function ( engine , bodies , context ) {
var c = context ,
render = engine . render ,
options = render . options ,
2015-05-20 15:38:41 -04:00
part ,
2014-03-22 13:51:49 -04:00
i ,
2015-05-20 15:38:41 -04:00
j ,
k ;
2014-03-22 13:51:49 -04:00
c . beginPath ( ) ;
for ( i = 0 ; i < bodies . length ; i ++ ) {
2015-05-20 15:38:41 -04:00
var body = bodies [ i ] ,
parts = body . parts ;
2014-03-22 13:51:49 -04:00
if ( ! body . render . visible )
continue ;
if ( options . showAxes ) {
// render all axes
2015-05-20 15:38:41 -04:00
for ( j = parts . length > 1 ? 1 : 0 ; j < parts . length ; j ++ ) {
part = parts [ j ] ;
for ( k = 0 ; k < part . axes . length ; k ++ ) {
var axis = part . axes [ k ] ;
c . moveTo ( part . position . x , part . position . y ) ;
c . lineTo ( part . position . x + axis . x * 20 , part . position . y + axis . y * 20 ) ;
}
2014-03-22 13:51:49 -04:00
}
2014-02-19 09:15:05 -05:00
} else {
2015-05-20 15:38:41 -04:00
for ( j = parts . length > 1 ? 1 : 0 ; j < parts . length ; j ++ ) {
part = parts [ j ] ;
for ( k = 0 ; k < part . axes . length ; k ++ ) {
// render a single axis indicator
c . moveTo ( part . position . x , part . position . y ) ;
c . lineTo ( ( part . vertices [ 0 ] . x + part . vertices [ part . vertices . length - 1 ] . x ) / 2 ,
( part . vertices [ 0 ] . y + part . vertices [ part . vertices . length - 1 ] . y ) / 2 ) ;
}
}
2014-02-19 09:15:05 -05:00
}
}
2014-03-22 13:51:49 -04:00
if ( options . wireframes ) {
c . strokeStyle = 'indianred' ;
} else {
2016-02-07 10:53:07 -05:00
c . strokeStyle = 'rgba(0,0,0,0.8)' ;
c . globalCompositeOperation = 'overlay' ;
2014-03-22 13:51:49 -04:00
}
c . lineWidth = 1 ;
c . stroke ( ) ;
2016-02-07 10:53:07 -05:00
c . globalCompositeOperation = 'source-over' ;
2014-03-22 13:51:49 -04:00
} ;
/ * *
* Draws body positions
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodyPositions
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . bodyPositions = function ( engine , bodies , context ) {
var c = context ,
render = engine . render ,
options = render . options ,
body ,
2015-05-20 15:38:41 -04:00
part ,
2015-07-02 15:17:03 -04:00
i ,
k ;
2014-03-22 13:51:49 -04:00
c . beginPath ( ) ;
// render current positions
for ( i = 0 ; i < bodies . length ; i ++ ) {
body = bodies [ i ] ;
2015-05-20 15:38:41 -04:00
if ( ! body . render . visible )
continue ;
// handle compound parts
for ( k = 0 ; k < body . parts . length ; k ++ ) {
part = body . parts [ k ] ;
c . arc ( part . position . x , part . position . y , 3 , 0 , 2 * Math . PI , false ) ;
2014-03-22 13:51:49 -04:00
c . closePath ( ) ;
2014-02-19 09:15:05 -05:00
}
}
2014-03-22 13:51:49 -04:00
if ( options . wireframes ) {
c . fillStyle = 'indianred' ;
} else {
c . fillStyle = 'rgba(0,0,0,0.5)' ;
}
c . fill ( ) ;
c . beginPath ( ) ;
// render previous positions
for ( i = 0 ; i < bodies . length ; i ++ ) {
body = bodies [ i ] ;
if ( body . render . visible ) {
c . arc ( body . positionPrev . x , body . positionPrev . y , 2 , 0 , 2 * Math . PI , false ) ;
c . closePath ( ) ;
2014-02-19 09:15:05 -05:00
}
}
2014-03-22 13:51:49 -04:00
c . fillStyle = 'rgba(255,165,0,0.8)' ;
c . fill ( ) ;
} ;
/ * *
* Draws body velocity
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodyVelocity
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . bodyVelocity = function ( engine , bodies , context ) {
2015-01-01 18:10:10 -05:00
var c = context ;
2014-03-22 13:51:49 -04:00
c . beginPath ( ) ;
for ( var i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
if ( ! body . render . visible )
continue ;
2014-02-19 09:15:05 -05:00
c . moveTo ( body . position . x , body . position . y ) ;
c . lineTo ( body . position . x + ( body . position . x - body . positionPrev . x ) * 2 , body . position . y + ( body . position . y - body . positionPrev . y ) * 2 ) ;
}
2014-03-22 13:51:49 -04:00
c . lineWidth = 3 ;
c . strokeStyle = 'cornflowerblue' ;
c . stroke ( ) ;
} ;
/ * *
* Draws body ids
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method bodyIds
* @ param { engine } engine
* @ param { body [ ] } bodies
* @ param { RenderingContext } context
* /
Render . bodyIds = function ( engine , bodies , context ) {
2015-05-20 15:38:41 -04:00
var c = context ,
i ,
j ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
for ( i = 0 ; i < bodies . length ; i ++ ) {
if ( ! bodies [ i ] . render . visible )
2014-03-22 13:51:49 -04:00
continue ;
2015-05-20 15:38:41 -04:00
var parts = bodies [ i ] . parts ;
for ( j = parts . length > 1 ? 1 : 0 ; j < parts . length ; j ++ ) {
var part = parts [ j ] ;
c . font = "12px Arial" ;
c . fillStyle = 'rgba(255,255,255,0.5)' ;
c . fillText ( part . id , part . position . x + 10 , part . position . y - 10 ) ;
}
2014-02-19 09:15:05 -05:00
}
} ;
2014-02-28 20:10:08 -05:00
/ * *
* Description
2014-06-09 14:40:24 -04:00
* @ private
2014-03-22 13:51:49 -04:00
* @ method collisions
2014-02-28 20:10:08 -05:00
* @ param { engine } engine
2014-03-22 13:51:49 -04:00
* @ param { pair [ ] } pairs
2014-02-28 20:10:08 -05:00
* @ param { RenderingContext } context
* /
2014-03-22 13:51:49 -04:00
Render . collisions = function ( engine , pairs , context ) {
2014-02-19 09:15:05 -05:00
var c = context ,
2014-03-22 13:51:49 -04:00
options = engine . render . options ,
pair ,
collision ,
2015-05-20 15:38:41 -04:00
corrected ,
bodyA ,
bodyB ,
2014-03-22 13:51:49 -04:00
i ,
j ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
c . beginPath ( ) ;
// render collision positions
for ( i = 0 ; i < pairs . length ; i ++ ) {
pair = pairs [ i ] ;
2015-05-20 15:38:41 -04:00
if ( ! pair . isActive )
continue ;
2014-03-22 13:51:49 -04:00
collision = pair . collision ;
for ( j = 0 ; j < pair . activeContacts . length ; j ++ ) {
var contact = pair . activeContacts [ j ] ,
vertex = contact . vertex ;
c . rect ( vertex . x - 1.5 , vertex . y - 1.5 , 3.5 , 3.5 ) ;
2014-02-19 09:15:05 -05:00
}
}
2014-03-22 13:51:49 -04:00
if ( options . wireframes ) {
c . fillStyle = 'rgba(255,255,255,0.7)' ;
} else {
c . fillStyle = 'orange' ;
}
c . fill ( ) ;
c . beginPath ( ) ;
2014-02-19 09:15:05 -05:00
2014-03-22 13:51:49 -04:00
// render collision normals
for ( i = 0 ; i < pairs . length ; i ++ ) {
pair = pairs [ i ] ;
2015-05-20 15:38:41 -04:00
if ( ! pair . isActive )
continue ;
2014-03-22 13:51:49 -04:00
collision = pair . collision ;
if ( pair . activeContacts . length > 0 ) {
var normalPosX = pair . activeContacts [ 0 ] . vertex . x ,
normalPosY = pair . activeContacts [ 0 ] . vertex . y ;
if ( pair . activeContacts . length === 2 ) {
normalPosX = ( pair . activeContacts [ 0 ] . vertex . x + pair . activeContacts [ 1 ] . vertex . x ) / 2 ;
normalPosY = ( pair . activeContacts [ 0 ] . vertex . y + pair . activeContacts [ 1 ] . vertex . y ) / 2 ;
}
2015-05-20 15:38:41 -04:00
if ( collision . bodyB === collision . supports [ 0 ] . body || collision . bodyA . isStatic === true ) {
c . moveTo ( normalPosX - collision . normal . x * 8 , normalPosY - collision . normal . y * 8 ) ;
} else {
c . moveTo ( normalPosX + collision . normal . x * 8 , normalPosY + collision . normal . y * 8 ) ;
}
2014-03-22 13:51:49 -04:00
c . lineTo ( normalPosX , normalPosY ) ;
2014-02-19 09:15:05 -05:00
}
}
2014-03-22 13:51:49 -04:00
if ( options . wireframes ) {
c . strokeStyle = 'rgba(255,165,0,0.7)' ;
} else {
c . strokeStyle = 'orange' ;
}
c . lineWidth = 1 ;
c . stroke ( ) ;
2014-02-19 09:15:05 -05:00
} ;
2015-05-20 15:38:41 -04:00
/ * *
* Description
* @ private
* @ method separations
* @ param { engine } engine
* @ param { pair [ ] } pairs
* @ param { RenderingContext } context
* /
Render . separations = function ( engine , pairs , context ) {
var c = context ,
options = engine . render . options ,
pair ,
collision ,
corrected ,
bodyA ,
bodyB ,
i ,
j ;
c . beginPath ( ) ;
// render separations
for ( i = 0 ; i < pairs . length ; i ++ ) {
pair = pairs [ i ] ;
if ( ! pair . isActive )
continue ;
collision = pair . collision ;
bodyA = collision . bodyA ;
bodyB = collision . bodyB ;
var k = 1 ;
if ( ! bodyB . isStatic && ! bodyA . isStatic ) k = 0.5 ;
if ( bodyB . isStatic ) k = 0 ;
c . moveTo ( bodyB . position . x , bodyB . position . y ) ;
c . lineTo ( bodyB . position . x - collision . penetration . x * k , bodyB . position . y - collision . penetration . y * k ) ;
k = 1 ;
if ( ! bodyB . isStatic && ! bodyA . isStatic ) k = 0.5 ;
if ( bodyA . isStatic ) k = 0 ;
c . moveTo ( bodyA . position . x , bodyA . position . y ) ;
c . lineTo ( bodyA . position . x + collision . penetration . x * k , bodyA . position . y + collision . penetration . y * k ) ;
}
if ( options . wireframes ) {
c . strokeStyle = 'rgba(255,165,0,0.5)' ;
} else {
c . strokeStyle = 'orange' ;
}
c . stroke ( ) ;
} ;
2014-02-28 20:10:08 -05:00
/ * *
* Description
2014-06-09 14:40:24 -04:00
* @ private
2014-02-28 20:10:08 -05:00
* @ method grid
* @ param { engine } engine
* @ param { grid } grid
* @ param { RenderingContext } context
* /
2014-02-19 09:15:05 -05:00
Render . grid = function ( engine , grid , context ) {
var c = context ,
options = engine . render . options ;
if ( options . wireframes ) {
c . strokeStyle = 'rgba(255,180,0,0.1)' ;
} else {
c . strokeStyle = 'rgba(255,180,0,0.5)' ;
}
2014-03-22 13:51:49 -04:00
c . beginPath ( ) ;
2014-02-19 09:15:05 -05:00
var bucketKeys = Common . keys ( grid . buckets ) ;
for ( var i = 0 ; i < bucketKeys . length ; i ++ ) {
var bucketId = bucketKeys [ i ] ;
if ( grid . buckets [ bucketId ] . length < 2 )
continue ;
var region = bucketId . split ( ',' ) ;
c . rect ( 0.5 + parseInt ( region [ 0 ] , 10 ) * grid . bucketWidth ,
0.5 + parseInt ( region [ 1 ] , 10 ) * grid . bucketHeight ,
grid . bucketWidth ,
grid . bucketHeight ) ;
}
2014-03-22 13:51:49 -04:00
c . lineWidth = 1 ;
c . stroke ( ) ;
2014-02-19 09:15:05 -05:00
} ;
2014-05-01 09:09:06 -04:00
/ * *
* Description
2014-06-09 14:40:24 -04:00
* @ private
2014-05-01 09:09:06 -04:00
* @ method inspector
* @ param { inspector } inspector
* @ param { RenderingContext } context
* /
Render . inspector = function ( inspector , context ) {
var engine = inspector . engine ,
selected = inspector . selected ,
render = engine . render ,
options = render . options ,
bounds ;
2014-05-05 14:32:51 -04:00
if ( options . hasBounds ) {
var boundsWidth = render . bounds . max . x - render . bounds . min . x ,
boundsHeight = render . bounds . max . y - render . bounds . min . y ,
boundsScaleX = boundsWidth / render . options . width ,
boundsScaleY = boundsHeight / render . options . height ;
context . scale ( 1 / boundsScaleX , 1 / boundsScaleY ) ;
2014-05-01 09:09:06 -04:00
context . translate ( - render . bounds . min . x , - render . bounds . min . y ) ;
2014-05-05 14:32:51 -04:00
}
2014-05-01 09:09:06 -04:00
for ( var i = 0 ; i < selected . length ; i ++ ) {
var item = selected [ i ] . data ;
context . translate ( 0.5 , 0.5 ) ;
context . lineWidth = 1 ;
context . strokeStyle = 'rgba(255,165,0,0.9)' ;
context . setLineDash ( [ 1 , 2 ] ) ;
switch ( item . type ) {
case 'body' :
// render body selections
bounds = item . bounds ;
context . beginPath ( ) ;
context . rect ( Math . floor ( bounds . min . x - 3 ) , Math . floor ( bounds . min . y - 3 ) ,
Math . floor ( bounds . max . x - bounds . min . x + 6 ) , Math . floor ( bounds . max . y - bounds . min . y + 6 ) ) ;
context . closePath ( ) ;
context . stroke ( ) ;
break ;
case 'constraint' :
// render constraint selections
var point = item . pointA ;
if ( item . bodyA )
point = item . pointB ;
context . beginPath ( ) ;
context . arc ( point . x , point . y , 10 , 0 , 2 * Math . PI ) ;
context . closePath ( ) ;
context . stroke ( ) ;
break ;
}
2015-08-12 19:38:20 -04:00
context . setLineDash ( [ ] ) ;
2014-05-01 09:09:06 -04:00
context . translate ( - 0.5 , - 0.5 ) ;
}
// render selection region
if ( inspector . selectStart !== null ) {
context . translate ( 0.5 , 0.5 ) ;
context . lineWidth = 1 ;
context . strokeStyle = 'rgba(255,165,0,0.6)' ;
context . fillStyle = 'rgba(255,165,0,0.1)' ;
bounds = inspector . selectBounds ;
context . beginPath ( ) ;
context . rect ( Math . floor ( bounds . min . x ) , Math . floor ( bounds . min . y ) ,
Math . floor ( bounds . max . x - bounds . min . x ) , Math . floor ( bounds . max . y - bounds . min . y ) ) ;
context . closePath ( ) ;
context . stroke ( ) ;
context . fill ( ) ;
context . translate ( - 0.5 , - 0.5 ) ;
}
if ( options . hasBounds )
2014-05-05 14:32:51 -04:00
context . setTransform ( 1 , 0 , 0 , 1 , 0 , 0 ) ;
2014-05-01 09:09:06 -04:00
} ;
2014-02-28 20:10:08 -05:00
/ * *
* Description
* @ method _createCanvas
* @ private
* @ param { } width
* @ param { } height
* @ return canvas
* /
2014-02-19 09:15:05 -05:00
var _createCanvas = function ( width , height ) {
var canvas = document . createElement ( 'canvas' ) ;
canvas . width = width ;
canvas . height = height ;
canvas . oncontextmenu = function ( ) { return false ; } ;
canvas . onselectstart = function ( ) { return false ; } ;
return canvas ;
} ;
2014-12-28 13:37:43 -05:00
/ * *
* Gets the pixel ratio of the canvas .
* @ method _getPixelRatio
* @ private
* @ param { HTMLElement } canvas
* @ return { Number } pixel ratio
* /
var _getPixelRatio = function ( canvas ) {
var context = canvas . getContext ( '2d' ) ,
devicePixelRatio = window . devicePixelRatio || 1 ,
backingStorePixelRatio = context . webkitBackingStorePixelRatio || context . mozBackingStorePixelRatio
|| context . msBackingStorePixelRatio || context . oBackingStorePixelRatio
|| context . backingStorePixelRatio || 1 ;
return devicePixelRatio / backingStorePixelRatio ;
} ;
2014-03-22 13:51:49 -04:00
/ * *
* Gets the requested texture ( an Image ) via its path
* @ method _getTexture
* @ private
* @ param { render } render
* @ param { string } imagePath
* @ return { Image } texture
* /
var _getTexture = function ( render , imagePath ) {
var image = render . textures [ imagePath ] ;
if ( image )
return image ;
image = render . textures [ imagePath ] = new Image ( ) ;
image . src = imagePath ;
return image ;
} ;
2015-01-20 19:15:04 -05:00
/ * *
* Applies the background to the canvas using CSS .
* @ method applyBackground
* @ private
* @ param { render } render
* @ param { string } background
* /
var _applyBackground = function ( render , background ) {
var cssBackground = background ;
if ( /(jpg|gif|png)$/ . test ( background ) )
cssBackground = 'url(' + background + ')' ;
render . canvas . style . background = cssBackground ;
render . canvas . style . backgroundSize = "contain" ;
render . currentBackground = background ;
} ;
2015-08-12 19:38:20 -04:00
/ *
*
* Events Documentation
*
* /
/ * *
* Fired before rendering
*
* @ event beforeRender
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
/ * *
* Fired after rendering
*
* @ event afterRender
* @ param { } event An event object
* @ param { number } event . timestamp The engine . timing . timestamp of the event
* @ param { } event . source The source object of the event
* @ param { } event . name The name of the event
* /
2014-06-09 14:40:24 -04:00
/ *
*
* Properties Documentation
*
* /
/ * *
* A back - reference to the ` Matter.Render ` module .
*
* @ property controller
* @ type render
* /
/ * *
* A reference to the element where the canvas is to be inserted ( if ` render.canvas ` has not been specified )
*
* @ property element
* @ type HTMLElement
* @ default null
* /
/ * *
* The canvas element to render to . If not specified , one will be created if ` render.element ` has been specified .
*
* @ property canvas
* @ type HTMLCanvasElement
* @ default null
* /
/ * *
* The configuration options of the renderer .
*
* @ property options
* @ type { }
* /
/ * *
* The target width in pixels of the ` render.canvas ` to be created .
*
* @ property options . width
* @ type number
* @ default 800
* /
/ * *
* The target height in pixels of the ` render.canvas ` to be created .
*
* @ property options . height
* @ type number
* @ default 600
* /
/ * *
* A flag that specifies if ` render.bounds ` should be used when rendering .
*
* @ property options . hasBounds
* @ type boolean
* @ default false
* /
/ * *
* A ` Bounds ` object that specifies the drawing view region .
* Rendering will be automatically transformed and scaled to fit within the canvas size ( ` render.options.width ` and ` render.options.height ` ) .
* This allows for creating views that can pan or zoom around the scene .
* You must also set ` render.options.hasBounds ` to ` true ` to enable bounded rendering .
*
* @ property bounds
* @ type bounds
* /
/ * *
* The 2 d rendering context from the ` render.canvas ` element .
*
* @ property context
* @ type CanvasRenderingContext2D
* /
/ * *
* The sprite texture cache .
*
* @ property textures
* @ type { }
* /
2014-02-19 09:15:05 -05:00
} ) ( ) ;
2015-12-05 11:47:50 -05:00
} , { "../body/Composite" : 2 , "../collision/Grid" : 6 , "../core/Common" : 14 , "../core/Events" : 16 , "../geometry/Bounds" : 24 , "../geometry/Vector" : 26 } ] , 30 : [ function ( require , module , exports ) {
2014-03-22 13:51:49 -04:00
/ * *
2016-02-07 10:53:07 -05:00
* The ` Matter.RenderPixi ` module is an example renderer using pixi . js .
* See also ` Matter.Render ` for a canvas based renderer .
2014-03-22 13:51:49 -04:00
*
* @ class RenderPixi
* /
var RenderPixi = { } ;
2015-08-17 18:50:03 -04:00
module . exports = RenderPixi ;
2015-09-17 13:47:56 -04:00
var Composite = require ( '../body/Composite' ) ;
var Common = require ( '../core/Common' ) ;
2014-03-22 13:51:49 -04:00
( function ( ) {
/ * *
* Creates a new Pixi . js WebGL renderer
* @ method create
* @ param { object } options
* @ return { RenderPixi } A new renderer
* /
RenderPixi . create = function ( options ) {
var defaults = {
controller : RenderPixi ,
element : null ,
canvas : null ,
2016-02-07 10:53:07 -05:00
renderer : null ,
container : null ,
spriteContainer : null ,
pixiOptions : null ,
2014-03-22 13:51:49 -04:00
options : {
width : 800 ,
height : 600 ,
background : '#fafafa' ,
wireframeBackground : '#222' ,
2014-07-29 11:26:49 -04:00
hasBounds : false ,
2014-03-22 13:51:49 -04:00
enabled : true ,
wireframes : true ,
showSleeping : true ,
showDebug : false ,
showBroadphase : false ,
showBounds : false ,
showVelocity : false ,
showCollisions : false ,
showAxes : false ,
showPositions : false ,
showAngleIndicator : false ,
showIds : false ,
showShadows : false
}
} ;
2014-07-29 11:26:49 -04:00
var render = Common . extend ( defaults , options ) ,
transparent = ! render . options . wireframes && render . options . background === 'transparent' ;
2014-03-22 13:51:49 -04:00
// init pixi
2016-02-07 10:53:07 -05:00
render . pixiOptions = render . pixiOptions || {
2015-05-21 19:33:26 -04:00
view : render . canvas ,
transparent : transparent ,
antialias : true ,
backgroundColor : options . background
2016-02-07 10:53:07 -05:00
} ;
render . renderer = render . renderer || new PIXI . WebGLRenderer ( render . options . width , render . options . height , render . pixiOptions ) ;
render . container = render . container || new PIXI . Container ( ) ;
render . spriteContainer = render . spriteContainer || new PIXI . Container ( ) ;
render . canvas = render . canvas || render . renderer . view ;
2014-07-29 11:26:49 -04:00
render . bounds = render . bounds || {
2016-02-07 10:53:07 -05:00
min : {
2014-07-29 11:26:49 -04:00
x : 0 ,
y : 0
} ,
max : {
x : render . options . width ,
y : render . options . height
}
} ;
2014-03-22 13:51:49 -04:00
// caches
render . textures = { } ;
render . sprites = { } ;
render . primitives = { } ;
// use a sprite batch for performance
2015-05-21 19:33:26 -04:00
render . container . addChild ( render . spriteContainer ) ;
2014-03-22 13:51:49 -04:00
// insert canvas
if ( Common . isElement ( render . element ) ) {
render . element . appendChild ( render . canvas ) ;
} else {
Common . log ( 'No "render.element" passed, "render.canvas" was not inserted into document.' , 'warn' ) ;
}
2014-03-24 16:11:42 -04:00
// prevent menus on canvas
render . canvas . oncontextmenu = function ( ) { return false ; } ;
render . canvas . onselectstart = function ( ) { return false ; } ;
2014-03-22 13:51:49 -04:00
return render ;
} ;
/ * *
* Clears the scene graph
* @ method clear
* @ param { RenderPixi } render
* /
RenderPixi . clear = function ( render ) {
2014-07-29 11:26:49 -04:00
var container = render . container ,
2015-05-21 19:33:26 -04:00
spriteContainer = render . spriteContainer ;
2014-03-22 13:51:49 -04:00
2014-07-29 11:26:49 -04:00
// clear stage container
while ( container . children [ 0 ] ) {
container . removeChild ( container . children [ 0 ] ) ;
2014-03-22 13:51:49 -04:00
}
// clear sprite batch
2015-05-21 19:33:26 -04:00
while ( spriteContainer . children [ 0 ] ) {
spriteContainer . removeChild ( spriteContainer . children [ 0 ] ) ;
2014-03-22 13:51:49 -04:00
}
var bgSprite = render . sprites [ 'bg-0' ] ;
// clear caches
render . textures = { } ;
render . sprites = { } ;
render . primitives = { } ;
// set background sprite
render . sprites [ 'bg-0' ] = bgSprite ;
if ( bgSprite )
2015-05-21 19:33:26 -04:00
container . addChildAt ( bgSprite , 0 ) ;
2014-03-22 13:51:49 -04:00
2014-07-29 11:26:49 -04:00
// add sprite batch back into container
2015-05-21 19:33:26 -04:00
render . container . addChild ( render . spriteContainer ) ;
2014-03-22 13:51:49 -04:00
// reset background state
render . currentBackground = null ;
2014-07-29 11:26:49 -04:00
// reset bounds transforms
container . scale . set ( 1 , 1 ) ;
container . position . set ( 0 , 0 ) ;
2014-03-22 13:51:49 -04:00
} ;
/ * *
* Sets the background of the canvas
* @ method setBackground
* @ param { RenderPixi } render
* @ param { string } background
* /
RenderPixi . setBackground = function ( render , background ) {
if ( render . currentBackground !== background ) {
var isColor = background . indexOf && background . indexOf ( '#' ) !== - 1 ,
bgSprite = render . sprites [ 'bg-0' ] ;
if ( isColor ) {
// if solid background color
var color = Common . colorToNumber ( background ) ;
2016-02-07 10:53:07 -05:00
render . renderer . backgroundColor = color ;
2014-03-22 13:51:49 -04:00
// remove background sprite if existing
if ( bgSprite )
2015-05-21 19:33:26 -04:00
render . container . removeChild ( bgSprite ) ;
2014-03-22 13:51:49 -04:00
} else {
// initialise background sprite if needed
if ( ! bgSprite ) {
var texture = _getTexture ( render , background ) ;
bgSprite = render . sprites [ 'bg-0' ] = new PIXI . Sprite ( texture ) ;
bgSprite . position . x = 0 ;
bgSprite . position . y = 0 ;
2015-05-21 19:33:26 -04:00
render . container . addChildAt ( bgSprite , 0 ) ;
2014-03-22 13:51:49 -04:00
}
}
render . currentBackground = background ;
}
} ;
/ * *
* Description
* @ method world
* @ param { engine } engine
* /
RenderPixi . world = function ( engine ) {
var render = engine . render ,
world = engine . world ,
2016-02-07 10:53:07 -05:00
renderer = render . renderer ,
2014-07-29 11:26:49 -04:00
container = render . container ,
2014-03-22 13:51:49 -04:00
options = render . options ,
2014-03-24 16:11:42 -04:00
bodies = Composite . allBodies ( world ) ,
2014-07-29 11:26:49 -04:00
allConstraints = Composite . allConstraints ( world ) ,
constraints = [ ] ,
2014-03-22 13:51:49 -04:00
i ;
if ( options . wireframes ) {
RenderPixi . setBackground ( render , options . wireframeBackground ) ;
} else {
RenderPixi . setBackground ( render , options . background ) ;
}
2014-07-29 11:26:49 -04:00
// handle bounds
var boundsWidth = render . bounds . max . x - render . bounds . min . x ,
boundsHeight = render . bounds . max . y - render . bounds . min . y ,
boundsScaleX = boundsWidth / render . options . width ,
boundsScaleY = boundsHeight / render . options . height ;
if ( options . hasBounds ) {
// Hide bodies that are not in view
for ( i = 0 ; i < bodies . length ; i ++ ) {
var body = bodies [ i ] ;
body . render . sprite . visible = Bounds . overlaps ( body . bounds , render . bounds ) ;
}
// filter out constraints that are not in view
for ( i = 0 ; i < allConstraints . length ; i ++ ) {
var constraint = allConstraints [ i ] ,
bodyA = constraint . bodyA ,
bodyB = constraint . bodyB ,
pointAWorld = constraint . pointA ,
pointBWorld = constraint . pointB ;
if ( bodyA ) pointAWorld = Vector . add ( bodyA . position , constraint . pointA ) ;
if ( bodyB ) pointBWorld = Vector . add ( bodyB . position , constraint . pointB ) ;
if ( ! pointAWorld || ! pointBWorld )
continue ;
if ( Bounds . contains ( render . bounds , pointAWorld ) || Bounds . contains ( render . bounds , pointBWorld ) )
constraints . push ( constraint ) ;
}
// transform the view
container . scale . set ( 1 / boundsScaleX , 1 / boundsScaleY ) ;
container . position . set ( - render . bounds . min . x * ( 1 / boundsScaleX ) , - render . bounds . min . y * ( 1 / boundsScaleY ) ) ;
} else {
constraints = allConstraints ;
}
2014-03-24 16:11:42 -04:00
for ( i = 0 ; i < bodies . length ; i ++ )
RenderPixi . body ( engine , bodies [ i ] ) ;
2014-03-22 13:51:49 -04:00
2014-03-24 16:11:42 -04:00
for ( i = 0 ; i < constraints . length ; i ++ )
RenderPixi . constraint ( engine , constraints [ i ] ) ;
2014-03-22 13:51:49 -04:00
2016-02-07 10:53:07 -05:00
renderer . render ( container ) ;
2014-03-22 13:51:49 -04:00
} ;
/ * *
* Description
* @ method constraint
* @ param { engine } engine
* @ param { constraint } constraint
* /
RenderPixi . constraint = function ( engine , constraint ) {
var render = engine . render ,
bodyA = constraint . bodyA ,
bodyB = constraint . bodyB ,
pointA = constraint . pointA ,
pointB = constraint . pointB ,
2014-07-29 11:26:49 -04:00
container = render . container ,
2014-03-22 13:51:49 -04:00
constraintRender = constraint . render ,
primitiveId = 'c-' + constraint . id ,
primitive = render . primitives [ primitiveId ] ;
// initialise constraint primitive if not existing
if ( ! primitive )
primitive = render . primitives [ primitiveId ] = new PIXI . Graphics ( ) ;
// don't render if constraint does not have two end points
if ( ! constraintRender . visible || ! constraint . pointA || ! constraint . pointB ) {
primitive . clear ( ) ;
return ;
}
// add to scene graph if not already there
2014-07-29 11:26:49 -04:00
if ( Common . indexOf ( container . children , primitive ) === - 1 )
container . addChild ( primitive ) ;
2014-03-22 13:51:49 -04:00
// render the constraint on every update, since they can change dynamically
primitive . clear ( ) ;
primitive . beginFill ( 0 , 0 ) ;
primitive . lineStyle ( constraintRender . lineWidth , Common . colorToNumber ( constraintRender . strokeStyle ) , 1 ) ;
if ( bodyA ) {
primitive . moveTo ( bodyA . position . x + pointA . x , bodyA . position . y + pointA . y ) ;
} else {
primitive . moveTo ( pointA . x , pointA . y ) ;
}
if ( bodyB ) {
primitive . lineTo ( bodyB . position . x + pointB . x , bodyB . position . y + pointB . y ) ;
} else {
primitive . lineTo ( pointB . x , pointB . y ) ;
}
primitive . endFill ( ) ;
} ;
/ * *
* Description
* @ method body
* @ param { engine } engine
* @ param { body } body
* /
RenderPixi . body = function ( engine , body ) {
var render = engine . render ,
bodyRender = body . render ;
if ( ! bodyRender . visible )
return ;
2014-03-30 14:45:30 -04:00
if ( bodyRender . sprite && bodyRender . sprite . texture ) {
2014-03-22 13:51:49 -04:00
var spriteId = 'b-' + body . id ,
sprite = render . sprites [ spriteId ] ,
2015-05-21 19:33:26 -04:00
spriteContainer = render . spriteContainer ;
2014-03-22 13:51:49 -04:00
// initialise body sprite if not existing
if ( ! sprite )
sprite = render . sprites [ spriteId ] = _createBodySprite ( render , body ) ;
// add to scene graph if not already there
2015-05-21 19:33:26 -04:00
if ( Common . indexOf ( spriteContainer . children , sprite ) === - 1 )
spriteContainer . addChild ( sprite ) ;
2014-03-22 13:51:49 -04:00
// update body sprite
sprite . position . x = body . position . x ;
sprite . position . y = body . position . y ;
sprite . rotation = body . angle ;
2014-12-28 13:37:43 -05:00
sprite . scale . x = bodyRender . sprite . xScale || 1 ;
sprite . scale . y = bodyRender . sprite . yScale || 1 ;
2014-03-22 13:51:49 -04:00
} else {
var primitiveId = 'b-' + body . id ,
primitive = render . primitives [ primitiveId ] ,
2014-07-29 11:26:49 -04:00
container = render . container ;
2014-03-22 13:51:49 -04:00
// initialise body primitive if not existing
if ( ! primitive ) {
primitive = render . primitives [ primitiveId ] = _createBodyPrimitive ( render , body ) ;
primitive . initialAngle = body . angle ;
}
// add to scene graph if not already there
2014-07-29 11:26:49 -04:00
if ( Common . indexOf ( container . children , primitive ) === - 1 )
container . addChild ( primitive ) ;
2014-03-22 13:51:49 -04:00
// update body primitive
primitive . position . x = body . position . x ;
primitive . position . y = body . position . y ;
primitive . rotation = body . angle - primitive . initialAngle ;
}
} ;
/ * *
* Creates a body sprite
* @ method _createBodySprite
* @ private
* @ param { RenderPixi } render
* @ param { body } body
* @ return { PIXI . Sprite } sprite
* /
var _createBodySprite = function ( render , body ) {
var bodyRender = body . render ,
texturePath = bodyRender . sprite . texture ,
texture = _getTexture ( render , texturePath ) ,
sprite = new PIXI . Sprite ( texture ) ;
2015-12-23 08:08:54 -05:00
sprite . anchor . x = body . render . sprite . xOffset ;
sprite . anchor . y = body . render . sprite . yOffset ;
2014-03-22 13:51:49 -04:00
return sprite ;
} ;
/ * *
* Creates a body primitive
* @ method _createBodyPrimitive
* @ private
* @ param { RenderPixi } render
* @ param { body } body
* @ return { PIXI . Graphics } graphics
* /
var _createBodyPrimitive = function ( render , body ) {
var bodyRender = body . render ,
options = render . options ,
2015-05-20 15:38:41 -04:00
primitive = new PIXI . Graphics ( ) ,
fillStyle = Common . colorToNumber ( bodyRender . fillStyle ) ,
strokeStyle = Common . colorToNumber ( bodyRender . strokeStyle ) ,
strokeStyleIndicator = Common . colorToNumber ( bodyRender . strokeStyle ) ,
strokeStyleWireframe = Common . colorToNumber ( '#bbb' ) ,
strokeStyleWireframeIndicator = Common . colorToNumber ( '#CD5C5C' ) ,
part ;
2014-03-22 13:51:49 -04:00
primitive . clear ( ) ;
2015-05-20 15:38:41 -04:00
// handle compound parts
for ( var k = body . parts . length > 1 ? 1 : 0 ; k < body . parts . length ; k ++ ) {
part = body . parts [ k ] ;
if ( ! options . wireframes ) {
primitive . beginFill ( fillStyle , 1 ) ;
primitive . lineStyle ( bodyRender . lineWidth , strokeStyle , 1 ) ;
} else {
primitive . beginFill ( 0 , 0 ) ;
primitive . lineStyle ( 1 , strokeStyleWireframe , 1 ) ;
}
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
primitive . moveTo ( part . vertices [ 0 ] . x - body . position . x , part . vertices [ 0 ] . y - body . position . y ) ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
for ( var j = 1 ; j < part . vertices . length ; j ++ ) {
primitive . lineTo ( part . vertices [ j ] . x - body . position . x , part . vertices [ j ] . y - body . position . y ) ;
}
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
primitive . lineTo ( part . vertices [ 0 ] . x - body . position . x , part . vertices [ 0 ] . y - body . position . y ) ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
primitive . endFill ( ) ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
// angle indicator
if ( options . showAngleIndicator || options . showAxes ) {
primitive . beginFill ( 0 , 0 ) ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
if ( options . wireframes ) {
primitive . lineStyle ( 1 , strokeStyleWireframeIndicator , 1 ) ;
} else {
primitive . lineStyle ( 1 , strokeStyleIndicator ) ;
}
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
primitive . moveTo ( part . position . x - body . position . x , part . position . y - body . position . y ) ;
primitive . lineTo ( ( ( part . vertices [ 0 ] . x + part . vertices [ part . vertices . length - 1 ] . x ) / 2 - body . position . x ) ,
( ( part . vertices [ 0 ] . y + part . vertices [ part . vertices . length - 1 ] . y ) / 2 - body . position . y ) ) ;
2014-03-22 13:51:49 -04:00
2015-05-20 15:38:41 -04:00
primitive . endFill ( ) ;
}
2014-03-22 13:51:49 -04:00
}
return primitive ;
} ;
/ * *
* Gets the requested texture ( a PIXI . Texture ) via its path
* @ method _getTexture
* @ private
* @ param { RenderPixi } render
* @ param { string } imagePath
* @ return { PIXI . Texture } texture
* /
var _getTexture = function ( render , imagePath ) {
var texture = render . textures [ imagePath ] ;
if ( ! texture )
texture = render . textures [ imagePath ] = PIXI . Texture . fromImage ( imagePath ) ;
return texture ;
} ;
} ) ( ) ;
2015-09-17 13:47:56 -04:00
} , { "../body/Composite" : 2 , "../core/Common" : 14 } ] } , { } , [ 28 ] ) ( 28 )
2015-08-17 18:50:03 -04:00
} ) ;