I created a simple animation in matter.js physics engine, with a few object colliding and falling on the ground.
I noticed that the outcome is always a little different. You can see here: https://jsfiddle.net/95urgeqf/1/
var Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body;
// create an engine
var engine = Engine.create();
// create a renderer
var render = Render.create({
element: document.body,
engine: engine
});
// create two boxes and a ground
var boxA = Bodies.rectangle(400, 200, 80, 80);
var boxB = Bodies.rectangle(450, 50, 80, 80);
var ground = Bodies.rectangle(400, 610, 810, 60, { isStatic: true });
var circle1 = Matter.Bodies.circle(400, 200, 20, { isStatic: true }, 300);
var circle2 = Matter.Bodies.circle(600, 300, 20, { isStatic: true }, 300);
var circle3 = Matter.Bodies.circle(200, 400, 20, { isStatic: true }, 300);
Body.setVelocity(boxA, { x: 0, y: -10});
// add all of the bodies to the world
World.add(engine.world, [boxA, boxB, ground, circle1, circle2, circle3]);
// run the engine
Engine.run(engine);
// run the renderer
Render.run(render);
Most noticeable is the square on the left when it touches the ground, it always falls a little different.
My aim is to create an animation that always behaves the same, so the left square should fall on the ground the same, identical, way each time, as long as it has the same params.
You got to use the same seed.
Matter.Common._seed = 12345678;
Anyway your animation can be different on different platforms/browsers due to difference in floating point operations.
If you want exactly the same behavior you need to use fixed point math.
UPD:
Also you need to use seeded random number generator(for example) across all application.
Related
I am creating the ground of a game using a Perlin noise function. This gives me an array of vertices. I then add a vertex at the front that is {x:0 y: WORLD_HEIGHT} and another at the end of the array that is {x: WORLD_WIDTH y: WORLD_HEIGHT}. I am hoping that will give me a flat base with a random top.
How then do I add this into the matter.js world?
I am trying to create the ground using;
var terrain = Bodies.fromVertices(???, ???, vertexSets, {
isStatic: true
}, true);
but I don't know what to use for the ??? co-ordinates. I think they are supposed to represent the center of the object. However, I don't know what that is because it is noise. What I would like to do is specify the x & y of the first perlin noise vertex.
I am not even sure that given these vertices matter.js is creating a single body or multiple.
Is this the right way to approach it or there another way to do this? I am really struggling with the docs and the examples.
I use Matter.Body.setPosition(body, position) to override the center of mass and put the ground where I want it based on its bounds property.
const engine = Matter.Engine.create();
const render = Matter.Render.create({
element: document.body,
engine: engine,
});
const w = 300;
const h = 300;
const vertices = [
...[...Array(16)].map((_, i) => ({
x: i * 20,
y: ~~(Math.random() * 40),
})),
{x: w, y: 100},
{x: 0, y: 100},
];
const ground = Matter.Bodies.fromVertices(
w - 10, h - 10, // offset by 10 pixels for illustration
vertices,
{isStatic: true},
/* flagInternal =*/ true,
);
Matter.Body.setPosition(ground, {
x: w - ground.bounds.min.x,
y: h - ground.bounds.max.y + 110,
});
const {min: {x}, max: {y}} = ground.bounds;
console.log(x, y); // 10 120
Matter.Composite.add(engine.world, [ground]);
Matter.Render.run(render);
Matter.Runner.run(engine);
<script src="https://cdn.jsdelivr.net/npm/poly-decomp#0.3.0/build/decomp.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>
Without setPosition, you can see things jump around if you run this snippet a few times (just to reproduce OP's error with a concrete example):
const engine = Matter.Engine.create();
const render = Matter.Render.create({
element: document.body,
engine: engine,
});
const vertices = [
...[...Array(16)].map((_, i) => ({
x: i * 20,
y: ~~(Math.random() * 40),
})),
{x: 300, y: 100},
{x: 0, y: 100},
];
const ground = Matter.Bodies.fromVertices(
200, 100, vertices,
{isStatic: true},
/* flagInternal =*/ true,
);
Matter.Composite.add(engine.world, [ground]);
Matter.Render.run(render);
Matter.Runner.run(engine);
<script src="https://cdn.jsdelivr.net/npm/poly-decomp#0.3.0/build/decomp.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>
I'm not using Perlin noise and there are some internal vertices that aren't properly detected in the above examples, but the result should be the same either way.
should be integers, all width and height of the noise texture. values at those x, y integer places can be floats... no problem.
and same width and height should go to terrain and values at that places will be the height of the terrain.
I am pretty new to Matter.js so forgive me if the answer to this is obvious.
I am trying to rotate a body on top of another (static) body and have it roll along that surface.
I need something similar to the car demo but I need there to be zero acceleration to the roll. i.e. every iteration of the loop I should be able to set a rotation amount and have the body rotate that much.
I also need this to able to work with non-eliptical bodies.
I have some code that rotates the body as I would like but I am struggling to make the body roll along the surface based on its rotation.
Any help would be much appreciated. Please see my current code below.
// module aliases
var Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body;
// create an engine
var engine = Engine.create();
// create a renderer
var render = Render.create({
element: document.body,
engine: engine
});
var boxA = Bodies.rectangle(400, 200, 80, 80);
var ground = Bodies.rectangle(400, 610, 810, 60, { isStatic: true });
// add all of the bodies to the world
World.add(engine.world, [boxA, ground]);
// run the renderer
Render.run(render);
engine.world.gravity = {x: 0, y:0, scale: 0}; //disable gravity
window.setInterval(function () {
Body.rotate(boxA, 0.01);
Body.translate(boxA, { x: 0, y: 10 });
Engine.update(engine, 1000 / 60);
}, 1000 / 60)
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script>
I have a simple rectangle that forms the clipping area for all shapes added to the canvas, which is working great:
var area = new paper.Rectangle(
100, 100, 300, 120
);
var path = new paper.Path.Rectangle(area);
group.addChild(path);
group.clipped = true;
What I'm trying to achieve is instead of hiding the paths that fall outside of this area, they are shown with a slight opacity, something like:
Thanks in advance for any help and suggestions.
This is not a simple way as clipped, you might do it by using method intersect.
Please try this code.
// SET INITIAL
var area = new paper.Path.Rectangle(100, 100, 300, 220);
area.fillColor = 'yellow'
area.opacity = 0.2
var circle1 = new paper.Path.Circle({
center:[150, 150],
radius: 100,
fillColor: 'red'
})
// OPACITY CLIPPING
var circle2 = circle1.intersect(area)
circle1.opacity = 0.2
I'm learning PhysicsJS, and I tried using union like so:
// Window bounds
var rect1 = Physics.aabb(0, 100, 300, 200);
var rect2 = Physics.aabb(100, 0, 200, 300);
var viewportBounds = Physics.aabb.union(rect1, rect2);
// Constrain bodies to these bounds
world.add(Physics.behavior('edge-collision-detection', {
aabb: viewportBounds,
restitution: 0.99,
cof: 0.99
}));
but the ball just falls through the bottom.
Physics(function(world){
var viewWidth = 300;
var viewHeight = 300;
var renderer = Physics.renderer('canvas', {
el: 'viewport',
width: viewWidth,
height: viewHeight,
meta: false
});
// add the renderer
world.add(renderer);
// render on each step
world.subscribe('step', function(){
world.render();
});
// Window bounds
var rect1 = Physics.aabb(0, 100, 300, 200);
var rect2 = Physics.aabb(100, 0, 200, 300);
var viewportBounds = Physics.aabb.union(rect1, rect2);
// Constrain bodies to these bounds
world.add(Physics.behavior('edge-collision-detection', {
aabb: viewportBounds,
restitution: 0.99,
cof: 0.99
}));
// Add the ball
world.add(
Physics.body('circle', {
x: 0, // x-coordinate
y: 0, // y-coordinate
vx: 0.2, // x-velocity
vy: 0.01, // y-velocity
radius: 2.0
})
);
// ensure objects bounce when edge collision is detected
world.add( Physics.behavior('body-impulse-response') );
// add some gravity
world.add( Physics.behavior('constant-acceleration') );
// subscribe to ticker to advance the simulation
Physics.util.ticker.subscribe(function( time, dt ){
world.step( time );
});
// start the ticker
Physics.util.ticker.start();
});
body {
/*background: #121212;*/
}
.pjs-meta {
display: none;
}
#viewport {
border: 1px solid #666;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src='http://wellcaffeinated.net/PhysicsJS/assets/scripts/vendor/physicsjs-0.5.0/physicsjs-full-0.5.0.min.js'></script>
<canvas id="viewport" width="300" height="300"></canvas>
I can't find any code on GitHub or anywhere using it. Can someone lend some guidance, please?
I can't find any code on GitHub or anywhere using it. Can someone lend some guidance, please?
You might try reading the unit tests in the .spec, on Github.
Sample test, which should look very readable even if barely know Javascript:
it("should initialize provided a width/height and point", function() {
var aabb = Physics.aabb( 4, 5, { x: 20, y: 9 } );
matches( aabb, { x: 20, y: 9, hw: 2, hh: 2.5 });
});
spec.js looks to be the test code. Test actually doubles as documentation, and libraries like spec serve to make test code read like documentation. Additionally, test code is, of course, a collection of examples of how to use the code. Enjoy.
Try reading other test code.
Figured it out. I was working with a super old version (physicsjs-0.5.0). I linked to the latest version (physicsjs-0.7.0), which has much more functionality (4,088 new lines of code between those two versions). I had to refactor my code a bit to match the updated spec, but it's all good!
If a lot of my drawings are going to be within a particular area of my larger canvas (in this case, in the center), is there a way to just say that you're working within that particular 'sub-canvas' instead of having to add/subtract the margins every time you want to draw? It just makes my code look a lot more complicated every time I'm specifying coordinates.
You can change the coordinates' origin using translate().
First, save the original origin using save(). Then, find the origin that suits the centre of your screen's drawing area and call translate(x, y). Do your drawing, and then use restore() to get your previous origin back.
jsFiddle.
Kinetic.js, a popular library for Canvas allows you to create a Group layer. You can specify the x, y coordinates, height and width of this Group. You can also add shapes and draw other things within this group.
Here's and example:
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var shapesLayer = new Kinetic.Layer();
/*
* create a group which will be used to combine
* multiple simple shapes. Transforming the group will
* transform all of the simple shapes together as
* one unit
*/
var group = new Kinetic.Group({
x: 220,
y: 40,
rotationDeg: 20
});
var colors = ['red', 'orange', 'yellow'];
for(var n = 0; n < 3; n++) {
// anonymous function to induce scope
(function() {
var i = n;
var box = new Kinetic.Rect({
x: i * 30,
y: i * 18,
width: 100,
height: 50,
name: colors[i],
fill: colors[i],
stroke: 'black',
strokeWidth: 4
});
group.add(box);
})();
}
shapesLayer.add(group);
stage.add(shapesLayer);
Here's a tutorial on how to add Groups
You can use drawimage to draw an offscreen canvas to a certain part of another canvas.
Create a new canvas object and draw all your stuff to that. In the end draw that canvas to your onscreen canvas with drawimage at some coordinates.