I have a ball and two straight vertical surfaces in my world.
When I apply a force to the ball I expect it to stay in a straight line, however it appears to bounce off at an angle.
fiddle: https://jsfiddle.net/zvjvvzeL/11/
var Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body,
Vector = Matter.Vector,
Events = Matter.Events;
// create an engine
var engine = Engine.create();
var canvas = document.getElementById('canvas');
engine.world.gravity.y = 0; // gravity not needed in this app
// create a renderer
var render = Render.create({
element: document.body,
canvas: canvas,
engine: engine,
options: {wireframes: true}
});
var ball_0 = Bodies.circle(100, 150, 11, {
density: 0.04,
frictionAir: 0.06,
restitution: 0.8,
friction: 0.3
});
var cushion_left = Bodies.rectangle(34, 160, 100, 208, { isStatic: true });
var cushion_right = Bodies.rectangle(492, 160, 100, 208, { isStatic: true });
// add all of the bodies to the world
World.add(engine.world, [cushion_left, cushion_right, ball_0]);
render.options.height = 300;
canvas.height = 300;
Engine.run(engine);
Render.run(render);
Body.applyForce(ball_0, { x: 0, y: 0 }, { x: 0.5, y: 0 });
Not too familiar with MatterJS, but it seems like the ball has angular rotation applied by default. I think this only affects a closed system like the one you've built.
Maybe you'll want it on in the long run, but for now you can set intertia : Infinity
var ball_0 = Bodies.circle(100, 150, 11, {
density: 0.04,
frictionAir: 0.06,
restitution: 0.8,
friction: 0.3,
inertia : Infinity
});
But now you also have to apply slightly more force to get the ball to touch the wall. I just turned it up to .6
Body.applyForce(ball_0, { x: 0, y: 0 }, { x: .6, y: 0 });
Related
I am new to Lottie and am wondering how to play 2 animations side by side at the same time in the same canvas element on the Web.
I have followed this example[1] and then the advice given here[2] with regards to transforming the canvas on every frame to position either animation respectively.
What I would like to achieve is this: 2 red balls bouncing side by side on the same canvas. One playing at x = 0 and one playing at x = 100 on the same canvas.
Here is my approach in a CodePen[3]. I extracted the JS for visibility.
const testjson = {...animation...};
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// Drawing sth on the context to see whether sharing works
ctx.fillStyle = "green";
ctx.fillRect(0, 0, 40, 40);
function renderAnimation(canvasContext, translation) {
const animData = {
renderer: "canvas",
loop: true,
rendererSettings: {
context: canvasContext,
clearCanvas: true,
},
animationData: testjson,
};
const anim = bodymovin.loadAnimation(animData);
// Transform the canvas for the respective animation on enter-frame
anim.addEventListener("enterFrame", () => {
ctx.translate(translation.x, translation.y);
});
// If efective, causes onion-effect
// anim.setSubframe(false);
}
renderAnimation(ctx, { x: 0, y: 0 });
renderAnimation(ctx, { x: 100, y: 0 });
Alas, the way I implemented it does not seem to work.
Does anybody know what I am missing?
Thank you!
[1]: https://codepen.io/RenanSgorlom/pen/orgxyJ
[2]: https://github.com/airbnb/lottie-web/issues/1671
[3]: https://codepen.io/user1207504/pen/MWVYvxd
You don't need that much code to have some balls bouncing on the same canvas ...
Certainly no need for a library to just do that.
The balls we can draw using arc functions:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc
movement is to increase the position on x or y, in the code is the x += vx
bouncing we just change the direction, you can see it in my code vx *= -1
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
class ball {
constructor(data) {
this.data = data
}
draw() {
this.data.x += this.data.vx
this.data.y += this.data.vy
if (this.data.x > canvas.width || this.data.x < 0) this.data.vx *= -1
if (this.data.y > canvas.height || this.data.y < 0) this.data.vy *= -1
ctx.beginPath()
ctx.fillStyle = this.data.color
ctx.arc(this.data.x,this.data.y, this.data.radius, 0, 2*Math.PI);
ctx.fill()
}
}
const balls = [
new ball({x: 10, y: 10, vx: 0, vy: 1, radius: 8, color: "pink" }),
new ball({x: 90, y: 90, vx: 0, vy: -1, radius: 8, color: "red" }),
new ball({x: 5, y: 50, vx: 1, vy: 1.5, radius: 8, color: "cyan" })
]
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
balls.forEach(b => b.draw())
requestAnimationFrame(animate)
}
animate()
<canvas id="canvas" width=100 height=100></canvas>
I am using Matter.js to build a simple robot kit environment with an ultrasonic sensor.
I have a shape for the ultrasonic sensor field of vision so I can detect whenever there is a collision.
How can I get the distance between the robot rectangle and the nearest point in which the sensor body is colliding with?
Using collision.seperation would not work as it will consider the distance from the other side after the robot is too close to the object.
Thank you
var Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Body = Matter.Body,
Constraint = Matter.Constraint,
Mouse = Matter.Mouse,
MouseConstraint = Matter.MouseConstraint,
Events = Matter.Events,
Common = Matter.Common
Bodies = Matter.Bodies;
var myCanvas = document.getElementById('world');
var engine = Engine.create();
engine.world.gravity.y = 0;
var render = Render.create({
canvas: myCanvas,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false
}
});
var topWall = Bodies.rectangle(400, 50, 720, 20, { isStatic: true });
var wheel1 = Bodies.rectangle(40, 232, 20, 6);
var robotBody = Bodies.rectangle(50, 250, 50, 30 );
var wheel2 = Bodies.rectangle(40, 268, 20, 5);
var sensor2 = Bodies.trapezoid(65, 108, 150, 200, 0.94, {
chamfer: { radius: [50, 0, 0, 50] }});
Body.setAngle(sensor2, 3.14159);
sensor2.isSensor = true;
sensor2.render.opacity = 0.2;
Body.setMass(sensor2, 0);
Body.setInertia(sensor2, 0);
sensor2.area = 0;
var robot = Body.create({parts: [wheel1, robotBody, wheel2, sensor2]});
Body.setMass(robot, 1000);
robot.friction = 0.9;
robot.frictionAir = 0.5;
Body.setPosition(robot, {x: 200, y: 400});
//add obstacle
var obstacle = Bodies.circle(500, 500, 50);
Body.setMass(obstacle, 100000000); //make it very heavy
World.add(engine.world, [topWall, robot, obstacle]);
Engine.run(engine);
Render.run(render);
// add mouse control
var mouse = Mouse.create(render.canvas),
mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false
}
}
});
World.add(engine.world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.min.js"></script>
<canvas id="world"></canvas>
I'am trying to clip the FabricJS rect shape to the polygon shape. The clipping works okay until the polygon shape which need to be clipped is now scaled. After this there is some weird offset that is caused by the polygon clipping.
Can anyone help me how can i fix the function to prevent the polygon offset issue when clip object is scaled.
This is how it looks before scalling. The clipping works fine
Image => https://i.imgur.com/Eop2YJh.png
And then there is the problem when the polygon is scaled.
2: Image => https://i.imgur.com/ICkP8SG.png
Here is the code on fiddle with the clipping function
https://jsfiddle.net/0xpvc9uq/
So if there is anyone who knows whats the point and how can I fix it I would appriciate it.
Thx
var canvas = new fabric.Canvas('c');
var rect1 = new fabric.Rect({
left: 0, top: 0,
width: 900, height: 900,
fill: 'blue',
selectable: false,
clipTo: clipRegion,
scaleX: 1.5,
scaleY: 1.5
});
var clipPoly = new fabric.Polygon([
{ x: 180, y: 10 },
{ x: 300, y: 50 },
{ x: 300, y: 180 },
{ x: 180, y: 220 }
], {
originX: 'left',
originY: 'top',
left: 180,
top: 10,
fill: 'transparent', /* use transparent for no fill */
strokeWidth: 0,
selectable: false,
strokeWidth: 1,
stroke: "red",
scaleX: 1.3,
scaleY: 1.3
});
canvas.add(rect1, clipPoly);
function clipRegion (ctx) {
rect1.setCoords();
const clipObj = clipPoly;
const scaleXTo1 = (1 / rect1.scaleX);
const scaleYTo1 = (1 / rect1.scaleY);
ctx.save();
const ctxLeft = -( rect1.width / 2 ) - clipObj.strokeWidth - rect1.strokeWidth;
const ctxTop = -( rect1.height / 2 ) - clipObj.strokeWidth - rect1.strokeWidth;
ctx.translate( ctxLeft, ctxTop );
ctx.scale(scaleXTo1, scaleYTo1);
ctx.rotate((rect1.angle * -1) * (Math.PI / 180));
ctx.beginPath();
const matrix = clipPoly.calcTransformMatrix();
let points = [];
clipObj.points.forEach( (point) => {
points.push({
x: ((point.x * matrix[0]) + (clipObj.strokeWidth * clipObj.scaleX)) - rect1.oCoords.tl.x,
y: ((point.y * matrix[3]) + (clipObj.strokeWidth * clipObj.scaleY)) - rect1.oCoords.tl.y
});
});
ctx.moveTo(points[0].x, points[0].y);
points.forEach((point) => {
ctx.lineTo(point.x, point.y);
});
ctx.lineTo(points[0].x, points[0].y);
ctx.closePath();
ctx.restore();
}
I discovered that there is also another approach that can be used and that solves all the problem.
The clipRegion function now looks like:
function clipRegion (ctx) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clipPoly.render(ctx);
ctx.restore();
}
Which makes the rendering okay. If still anyone have other way to fix the above problem, I would like to see the answer
I'm trying to animate a three.js block in such a way that it returns to its original position when the animation ends, using tween.js.
Is there a way to achieve this with tween.js only using one tween?
I have got this working as shown below:
var position = {x: -200, y: 150, width: 1, height: 1, depth: 1, rotx: -0.5, roty: 0.7, rotz: 0.9};
var target = {x: 200, y: -100, width: 0.4, height: 3, depth: 8, rotx: 0.3, roty: -0.4, rotz: -0.6};
var position2 = {x: -200, y: 150, width: 1, height: 1, depth: 1, rotx: -0.5, roty: 0.7, rotz: 0.9};
var mesh = new THREE.Mesh(
new THREE.CubeGeometry(190, 45, 30),
new THREE.MeshBasicMaterial({color: 0x444444}),
0
);
mesh.position.set(position.x, position.y, 0);
mesh.rotation.set(position.rotx, position.roty, position.rotz);
scene.add(mesh);
var t1 = new TWEEN.Tween(position).to(target, 2000);
t1.onUpdate(function() {
mesh.position.set(position.x, position.y, 0);
mesh.scale.set(position.width, position.height, position.depth);
mesh.rotation.set(position.rotx, position.roty, position.rotz);
});
t1.easing(TWEEN.Easing.Quadratic.Out);
t1.onComplete(function() {t2.start();});
var t2 = new TWEEN.Tween(target).to(position2, 2000);
t2.onUpdate(function() {
mesh.position.set(target.x, target.y, 0);
mesh.scale.set(target.width, target.height, target.depth);
mesh.rotation.set(target.rotx, target.roty, target.rotz);
});
t2.easing(TWEEN.Easing.Quadratic.In);
t1.start();
And I have the tweens updating in my animation function:
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
mesh.__dirtyPosition = true;
mesh.__dirtyRotation = true;
TWEEN.update();
}
animate();
This is working as I expect it to, but it is clearly very inefficient, and difficult to work around.
Any and all help will be appreciated.
You're overcomplicating things a bit by re-naming the x, y, z properties to width, height, depth or rotx, roty, rotz. This only means you have to manually translate these properties onUpdate when you do scale.x = position.width and rotation.x = position.rotx. I recommend you keep x, y, z, to avoid these repetitive assignments.
// We set our start and target pos using the THREE.js "x, y, z" nomenclature
var startPos = {x: -200, y: 150, z: 0};
var targetPos = {x: 200, y: -100, z: 0};
// Scale also is defined in "x, y, z"
var startScale = {x: 1, y: 1, z: 1};
var targetScale = {x: 0.4, y: 3, z: 8};
// Rotation also has "x, y, z" degrees in Euler angles
var startRot = {x: -0.5, y: 0.7, z: 0.9};
var targetRot = {x: 0.3, y: -0.4, z: -0.6};
// Standard mesh setup
var mesh = new THREE.Mesh(
new THREE.CubeGeometry(190, 45, 30),
new THREE.MeshBasicMaterial({color: 0x444444})
);
mesh.position.copy(startPos);
mesh.rotation.copy(startRot);
scene.add(mesh);
// Create shortcuts for shorter easing names
var QuadOut = TWEEN.Easing.Quadratic.Out;
var QuadIn = TWEEN.Easing.Quadratic.In;
// Create one tween for position
// Notice that you can chain the animation
// back to startPos by doing double ".to().to()""
var t1 = new TWEEN.Tween(mesh.position)
.to(targetPos, 2000, QuadOut)
.to(startPos, 2000, QuadIn);
// Second, we tween the mesh's rotation
var t2 = new TWEEN.Tween(mesh.rotation)
.to(targetRot, 2000, QuadOut)
.to(startRot, 2000, QuadIn);
// Third, we tween the mesh's scale
var t3 = new TWEEN.Tween(mesh.scale)
.to(targetScale, 2000, QuadOut)
.to(startScale, 2000, QuadIn);
t1.start();
t2.start();
t3.start();
And finally, during animate(), you no longer have to change __dirtyPosition or anything, because the tween is updating the mesh's properties directly.
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
renderer.render(scene, camera);
}
animate();
How do you do the isometric cube in canvas 2d? I've followed True Isometric Projection with HTML5 Canvas to get the top of the cube, but how do you do the left and right sides?
Note: I want to use the Kinetic.js Objects with their event handling features intact.
This is what I have right now:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas {
border: 1px solid #9C9898;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.0.0.js"></script>
<script>
window.onload = function() {
var stage = new Kinetic.Stage({
container: "container",
width: 578,
height: 200,
//scale: [1, 0.5],
//scale: [1, 0.86062],
//rotation: -30 * Math.PI /180,
});
var layer = new Kinetic.Layer({
scale: [1,0.5],
});
var foo = false;
layer.beforeDraw(function(){
if (!foo) {
var context = this.getContext();
var sx = 45*Math.PI/180;
// .75 horizontal shear
var sy = 0;
// no vertical shear
// apply custom transform
//context.transform(1, sy, sx, 1, 0, 0);
//context.scale(1, 0.5);
//context.rotate(45 * Math.PI /180);
//var angle = 30;
//context.setTransform(1, Math.tan(30), 0, 1, 0, 0);
}
foo = true;
});
layer.afterDraw(function(){
var context = this.getContext();
//context.scale(1, 2);
//context.rotate(-45 * Math.PI /180);
});
var rect = new Kinetic.Rect({
x: 200,
y: 100,
width: 50,
height: 50,
fill: "blue",
stroke: "black",
strokeWidth: 4,
rotation: -45 * Math.PI /180,
//scale: [1, 0.5],
});
rect.on("mouseover", function() {
//alert(this.getFill());
this.setFill("red");
layer.draw();
});
rect.on("mouseout", function() {
//alert(this.getFill());
this.setFill("blue");
layer.draw();
});
// add the shape to the layer
layer.add(rect);
// add the layer to the stage
stage.add(layer);
};
</script>
demo: http://jsfiddle.net/F5SzS/
Maybe use Polygon instead? Here's an example;
http://jsfiddle.net/Ygnbb/
I made 3 parts separate, but you could do it as one ploygon I guess. Positions and sizes need some tweaking though...