0
0
Fork 0
mirror of https://github.com/liabru/matter-js.git synced 2024-11-27 09:50:52 -05:00

Merge branch 'master' into performance-2

* master:
  updated benchmark tests
  added repeats and updates options to test tools
  added Example.stress4
  added arrow key navigation of examples in development demo
  reduce canvas hit testing in demo when using matter-tools
This commit is contained in:
liabru 2023-08-13 14:11:28 +01:00
commit e4526a5138
8 changed files with 213 additions and 44 deletions

View file

@ -41,8 +41,10 @@ var demo = function(examples, isDev) {
document.title = 'Matter.js Demo' + (isDev ? ' ・ Dev' : ''); document.title = 'Matter.js Demo' + (isDev ? ' ・ Dev' : '');
if (isDev) { if (isDev) {
var buttonSource = demo.dom.buttonSource; // add compare button
var buttonCompare = buttonSource.cloneNode(true); var buttonSource = demo.dom.buttonSource,
buttonCompare = buttonSource.cloneNode(true);
buttonCompare.textContent = '⎄'; buttonCompare.textContent = '⎄';
buttonCompare.title = 'Compare'; buttonCompare.title = 'Compare';
buttonCompare.href = '?compare'; buttonCompare.href = '?compare';
@ -52,11 +54,29 @@ var demo = function(examples, isDev) {
window.location = '?compare#' + demo.example.id; window.location = '?compare#' + demo.example.id;
event.preventDefault(); event.preventDefault();
}); });
buttonSource.parentNode.insertBefore(buttonCompare, buttonSource.nextSibling); buttonSource.parentNode.insertBefore(buttonCompare, buttonSource.nextSibling);
// always show debug info
Matter.before('Render.create', function(renderOptions) { Matter.before('Render.create', function(renderOptions) {
renderOptions.options.showDebug = true; renderOptions.options.showDebug = true;
}); });
// arrow key navigation of examples
document.addEventListener('keyup', function(event) {
var isBackKey = event.key === 'ArrowLeft' || event.key === 'ArrowUp',
isForwardKey = event.key === 'ArrowRight' || event.key === 'ArrowDown';
if (isBackKey || isForwardKey) {
var direction = isBackKey ? -1 : 1,
currentExampleIndex = demo.examples.findIndex(function(example) {
return example.id === demo.example.id;
}),
nextExample = demo.examples[(demo.examples.length + currentExampleIndex + direction) % demo.examples.length];
MatterTools.Demo.setExample(demo, nextExample);
}
});
} }
MatterTools.Demo.start(demo); MatterTools.Demo.start(demo);

View file

