mirror of
https://github.com/liabru/matter-js.git
synced 2024-12-26 13:49:01 -05:00
515 lines
17 KiB
JavaScript
515 lines
17 KiB
JavaScript
/**
|
|
* The `Matter.RenderPixi` module is an example renderer using pixi.js.
|
|
* See also `Matter.Render` for a canvas based renderer.
|
|
*
|
|
* @class RenderPixi
|
|
* @deprecated the Matter.RenderPixi module will soon be removed from the Matter.js core.
|
|
* It will likely be moved to its own repository (but maintenance will be limited).
|
|
*/
|
|
|
|
var RenderPixi = {};
|
|
|
|
module.exports = RenderPixi;
|
|
|
|
var Bounds = require('../geometry/Bounds');
|
|
var Composite = require('../body/Composite');
|
|
var Common = require('../core/Common');
|
|
var Events = require('../core/Events');
|
|
var Vector = require('../geometry/Vector');
|
|
|
|
(function() {
|
|
|
|
var _requestAnimationFrame,
|
|
_cancelAnimationFrame;
|
|
|
|
if (typeof window !== 'undefined') {
|
|
_requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame
|
|
|| window.mozRequestAnimationFrame || window.msRequestAnimationFrame
|
|
|| function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); };
|
|
|
|
_cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame
|
|
|| window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;
|
|
}
|
|
|
|
/**
|
|
* Creates a new Pixi.js WebGL renderer
|
|
* @method create
|
|
* @param {object} options
|
|
* @return {RenderPixi} A new renderer
|
|
* @deprecated
|
|
*/
|
|
RenderPixi.create = function(options) {
|
|
Common.warn('RenderPixi.create: Matter.RenderPixi is deprecated (see docs)');
|
|
|
|
var defaults = {
|
|
controller: RenderPixi,
|
|
engine: null,
|
|
element: null,
|
|
frameRequestId: null,
|
|
canvas: null,
|
|
renderer: null,
|
|
container: null,
|
|
spriteContainer: null,
|
|
pixiOptions: null,
|
|
options: {
|
|
width: 800,
|
|
height: 600,
|
|
background: '#fafafa',
|
|
wireframeBackground: '#222',
|
|
hasBounds: false,
|
|
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
|
|
}
|
|
};
|
|
|
|
var render = Common.extend(defaults, options),
|
|
transparent = !render.options.wireframes && render.options.background === 'transparent';
|
|
|
|
// init pixi
|
|
render.pixiOptions = render.pixiOptions || {
|
|
view: render.canvas,
|
|
transparent: transparent,
|
|
antialias: true,
|
|
backgroundColor: options.background
|
|
};
|
|
|
|
render.mouse = options.mouse;
|
|
render.engine = options.engine;
|
|
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;
|
|
render.bounds = render.bounds || {
|
|
min: {
|
|
x: 0,
|
|
y: 0
|
|
},
|
|
max: {
|
|
x: render.options.width,
|
|
y: render.options.height
|
|
}
|
|
};
|
|
|
|
// event listeners
|
|
Events.on(render.engine, 'beforeUpdate', function() {
|
|
RenderPixi.clear(render);
|
|
});
|
|
|
|
// caches
|
|
render.textures = {};
|
|
render.sprites = {};
|
|
render.primitives = {};
|
|
|
|
// use a sprite batch for performance
|
|
render.container.addChild(render.spriteContainer);
|
|
|
|
// insert canvas
|
|
if (Common.isElement(render.element)) {
|
|
render.element.appendChild(render.canvas);
|
|
} else {
|
|
Common.warn('No "render.element" passed, "render.canvas" was not inserted into document.');
|
|
}
|
|
|
|
// prevent menus on canvas
|
|
render.canvas.oncontextmenu = function() { return false; };
|
|
render.canvas.onselectstart = function() { return false; };
|
|
|
|
return render;
|
|
};
|
|
|
|
/**
|
|
* Continuously updates the render canvas on the `requestAnimationFrame` event.
|
|
* @method run
|
|
* @param {render} render
|
|
* @deprecated
|
|
*/
|
|
RenderPixi.run = function(render) {
|
|
(function loop(time){
|
|
render.frameRequestId = _requestAnimationFrame(loop);
|
|
RenderPixi.world(render);
|
|
})();
|
|
};
|
|
|
|
/**
|
|
* Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop.
|
|
* @method stop
|
|
* @param {render} render
|
|
* @deprecated
|
|
*/
|
|
RenderPixi.stop = function(render) {
|
|
_cancelAnimationFrame(render.frameRequestId);
|
|
};
|
|
|
|
/**
|
|
* Clears the scene graph
|
|
* @method clear
|
|
* @param {RenderPixi} render
|
|
* @deprecated
|
|
*/
|
|
RenderPixi.clear = function(render) {
|
|
var container = render.container,
|
|
spriteContainer = render.spriteContainer;
|
|
|
|
// clear stage container
|
|
while (container.children[0]) {
|
|
container.removeChild(container.children[0]);
|
|
}
|
|
|
|
// clear sprite batch
|
|
while (spriteContainer.children[0]) {
|
|
spriteContainer.removeChild(spriteContainer.children[0]);
|
|
}
|
|
|
|
var bgSprite = render.sprites['bg-0'];
|
|
|
|
// clear caches
|
|
render.textures = {};
|
|
render.sprites = {};
|
|
render.primitives = {};
|
|
|
|
// set background sprite
|
|
render.sprites['bg-0'] = bgSprite;
|
|
if (bgSprite)
|
|
container.addChildAt(bgSprite, 0);
|
|
|
|
// add sprite batch back into container
|
|
render.container.addChild(render.spriteContainer);
|
|
|
|
// reset background state
|
|
render.currentBackground = null;
|
|
|
|
// reset bounds transforms
|
|
container.scale.set(1, 1);
|
|
container.position.set(0, 0);
|
|
};
|
|
|
|
/**
|
|
* Sets the background of the canvas
|
|
* @method setBackground
|
|
* @param {RenderPixi} render
|
|
* @param {string} background
|
|
* @deprecated
|
|
*/
|
|
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);
|
|
render.renderer.backgroundColor = color;
|
|
|
|
// remove background sprite if existing
|
|
if (bgSprite)
|
|
render.container.removeChild(bgSprite);
|
|
} 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;
|
|
render.container.addChildAt(bgSprite, 0);
|
|
}
|
|
}
|
|
|
|
render.currentBackground = background;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Description
|
|
* @method world
|
|
* @param {engine} engine
|
|
* @deprecated
|
|
*/
|
|
RenderPixi.world = function(render) {
|
|
var engine = render.engine,
|
|
world = engine.world,
|
|
renderer = render.renderer,
|
|
container = render.container,
|
|
options = render.options,
|
|
bodies = Composite.allBodies(world),
|
|
allConstraints = Composite.allConstraints(world),
|
|
constraints = [],
|
|
i;
|
|
|
|
if (options.wireframes) {
|
|
RenderPixi.setBackground(render, options.wireframeBackground);
|
|
} else {
|
|
RenderPixi.setBackground(render, options.background);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
for (i = 0; i < bodies.length; i++)
|
|
RenderPixi.body(render, bodies[i]);
|
|
|
|
for (i = 0; i < constraints.length; i++)
|
|
RenderPixi.constraint(render, constraints[i]);
|
|
|
|
renderer.render(container);
|
|
};
|
|
|
|
|
|
/**
|
|
* Description
|
|
* @method constraint
|
|
* @param {engine} engine
|
|
* @param {constraint} constraint
|
|
* @deprecated
|
|
*/
|
|
RenderPixi.constraint = function(render, constraint) {
|
|
var engine = render.engine,
|
|
bodyA = constraint.bodyA,
|
|
bodyB = constraint.bodyB,
|
|
pointA = constraint.pointA,
|
|
pointB = constraint.pointB,
|
|
container = render.container,
|
|
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
|
|
if (Common.indexOf(container.children, primitive) === -1)
|
|
container.addChild(primitive);
|
|
|
|
// 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
|
|
* @deprecated
|
|
*/
|
|
RenderPixi.body = function(render, body) {
|
|
var engine = render.engine,
|
|
bodyRender = body.render;
|
|
|
|
if (!bodyRender.visible)
|
|
return;
|
|
|
|
if (bodyRender.sprite && bodyRender.sprite.texture) {
|
|
var spriteId = 'b-' + body.id,
|
|
sprite = render.sprites[spriteId],
|
|
spriteContainer = render.spriteContainer;
|
|
|
|
// initialise body sprite if not existing
|
|
if (!sprite)
|
|
sprite = render.sprites[spriteId] = _createBodySprite(render, body);
|
|
|
|
// add to scene graph if not already there
|
|
if (Common.indexOf(spriteContainer.children, sprite) === -1)
|
|
spriteContainer.addChild(sprite);
|
|
|
|
// update body sprite
|
|
sprite.position.x = body.position.x;
|
|
sprite.position.y = body.position.y;
|
|
sprite.rotation = body.angle;
|
|
sprite.scale.x = bodyRender.sprite.xScale || 1;
|
|
sprite.scale.y = bodyRender.sprite.yScale || 1;
|
|
} else {
|
|
var primitiveId = 'b-' + body.id,
|
|
primitive = render.primitives[primitiveId],
|
|
container = render.container;
|
|
|
|
// 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
|
|
if (Common.indexOf(container.children, primitive) === -1)
|
|
container.addChild(primitive);
|
|
|
|
// 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
|
|
* @deprecated
|
|
*/
|
|
var _createBodySprite = function(render, body) {
|
|
var bodyRender = body.render,
|
|
texturePath = bodyRender.sprite.texture,
|
|
texture = _getTexture(render, texturePath),
|
|
sprite = new PIXI.Sprite(texture);
|
|
|
|
sprite.anchor.x = body.render.sprite.xOffset;
|
|
sprite.anchor.y = body.render.sprite.yOffset;
|
|
|
|
return sprite;
|
|
};
|
|
|
|
/**
|
|
* Creates a body primitive
|
|
* @method _createBodyPrimitive
|
|
* @private
|
|
* @param {RenderPixi} render
|
|
* @param {body} body
|
|
* @return {PIXI.Graphics} graphics
|
|
* @deprecated
|
|
*/
|
|
var _createBodyPrimitive = function(render, body) {
|
|
var bodyRender = body.render,
|
|
options = render.options,
|
|
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;
|
|
|
|
primitive.clear();
|
|
|
|
// 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);
|
|
}
|
|
|
|
primitive.moveTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
|
|
|
|
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);
|
|
}
|
|
|
|
primitive.lineTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
|
|
|
|
primitive.endFill();
|
|
|
|
// angle indicator
|
|
if (options.showAngleIndicator || options.showAxes) {
|
|
primitive.beginFill(0, 0);
|
|
|
|
if (options.wireframes) {
|
|
primitive.lineStyle(1, strokeStyleWireframeIndicator, 1);
|
|
} else {
|
|
primitive.lineStyle(1, strokeStyleIndicator);
|
|
}
|
|
|
|
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));
|
|
|
|
primitive.endFill();
|
|
}
|
|
}
|
|
|
|
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
|
|
* @deprecated
|
|
*/
|
|
var _getTexture = function(render, imagePath) {
|
|
var texture = render.textures[imagePath];
|
|
|
|
if (!texture)
|
|
texture = render.textures[imagePath] = PIXI.Texture.fromImage(imagePath);
|
|
|
|
return texture;
|
|
};
|
|
|
|
})();
|