mirror of
https://github.com/liabru/matter-js.git
synced 2024-12-27 13:59:01 -05:00
364 lines
12 KiB
JavaScript
364 lines
12 KiB
JavaScript
/**
|
|
* The Matter.js demo page controller and example runner.
|
|
*
|
|
* NOTE: For the actual example code, refer to the source files in `/examples/`.
|
|
*
|
|
* @class Demo
|
|
*/
|
|
|
|
(function() {
|
|
|
|
var _isBrowser = typeof window !== 'undefined' && window.location,
|
|
_useInspector = _isBrowser && window.location.hash.indexOf('-inspect') !== -1,
|
|
_isMobile = _isBrowser && /(ipad|iphone|ipod|android)/gi.test(navigator.userAgent),
|
|
_isAutomatedTest = !_isBrowser || window._phantom;
|
|
|
|
var Matter = _isBrowser ? window.Matter : require('../../build/matter-dev.js');
|
|
|
|
var Demo = {};
|
|
Matter.Demo = Demo;
|
|
|
|
if (!_isBrowser) {
|
|
module.exports = Demo;
|
|
window = {};
|
|
}
|
|
|
|
// Matter aliases
|
|
var Body = Matter.Body,
|
|
Example = Matter.Example,
|
|
Engine = Matter.Engine,
|
|
World = Matter.World,
|
|
Common = Matter.Common,
|
|
Bodies = Matter.Bodies,
|
|
Events = Matter.Events,
|
|
Mouse = Matter.Mouse,
|
|
MouseConstraint = Matter.MouseConstraint,
|
|
Runner = Matter.Runner;
|
|
|
|
// MatterTools aliases
|
|
if (window.MatterTools) {
|
|
var Gui = MatterTools.Gui,
|
|
Inspector = MatterTools.Inspector;
|
|
}
|
|
|
|
Demo.create = function(options) {
|
|
var defaults = {
|
|
isManual: false,
|
|
sceneName: 'mixed',
|
|
sceneEvents: []
|
|
};
|
|
|
|
return Common.extend(defaults, options);
|
|
};
|
|
|
|
Demo.init = function() {
|
|
var demo = Demo.create();
|
|
Matter.Demo._demo = demo;
|
|
|
|
// get container element for the canvas
|
|
demo.container = document.getElementById('canvas-container');
|
|
|
|
// create an example engine (see /examples/engine.js)
|
|
demo.engine = Example.engine(demo);
|
|
|
|
// run the engine
|
|
demo.runner = Engine.run(demo.engine);
|
|
|
|
// add a mouse controlled constraint
|
|
demo.mouseConstraint = MouseConstraint.create(demo.engine);
|
|
World.add(demo.engine.world, demo.mouseConstraint);
|
|
|
|
// pass mouse to renderer to enable showMousePosition
|
|
demo.engine.render.mouse = demo.mouseConstraint.mouse;
|
|
|
|
// get the scene function name from hash
|
|
if (window.location.hash.length !== 0)
|
|
demo.sceneName = window.location.hash.replace('#', '').replace('-inspect', '');
|
|
|
|
// set up a scene with bodies
|
|
Demo.reset(demo);
|
|
Demo.setScene(demo, demo.sceneName);
|
|
|
|
// set up demo interface (see end of this file)
|
|
Demo.initControls(demo);
|
|
|
|
// pass through runner as timing for debug rendering
|
|
demo.engine.metrics.timing = demo.runner;
|
|
|
|
return demo;
|
|
};
|
|
|
|
// call init when the page has loaded fully
|
|
if (!_isAutomatedTest) {
|
|
if (window.addEventListener) {
|
|
window.addEventListener('load', Demo.init);
|
|
} else if (window.attachEvent) {
|
|
window.attachEvent('load', Demo.init);
|
|
}
|
|
}
|
|
|
|
Demo.setScene = function(demo, sceneName) {
|
|
Example[sceneName](demo);
|
|
};
|
|
|
|
// the functions for the demo interface and controls below
|
|
Demo.initControls = function(demo) {
|
|
var demoSelect = document.getElementById('demo-select'),
|
|
demoReset = document.getElementById('demo-reset');
|
|
|
|
// create a Matter.Gui
|
|
if (!_isMobile && Gui) {
|
|
demo.gui = Gui.create(demo.engine, demo.runner);
|
|
|
|
// need to add mouse constraint back in after gui clear or load is pressed
|
|
Events.on(demo.gui, 'clear load', function() {
|
|
demo.mouseConstraint = MouseConstraint.create(demo.engine);
|
|
World.add(demo.engine.world, demo.mouseConstraint);
|
|
});
|
|
|
|
// need to rebind mouse on render change
|
|
Events.on(demo.gui, 'setRenderer', function() {
|
|
Mouse.setElement(demo.mouseConstraint.mouse, demo.engine.render.canvas);
|
|
});
|
|
}
|
|
|
|
// create a Matter.Inspector
|
|
if (!_isMobile && Inspector && _useInspector) {
|
|
demo.inspector = Inspector.create(demo.engine, demo.runner);
|
|
|
|
Events.on(demo.inspector, 'import', function() {
|
|
demo.mouseConstraint = MouseConstraint.create(demo.engine);
|
|
World.add(demo.engine.world, demo.mouseConstraint);
|
|
});
|
|
|
|
Events.on(demo.inspector, 'play', function() {
|
|
demo.mouseConstraint = MouseConstraint.create(demo.engine);
|
|
World.add(demo.engine.world, demo.mouseConstraint);
|
|
});
|
|
|
|
Events.on(demo.inspector, 'selectStart', function() {
|
|
demo.mouseConstraint.constraint.render.visible = false;
|
|
});
|
|
|
|
Events.on(demo.inspector, 'selectEnd', function() {
|
|
demo.mouseConstraint.constraint.render.visible = true;
|
|
});
|
|
}
|
|
|
|
// go fullscreen when using a mobile device
|
|
if (_isMobile) {
|
|
var body = document.body;
|
|
|
|
body.className += ' is-mobile';
|
|
demo.engine.render.canvas.addEventListener('touchstart', Demo.fullscreen);
|
|
|
|
var fullscreenChange = function() {
|
|
var fullscreenEnabled = document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled;
|
|
|
|
// delay fullscreen styles until fullscreen has finished changing
|
|
setTimeout(function() {
|
|
if (fullscreenEnabled) {
|
|
body.className += ' is-fullscreen';
|
|
} else {
|
|
body.className = body.className.replace('is-fullscreen', '');
|
|
}
|
|
}, 2000);
|
|
};
|
|
|
|
document.addEventListener('webkitfullscreenchange', fullscreenChange);
|
|
document.addEventListener('mozfullscreenchange', fullscreenChange);
|
|
document.addEventListener('fullscreenchange', fullscreenChange);
|
|
}
|
|
|
|
// keyboard controls
|
|
document.onkeypress = function(keys) {
|
|
// shift + a = toggle manual
|
|
if (keys.shiftKey && keys.keyCode === 65) {
|
|
Demo.setManualControl(demo, !demo.isManual);
|
|
}
|
|
|
|
// shift + q = step
|
|
if (keys.shiftKey && keys.keyCode === 81) {
|
|
if (!demo.isManual) {
|
|
Demo.setManualControl(demo, true);
|
|
}
|
|
|
|
Runner.tick(demo.runner, demo.engine);
|
|
}
|
|
};
|
|
|
|
// initialise demo selector
|
|
demoSelect.value = demo.sceneName;
|
|
Demo.setUpdateSourceLink(demo.sceneName);
|
|
|
|
demoSelect.addEventListener('change', function(e) {
|
|
Demo.reset(demo);
|
|
Demo.setScene(demo,demo.sceneName = e.target.value);
|
|
|
|
if (demo.gui) {
|
|
Gui.update(demo.gui);
|
|
}
|
|
|
|
var scrollY = window.scrollY;
|
|
window.location.hash = demo.sceneName;
|
|
window.scrollY = scrollY;
|
|
Demo.setUpdateSourceLink(demo.sceneName);
|
|
});
|
|
|
|
demoReset.addEventListener('click', function(e) {
|
|
Demo.reset(demo);
|
|
Demo.setScene(demo, demo.sceneName);
|
|
|
|
if (demo.gui) {
|
|
Gui.update(demo.gui);
|
|
}
|
|
|
|
Demo.setUpdateSourceLink(demo.sceneName);
|
|
});
|
|
};
|
|
|
|
Demo.setUpdateSourceLink = function(sceneName) {
|
|
var demoViewSource = document.getElementById('demo-view-source'),
|
|
sourceUrl = 'https://github.com/liabru/matter-js/blob/master/examples';
|
|
demoViewSource.setAttribute('href', sourceUrl + '/' + sceneName + '.js');
|
|
};
|
|
|
|
Demo.setManualControl = function(demo, isManual) {
|
|
var engine = demo.engine,
|
|
world = engine.world,
|
|
runner = demo.runner;
|
|
|
|
demo.isManual = isManual;
|
|
|
|
if (demo.isManual) {
|
|
Runner.stop(runner);
|
|
|
|
// continue rendering but not updating
|
|
(function render(time){
|
|
runner.frameRequestId = window.requestAnimationFrame(render);
|
|
Events.trigger(engine, 'beforeUpdate');
|
|
Events.trigger(engine, 'tick');
|
|
engine.render.controller.world(engine);
|
|
Events.trigger(engine, 'afterUpdate');
|
|
})();
|
|
} else {
|
|
Runner.stop(runner);
|
|
Runner.start(runner, engine);
|
|
}
|
|
};
|
|
|
|
Demo.fullscreen = function(demo) {
|
|
var _fullscreenElement = demo.engine.render.canvas;
|
|
|
|
if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement) {
|
|
if (_fullscreenElement.requestFullscreen) {
|
|
_fullscreenElement.requestFullscreen();
|
|
} else if (_fullscreenElement.mozRequestFullScreen) {
|
|
_fullscreenElement.mozRequestFullScreen();
|
|
} else if (_fullscreenElement.webkitRequestFullscreen) {
|
|
_fullscreenElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
|
|
}
|
|
}
|
|
};
|
|
|
|
Demo.reset = function(demo) {
|
|
var world = demo.engine.world,
|
|
i;
|
|
|
|
World.clear(world);
|
|
Engine.clear(demo.engine);
|
|
|
|
// clear scene graph (if defined in controller)
|
|
if (demo.engine.render) {
|
|
var renderController = demo.engine.render.controller;
|
|
if (renderController && renderController.clear)
|
|
renderController.clear(demo.engine.render);
|
|
}
|
|
|
|
// clear all scene events
|
|
if (demo.engine.events) {
|
|
for (i = 0; i < demo.sceneEvents.length; i++)
|
|
Events.off(demo.engine, demo.sceneEvents[i]);
|
|
}
|
|
|
|
if (demo.mouseConstraint && demo.mouseConstraint.events) {
|
|
for (i = 0; i < demo.sceneEvents.length; i++)
|
|
Events.off(demo.mouseConstraint, demo.sceneEvents[i]);
|
|
}
|
|
|
|
if (world.events) {
|
|
for (i = 0; i < demo.sceneEvents.length; i++)
|
|
Events.off(world, demo.sceneEvents[i]);
|
|
}
|
|
|
|
if (demo.runner && demo.runner.events) {
|
|
for (i = 0; i < demo.sceneEvents.length; i++)
|
|
Events.off(demo.runner, demo.sceneEvents[i]);
|
|
}
|
|
|
|
if (demo.engine.render && demo.engine.render.events) {
|
|
for (i = 0; i < demo.sceneEvents.length; i++)
|
|
Events.off(demo.engine.render, demo.sceneEvents[i]);
|
|
}
|
|
|
|
demo.sceneEvents = [];
|
|
|
|
// reset id pool
|
|
Body._nextCollidingGroupId = 1;
|
|
Body._nextNonCollidingGroupId = -1;
|
|
Body._nextCategory = 0x0001;
|
|
Common._nextId = 0;
|
|
|
|
// reset random seed
|
|
Common._seed = 0;
|
|
|
|
// reset mouse offset and scale (only required for Demo.views)
|
|
if (demo.mouseConstraint) {
|
|
Mouse.setScale(demo.mouseConstraint.mouse, { x: 1, y: 1 });
|
|
Mouse.setOffset(demo.mouseConstraint.mouse, { x: 0, y: 0 });
|
|
}
|
|
|
|
demo.engine.enableSleeping = false;
|
|
demo.engine.world.gravity.y = 1;
|
|
demo.engine.world.gravity.x = 0;
|
|
demo.engine.timing.timeScale = 1;
|
|
|
|
var offset = 5;
|
|
World.add(world, [
|
|
Bodies.rectangle(400, -offset, 800.5 + 2 * offset, 50.5, { isStatic: true }),
|
|
Bodies.rectangle(400, 600 + offset, 800.5 + 2 * offset, 50.5, { isStatic: true }),
|
|
Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, { isStatic: true }),
|
|
Bodies.rectangle(-offset, 300, 50.5, 600.5 + 2 * offset, { isStatic: true })
|
|
]);
|
|
|
|
if (demo.mouseConstraint) {
|
|
World.add(world, demo.mouseConstraint);
|
|
}
|
|
|
|
if (demo.engine.render) {
|
|
var renderOptions = demo.engine.render.options;
|
|
renderOptions.wireframes = true;
|
|
renderOptions.hasBounds = false;
|
|
renderOptions.showDebug = false;
|
|
renderOptions.showBroadphase = false;
|
|
renderOptions.showBounds = false;
|
|
renderOptions.showVelocity = false;
|
|
renderOptions.showCollisions = false;
|
|
renderOptions.showAxes = false;
|
|
renderOptions.showPositions = false;
|
|
renderOptions.showAngleIndicator = true;
|
|
renderOptions.showIds = false;
|
|
renderOptions.showShadows = false;
|
|
renderOptions.showVertexNumbers = false;
|
|
renderOptions.showConvexHulls = false;
|
|
renderOptions.showInternalEdges = false;
|
|
renderOptions.showSeparations = false;
|
|
renderOptions.background = '#fff';
|
|
|
|
if (_isMobile) {
|
|
renderOptions.showDebug = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
})();
|