@ -47,6 +47,14 @@
opacity: 0.5; opacity: 0.5;
background: transparent !important; background: transparent !important;
} }
@media only screen and (min-width: 1300px) {
/* reduce hit testing when using matter-tools */
.matter-demo canvas {
position: relative;
z-index: 20;
}
}
</style> </style>
</head> </head>
<body><% for (var chunk in htmlWebpackPlugin.files.js) { %> <body><% for (var chunk in htmlWebpackPlugin.files.js) { %>

View file

@ -40,6 +40,7 @@ module.exports = {
stress: require('./stress.js'), stress: require('./stress.js'),
stress2: require('./stress2.js'), stress2: require('./stress2.js'),
stress3: require('./stress3.js'), stress3: require('./stress3.js'),
stress4: require('./stress4.js'),
svg: require('./svg.js'), svg: require('./svg.js'),
terrain: require('./terrain.js'), terrain: require('./terrain.js'),
timescale: require('./timescale.js'), timescale: require('./timescale.js'),

121
examples/stress4.js Normal file
View file

@ -0,0 +1,121 @@
var Example = Example || {};
Example.stress4 = function() {
var Engine = Matter.Engine,
Events = Matter.Events,
Render = Matter.Render,
Runner = Matter.Runner,
Composites = Matter.Composites,
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint,
Mouse = Matter.Mouse,
Composite = Matter.Composite,
Bodies = Matter.Bodies;
// create engine
var engine = Engine.create({
positionIterations: 25,
velocityIterations: 35
});
var world = engine.world;
// create renderer
var render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
showStats: true,
showPerformance: true
}
});
Render.run(render);
// create runner
var runner = Runner.create({
isFixed: true
});
Runner.run(runner, engine);
// add bodies
var stack = function(scale, columns, rows) {
return Composites.stack(40, 40, columns, rows, 0, 0, function(x, y) {
var sides = Math.round(Common.random(1, 8));
switch (Math.round(Common.random(0, 1))) {
case 0:
if (Common.random() < 0.8) {
return Bodies.rectangle(x, y, Common.random(25, 50) * scale, Common.random(25, 50) * scale);
} else {
return Bodies.rectangle(x, y, Common.random(80, 120) * scale, Common.random(25, 30) * scale);
}
case 1:
return Bodies.polygon(x, y, sides, Common.random(25, 50) * scale);
}
});
};
Composite.add(world, [
stack(0.2, 61, 15),
stack(0.3, 31, 12),
Bodies.rectangle(400, 0, 800, 50, { isStatic: true, render: { visible: false } }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true, render: { visible: false } }),
Bodies.rectangle(800, 300, 50, 600, { isStatic: true, render: { visible: false } }),
Bodies.rectangle(0, 300, 50, 600, { isStatic: true, render: { visible: false } })
]);
// scene animation
engine.timing.timeScale = 0.9;
engine.gravity.scale = 0.0007;
Events.on(engine, 'beforeUpdate', function() {
engine.gravity.x = Math.cos(engine.timing.timestamp * 0.0005);
engine.gravity.y = Math.sin(engine.timing.timestamp * 0.0005);
});
// add mouse control
var mouse = Mouse.create(render.canvas),
mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false
}
}
});
Composite.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
// fit the render viewport to the scene
Render.lookAt(render, {
min: { x: 0, y: 0 },
max: { x: 800, y: 600 }
});
// context for MatterTools.Demo
return {
engine: engine,
runner: runner,
render: render,
canvas: render.canvas,
stop: function() {
Matter.Render.stop(render);
Matter.Runner.stop(runner);
}
};
};
Example.stress4.title = 'Stress 4';
Example.stress4.for = '>=0.14.2';
if (typeof module !== 'undefined') {
module.exports = Example.stress4;
}

View file

