Im trying to apply a force to an object. To get it to move in the angle that my mouseposition is generating relative to the object.
I have the angle
targetAngle = Matter.Vector.angle(myBody.pos, mouse.position);
Now I need to apply a force, to get the body to move along that angle. What do I put in the values below for the applyForce method?
// applyForce(body, position, force)
Body.applyForce(myBody, {
x : ??, y : ??
},{
x:??, y: ?? // how do I derive this force??
});
What do I put in the x and y values here to get the body to move along the angle between the mouse and the body.
Im trying to apply a force to an object. To get it to move in the angle that my mouseposition is generating relative to the object.
I have the angle
targetAngle = Matter.Vector.angle(myBody.pos, mouse.position);
Now I need to apply a force, to get the body to move along that angle. What do I put in the values below for the applyForce method?
// applyForce(body, position, force)
Body.applyForce(myBody, {
x : ??, y : ??
},{
x:??, y: ?? // how do I derive this force??
});
What do I put in the x and y values here to get the body to move along the angle between the mouse and the body.
Share Improve this question asked Mar 6, 2016 at 12:49 KylieKylie 11.7k11 gold badges51 silver badges81 bronze badges3 Answers
Reset to default 10To apply a force to move your object in that direction you need to take the sine and cosine of the angle in radians. You'll want to just pass the object's position as the first vector to not apply torque (rotation).
var targetAngle = Matter.Vector.angle(myBody.pos, mouse.position);
var force = 10;
Body.applyForce(myBody, myBody.position, {
x: cos(targetAngle) * force,
y: sin(targetAngle) * force
});
Also if you need it, the docs on applyForce()
are here.
(I understand this question is old, I'm more or less doing this for anyone who stumbles across it)
You can rely on the Matter.Vector
module and use it to substract, normalize and multiply positions vectors:
var force = 10;
var deltaVector = Matter.Vector.sub(mouse.position, myBody.position);
var normalizedDelta = Matter.Vector.normalise(deltaVector);
var forceVector = Matter.Vector.mult(normalizedDelta, force);
Body.applyForce(myBody, myBody.position, forceVector);
Calculating the amplitude: you have to apply the force in the simulation loop
Focusing on the force amplitude/duration part of it, it is important to know that you should apply the force over time once for every simulation step, which can be done from the beforeUpdate
callback:
- https://brm.io/matter-js/docs/classes/Body.html#method_applyForce
- Keyboard movement is jerky in matter.js
So something like:
const moveForce = 0.01
const keysDown = new Set()
const keyHandlers = {
KeyW: () => {
Matter.Body.applyForce(boxA, {
x: boxA.position.x,
y: boxA.position.y
}, { x: 0, y: -moveForce } )
},
KeyS: () => {
Matter.Body.applyForce(boxA, {
x: boxA.position.x,
y: boxA.position.y
}, { x: 0, y: moveForce } )
},
}
document.addEventListener("keydown", event => {
keysDown.add(event.code)
});
document.addEventListener("keyup", event => {
keysDown.delete(event.code)
});
Matter.Events.on(engine, 'beforeUpdate', event => {
;[...keysDown].forEach(k => {
keyHandlers[k]?.();
});
});
Here's a full minimal runnable example that modifies the Matter.js hello world to allow to you to move one of the boxes around with ASDW:
asdw.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ASDW</title>
<script src="node_modules/matter-js/build/matter.min.js"></script>
</head>
<body>
<script>
// module aliases
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Bodies = Matter.Bodies,
Composite = Matter.Composite;
// 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 });
// add all of the bodies to the world
Composite.add(engine.world, [boxA, boxB, ground]);
// Move boxA with ASDW
const moveForce = 0.01
const keysDown = new Set()
const keyHandlers = {
KeyW: () => {
Matter.Body.applyForce(boxA, {
x: boxA.position.x,
y: boxA.position.y
}, { x: 0, y: -moveForce } )
},
KeyS: () => {
Matter.Body.applyForce(boxA, {
x: boxA.position.x,
y: boxA.position.y
}, { x: 0, y: moveForce } )
},
KeyA: () => {
Matter.Body.applyForce(boxA, {
x: boxA.position.x,
y: boxA.position.y
}, { x: -moveForce, y: 0 } )
},
KeyD: () => {
Matter.Body.applyForce(boxA, {
x: boxA.position.x,
y: boxA.position.y
}, { x: moveForce, y: 0 } )
},
}
document.addEventListener("keydown", event => {
keysDown.add(event.code)
});
document.addEventListener("keyup", event => {
keysDown.delete(event.code)
});
Matter.Events.on(engine, 'beforeUpdate', event => {
;[...keysDown].forEach(k => {
keyHandlers[k]?.();
});
});
// run the renderer
Render.run(render);
// create runner
var runner = Runner.create();
// run the engine
Runner.run(runner, engine);
</script>
</body>
</html>
Constraints
Another way of doing it is using constraints, which implicitly add forces correctly to the loop.
There is in particular a mouse constraint helper for the mouse use case: How to allow only a single body to move using Matter-js Mouse
The mouse constraint is super easy to use, all you need is this code adapted from https://github.com/liabru/matter-js/blob/0.19.0/examples/constraints.js#L145
const mouse = Matter.Mouse.create(render.canvas)
const mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse,
constraint: {
// allow bodies on mouse to rotate
angularStiffness: 0,
render: {
visible: false
}
}
})
Composite.add(engine.world, mouseConstraint)
render.mouse = mouse;
This allows you to drag any block by clicking on them and pulling them around.
Minimal runnable example based on the Matter.js hello world:
mouse.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>mouse</title>
<script src="node_modules/matter-js/build/matter.js"></script>
</head>
<body>
<script>
// module aliases
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Bodies = Matter.Bodies,
Composite = Matter.Composite;
// 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 });
// add all of the bodies to the world
Composite.add(engine.world, [boxA, boxB, ground]);
// Add mouse control
const mouse = Matter.Mouse.create(render.canvas)
const mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse,
constraint: {
// allow bodies on mouse to rotate
angularStiffness: 0,
render: {
visible: false
}
}
})
Composite.add(engine.world, mouseConstraint)
render.mouse = mouse;
// run the renderer
Render.run(render);
// create runner
var runner = Runner.create();
// run the engine
Runner.run(runner, engine);
</script>
</body>
</html>