Matter.js如何计算applyForce参数让盒子准确落到目标静态盒子上
Matter.js 计算
applyForce参数实现盒子精确抛接的方案 
要实现动态盒子a精确落到静态盒子b的上方,不需要手动调试力的参数,通过物理运动公式计算即可适配任意位置场景,具体实现步骤如下:
核心计算逻辑
我们通过模拟斜抛运动来实现效果,已知Matter.js坐标系y轴向下为正,重力默认向下作用。
1. 确定目标落点坐标
首先计算出a需要落到的最终位置,确保刚好落在b的顶部:
// 以b的中心x作为落点x,保证水平居中 const targetX = b.position.x; // 计算两个盒子的高度 const bHeight = b.bounds.max.y - b.bounds.min.y; const aHeight = a.bounds.max.y - a.bounds.min.y; // 落点y = b的顶部位置 - a的一半高度 - 少量缓冲,避免碰撞误差 const targetY = b.position.y - bHeight/2 - aHeight/2 - 2;
2. 自定义飞行时长
设置一个抛射总时长t(单位:秒,推荐取值1~2,值越大抛射轨迹越平缓,速度越慢),例如我们取t=1.2。
3. 计算所需初速度
- 水平方向没有空气阻力,做匀速运动,初速度等于水平位移除以飞行时长
- 竖直方向受重力影响,通过位移公式变形计算初速度
const deltaX = targetX - a.position.x; const deltaY = targetY - a.position.y; // Matter.js默认重力加速度计算 const g = world.gravity.y * 9.8; // 计算x、y方向初速度 const vx = deltaX / t; const vy = (deltaY - 0.5 * g * t * t) / t;
如果施力时a已经有初始速度,减去对应方向的初始速度即可:
const vx = deltaX / t - a.velocity.x; const vy = (deltaY - 0.5 * g * t * t) / t - a.velocity.y;
4. 转换为applyForce的力参数
基于牛顿第二定律F=ma,加速度等于速度变化除以力的作用时长,单次调用applyForce的作用时长默认取一帧的时长1/60秒:
const deltaT = 1/60; const forceX = a.mass * vx / deltaT; const forceY = a.mass * vy / deltaT; // 施力 Body.applyForce(a, a.position, {x: forceX, y: forceY});
简化方案
如果你不需要严格使用applyForce,直接调用Body.setVelocity(a, {x: vx, y: vy})可以达到完全一样的效果,还不需要做力的转换,实现更简单。
完整修改后的代码
var Engine = Matter.Engine, Render = Matter.Render, Bodies = Matter.Bodies, Body = Matter.Body, Composite = Matter.Composite, Runner = Matter.Runner; var canvas = document.createElement('canvas'), context = canvas.getContext('2d'); var bodies = []; canvas.width = 500; canvas.height = 200; var count = 0; document.body.appendChild(canvas); var engine = Engine.create(); var render = Render.create({ canvas: canvas, engine: engine, options: { width: canvas.width, height: canvas.height, showAngleIndicator: true, showCollisions: true, showVelocity: true } }) var world = engine.world Render.run(render) var runner = Runner.create(); Runner.run(runner, engine) Composite.add(world, Bodies.rectangle(250, 180, 500, 20, { isStatic: true })); // random position var b = Bodies.rectangle(200, 80, 50, 25, { isStatic: true }); Composite.add(world, b); var a = Bodies.rectangle(50, 50, 30, 30); Composite.add(world, a); setTimeout(function() { // 计算目标落点 const targetX = b.position.x; const bHeight = b.bounds.max.y - b.bounds.min.y; const aHeight = a.bounds.max.y - a.bounds.min.y; const targetY = b.position.y - bHeight/2 - aHeight/2 - 2; // 自定义飞行时长 const t = 1.2; const deltaX = targetX - a.position.x; const deltaY = targetY - a.position.y; const g = world.gravity.y * 9.8; // 计算初速度 const vx = deltaX / t - a.velocity.x; const vy = (deltaY - 0.5 * g * t * t) / t - a.velocity.y; // 转换为力 const deltaT = 1/60; const forceX = a.mass * vx / deltaT; const forceY = a.mass * vy / deltaT; Body.applyForce(a, a.position, {x: forceX, y: forceY}); }, 1000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script>
内容的提问来源于stack exchange,提问作者pius lee
相关产品推荐
相关产品推荐