@ -50,16 +50,16 @@
"lint": "eslint 'src/**/*.js' 'demo/src/**/*.js' 'examples/*.js' 'webpack.*.js'", "lint": "eslint 'src/**/*.js' 'demo/src/**/*.js' 'examples/*.js' 'webpack.*.js'",
"doc": "yuidoc --config yuidoc.json --project-version $npm_package_version", "doc": "yuidoc --config yuidoc.json --project-version $npm_package_version",
"doc-watch": "nodemon --delay 3 --watch 'matter-doc-theme' --watch src -e 'js,html,css,handlebars' --exec 'npm run doc'", "doc-watch": "nodemon --delay 3 --watch 'matter-doc-theme' --watch src -e 'js,html,css,handlebars' --exec 'npm run doc'",
"benchmark": "EXAMPLES=stress3 npm run test-node", "benchmark": "npm run test-node -- --examples=stress3,stress4 --updates=300 --repeats=3",
"test": "npm run test-node", "test": "npm run test-node",
"test-node": "npm run build-dev && node --expose-gc node_modules/.bin/jest --force-exit --no-cache --runInBand ./test/Examples.spec.js", "test-node": "npm run build-dev && node --expose-gc node_modules/.bin/jest --force-exit --no-cache --runInBand ./test/Examples.spec.js",
"test-browser": "node --expose-gc node_modules/.bin/jest --force-exit --no-cache --runInBand ./test/Browser.spec.js", "test-browser": "node --expose-gc node_modules/.bin/jest --force-exit --no-cache --runInBand ./test/Browser.spec.js",
"test-all": "npm run test-node && npm run test-browser", "test-all": "npm run test-node && npm run test-browser",
"test-save": "SAVE=true npm run test-node", "test-save": "npm run test-node -- --save=true",
"test-watch": "npm run test-node -- --watch", "test-watch": "npm run test-node -- --watch",
"changelog": "conventional-changelog -i CHANGELOG.md -s -r", "changelog": "conventional-changelog -i CHANGELOG.md -s -r",
"release": "npm version --no-git-tag-version", "release": "npm version --no-git-tag-version",
"preversion": "git checkout master && npm run lint && SAVE=true npm run test-all", "preversion": "git checkout master && npm run lint && npm run test-all -- --save=true",
"version": "git checkout -b release/$npm_package_version && npm run build" "version": "git checkout -b release/$npm_package_version && npm run build"
}, },
"files": [ "files": [

View file

@ -13,50 +13,57 @@ const runExample = options => {
frameCallbacks frameCallbacks
} = prepareEnvironment(options); } = prepareEnvironment(options);
const Examples = requireUncached('../examples/index');
const example = Examples[options.name]();
const engine = example.engine;
const runner = example.runner;
const render = example.render;
let totalMemory = 0; let totalMemory = 0;
let totalDuration = 0; let totalDuration = 0;
let overlapTotal = 0; let overlapTotal = 0;
let overlapCount = 0; let overlapCount = 0;
let i; let i;
let j;
if (global.gc) {
global.gc();
}
try { try {
for (i = 0; i < options.updates; i += 1) { let runner;
const time = i * runner.delta; let engine;
const callbackCount = frameCallbacks.length; let render;
for (let p = 0; p < callbackCount; p += 1) { for (i = 0; i < options.repeats; i += 1) {
totalMemory += process.memoryUsage().heapUsed; if (global.gc) {
const callback = frameCallbacks.shift(); global.gc();
const startTime = process.hrtime();
callback(time);
const duration = process.hrtime(startTime);
totalMemory += process.memoryUsage().heapUsed;
totalDuration += duration[0] * 1e9 + duration[1];
} }
const pairsList = engine.pairs.list; const Examples = requireUncached('../examples/index');
const pairsListLength = engine.pairs.list.length; const example = Examples[options.name]();
for (let p = 0; p < pairsListLength; p += 1) { runner = example.runner;
const pair = pairsList[p]; engine = example.engine;
const separation = pair.separation - pair.slop; render = example.render;
if (pair.isActive && !pair.isSensor) { for (j = 0; j < options.updates; j += 1) {
overlapTotal += separation > 0 ? separation : 0; const time = j * runner.delta;
overlapCount += 1; const callbackCount = frameCallbacks.length;
for (let p = 0; p < callbackCount; p += 1) {
totalMemory += process.memoryUsage().heapUsed;
const callback = frameCallbacks.shift();
const startTime = process.hrtime();
callback(time);
const duration = process.hrtime(startTime);
totalMemory += process.memoryUsage().heapUsed;
totalDuration += duration[0] * 1e9 + duration[1];
}
const pairsList = engine.pairs.list;
const pairsListLength = engine.pairs.list.length;
for (let p = 0; p < pairsListLength; p += 1) {
const pair = pairsList[p];
const separation = pair.separation - pair.slop;
if (pair.isActive && !pair.isSensor) {
overlapTotal += separation > 0 ? separation : 0;
overlapCount += 1;
}
} }
} }
} }
@ -75,7 +82,7 @@ const runExample = options => {
}; };
} catch (err) { } catch (err) {
err.message = `On example '${options.name}' update ${i}:\n\n ${err.message}`; err.message = `On example '${options.name}' update ${j}:\n\n ${err.message}`;
throw err; throw err;
} }
}; };

View file

@ -10,7 +10,8 @@ const {
comparisonReport, comparisonReport,
logReport, logReport,
toMatchExtrinsics, toMatchExtrinsics,
toMatchIntrinsics toMatchIntrinsics,
getArg
} = require('./TestTools'); } = require('./TestTools');
const Example = requireUncached('../examples/index'); const Example = requireUncached('../examples/index');
@ -18,9 +19,11 @@ const MatterBuild = requireUncached('../build/matter');
const { versionSatisfies } = requireUncached('../src/core/Plugin'); const { versionSatisfies } = requireUncached('../src/core/Plugin');
const Worker = require('jest-worker').default; const Worker = require('jest-worker').default;
const specificExamples = process.env.EXAMPLES ? process.env.EXAMPLES.split(' ') : null; const testComparison = getArg('compare', null) === 'true';
const testComparison = process.env.COMPARE === 'true'; const saveComparison = getArg('save', null) === 'true';
const saveComparison = process.env.SAVE === 'true'; const specificExamples = getArg('examples', null, (val) => val.split(','));
const repeats = getArg('repeats', 1, parseFloat);
const updates = getArg('updates', 150, parseFloat);
const excludeExamples = ['svg', 'terrain']; const excludeExamples = ['svg', 'terrain'];
const excludeJitter = ['stack', 'circleStack', 'restitution', 'staticFriction', 'friction', 'newtonsCradle', 'catapult']; const excludeJitter = ['stack', 'circleStack', 'restitution', 'staticFriction', 'friction', 'newtonsCradle', 'catapult'];
@ -42,6 +45,7 @@ const captureExamples = async useDev => {
name, name,
useDev, useDev,
updates: 2, updates: 2,
repeats: 1,
stableSort: true, stableSort: true,
jitter: excludeJitter.includes(name) ? 0 : 1e-10 jitter: excludeJitter.includes(name) ? 0 : 1e-10
}))); })));
@ -50,6 +54,7 @@ const captureExamples = async useDev => {
name, name,
useDev, useDev,
updates: 2, updates: 2,
repeats: 1,
stableSort: true, stableSort: true,
jitter: excludeJitter.includes(name) ? 0 : 1e-10 jitter: excludeJitter.includes(name) ? 0 : 1e-10
}))); })));
@ -58,6 +63,7 @@ const captureExamples = async useDev => {
name, name,
useDev, useDev,
updates: 2, updates: 2,
repeats: 1,
stableSort: false, stableSort: false,
jitter: excludeJitter.includes(name) ? 0 : 1e-10 jitter: excludeJitter.includes(name) ? 0 : 1e-10
}))); })));
@ -72,7 +78,8 @@ const captureExamples = async useDev => {
const completeRuns = await Promise.all(examples.map(name => singleThreadWorker.runExample({ const completeRuns = await Promise.all(examples.map(name => singleThreadWorker.runExample({
name, name,
useDev, useDev,
updates: 150, updates: updates,
repeats: repeats,
stableSort: false, stableSort: false,
jitter: excludeJitter.includes(name) ? 0 : 1e-10 jitter: excludeJitter.includes(name) ? 0 : 1e-10
}))); })));

View file

@ -254,6 +254,11 @@ const requireUncached = path => {
return module; return module;
}; };
const getArg = (name, defaultValue=null, parser=(v) => v) => {
const value = process.argv.find(arg => arg.startsWith(`--${name}=`));
return value ? parser(value.split('=')[1]) : defaultValue;
};
const toMatchExtrinsics = { const toMatchExtrinsics = {
toMatchExtrinsics(received, value) { toMatchExtrinsics(received, value) {
const similaritys = extrinsicSimilarity(received, value, 'extrinsic'); const similaritys = extrinsicSimilarity(received, value, 'extrinsic');
@ -286,6 +291,6 @@ const toMatchIntrinsics = {
}; };
module.exports = { module.exports = {
requireUncached, comparisonReport, logReport, requireUncached, comparisonReport, logReport, getArg,
serialize, toMatchExtrinsics, toMatchIntrinsics serialize, toMatchExtrinsics, toMatchIntrinsics
}; };