Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matter.js 2D 物理引擎介绍 #90

Open
pfan123 opened this issue Apr 15, 2021 · 0 comments
Open

Matter.js 2D 物理引擎介绍 #90

pfan123 opened this issue Apr 15, 2021 · 0 comments

Comments

@pfan123
Copy link
Owner

pfan123 commented Apr 15, 2021

什么物理引擎?

物理引擎是一个计算机程序,使用质量、速度、摩擦力和空气阻力等变量,模拟了一个近似真实的物理系统,为刚性物体赋予真实的物理效果,比如重力、旋转和碰撞等效果,让物体的行为表现的更加趋向真实。

百度百科,针对 物理引擎 解释

物理引擎通常有两种常见类型:实时物理引擎和高精度物理引擎。高精度物理引擎需要更多的处理能力来计算非常精确的物理,通常使用在科学研究(计算物理学)和动画电影制作。实时物理引擎常用于电子游戏并且简化了算法,降低精确度以减少处理时间,使得在游戏中有更好的处理速度。

物理引擎在游戏中的应用

在前端开发领域,物理引擎是比较小众的话题,通常作为游戏开发引擎附属工具出现。物理引擎仿真在计算机的虚拟世界中模拟物体在真实世界的表现(动力学仿真最为常见),让画面中物体的运动表现更符合玩家对现实世界的认知,比如在《愤怒的小鸟》游戏中被弹弓发射出去小鸟或是因为被撞击而坍塌的物体堆。

matter

物理引擎可以帮助开发者更快速地实现诸如碰撞反弹、摩擦力、单摆、弹簧、布料等等不同类型的仿真效果。物理引擎通常并不需要处理和画面渲染相关的事务,而只需要完成计算仿真的部分就可以了。Matter.js 提供了基于 canvas2D API 的渲染引擎,可以结合 p2.js 与 CreateJS 或 Egret 渲染引擎使用。

游戏引擎和物理引擎的联合使用并没有想象中那么复杂,实际上只需要完成不同引擎之间的坐标系映射就可以了。

img

Matter.js 介绍

Matter.js 是一个用于 Web 的 JavaScript 2D 物理引擎库,该项目诞生于 2014 年 2 月 28 号(0.5.0-alpha 版本),它相较于老牌的 Box2D 引擎库,Matter.js 更为轻量级,并且在性能和功能方面也不逊色。

box2d.js 通过 Emscripten 将 c 语言转换为 asm.js 进行实现

Matter.js 特性

刚体 (Rigid bodies) 复合体 (Compound bodies) 组合体(Composite bodies)
凹面和凸面 物理特性(质量、面积、密度等) 弹性(弹性和非弹性碰撞)
碰撞(粗略阶段、中间阶段、精细阶段) 稳定的堆叠和静止 动量守恒
摩擦力和阻力(Friction and resistance) 事件监听(Events) 约束(Constraints)
重力(Gravity) 睡眠和静态物体 圆角(倒角)
视图(平移、缩放) 碰撞查询(射线追踪、区域测试) 时间缩放(减速、加速)
Canvas 渲染器(支持向量和纹理) MatterTools 工具(创建、测试和调试) 世界状态序列化,需要 resurrect.js
跨浏览器(Chrome、Firefox、Safari、IE8+) 兼容移动端(触摸、响应) 原生 JS 实现

Matter.js 基础概念

大多数的物理引擎对于物理模拟的要素都有着相近的概念,不同的引擎差别在于使用的方式,功能的全面性,模拟的精细度等层面,下面就先从物理世界的基础概念讲起。

Engine(引擎)和 World(世界)

Matter.Engine 模块包含了创建和处理引擎的方法,引擎是负责管理和更新模拟世界的控制器,引擎可以控制时间的缩放,可以检测所有的碰撞事件,并且拿到所有碰撞的物体对(pairs)。

在 Matter.js 中任何的物体都需要一个容身处,而存放这些物体的地方,我们称之为世界,物体必须添加到世界里,然后由引擎运行这个世界。而创建世界需要使用到 Matter.World 模块,该模块包含了用于创建和操作世界的方法,一个 Matter.World 相当于一个复合物体,物体、约束、复合物体的聚合体,其次世界还有额外的一些属性,比如重力、边界。

img

Render(渲染)

// Matter.Render 用法
const engine = Engine.create();

// 将物体加入到世界中
const render = Render.create({
    element: document.body,
    engine: engine,
    options: options
});

Engine.run(engine);
Render.run(render);
  • element 是一个容器元素,使用时指定要渲染的节点
  • engine 指定为 Matter.Engine 实例
  • options 指定一些渲染的参数

Matter.Render 是将实例渲染到 Canvas 中的渲染器,控制视图层的样式,它的主要作用是用于开发和调试,默认情况下 Matter.Render 将只显示物体的线框(轮廓),这对于开发和调试很有帮助,但如果需要使用到全局实体渲染则需要将线框模式关闭 render.options.wireframes = false,另外它同样也适合制作一些简单的游戏,因为它包括了一些绘图选项、线框、向量、Sprite 精灵和视窗功能。

img

Body(刚体)

物体或者叫刚体,在物理引擎里特指坚硬的物体,具有固定的形状,不能形变。刚体可以用于表示一个箱子、一个球或是一块木头,每个物体都有自己的物理属性,质量、速度、摩擦力、角度等,还可以设置刚体的标记。Matter.Bodies 模块中内置了几种刚体,矩形 Matter.rectangle、多边形 Matter.polygon、圆形 Matter.circle 、梯形 Matter.trapezoid 等等。

img

// 创建刚体
const rect = Bodies.rectangle(200, 100, 50, 50), // 矩形
    circle = Bodies.circle(300, 100, 25), // 圆
    polygon = Bodies.polygon(450, 100, 5, 25), // 多边形
    trapezoid = Bodies.trapezoid(590, 100, 50, 50, 3); // 梯形

// 将刚体添加到世界中
World.add(engine.world, [rect, circle, polygon, trapezoid]);

Composite(复合体)

由刚体和复合材料通过约束组合在一起的就叫做复合体。复合体对外当作一个刚体,复合体的物理属性是通过所包含的刚体的属性综合计算出来的。Matter.Composite 模块包含用于创建和处理复合体的方法,另外还有一个 Matter.Composites 模块,提供了几种特别的复合材料,例如 链 Composites.chain、牛顿摆球 Composites.newtonsCradle、软体 Composites.softBody、汽车 Composites.car 、堆叠 Composites.stack 等等。

桥梁 (Bridge)

img

// 使用堆叠创建桥梁
const group = Body.nextGroup(true);

const bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y) {
    return Bodies.rectangle(x, y, 50, 20, {
        collisionFilter: { // 过滤碰撞
            group: group
        }
    });
});

// 创建链约束
Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 });

布 (Cloth)

img

// 软体
const cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, {
    friction: 0.00001, // 摩擦力
    collisionFilter: {
        group: Body.nextGroup(true)
    },
    render: {
        visible: false
    }
});

牛顿摆球 (Newton's Cradle)

img

// 创建牛顿摆球
const newtonsCradle = Composites.newtonsCradle(300, 320, 5, 25, 150);

Constraint(约束)

约束可理解为通过一条线,将刚体 A 和刚体 B 两个刚体连接起来,被约束的两个刚体由于被连接在了一起,移动就相互受到了限制。Matter.Constraint 模块包含了用于创建和处理约束的方法,这个约束可以很宽松,也可以很紧绷,还可以定义约束的距离,约束具有弹性,可以用来当作橡皮筋。

img

// 创建一个矩形和圆形
const rect = Bodies.rectangle(400, 100, 50, 50, {
      isStatic: true
    }),
    ball = Bodies.circle(400, 400, 50);

World.add(engine.world, [
    rect,
    ball,
    Constraint.create({
        bodyA: rect, // 约束刚体 A
        pointA : { // 约束点 A
            x: 0,
            y: 0
        },
        bodyB: ball, // 约束刚体 B
        pointB: { // 约束点 B
            x: 0,
            y: -50
        },
        stiffness: 0.6
    })
]);

MouseConstraint(鼠标约束)

如果你想让刚体与用户之间有交互,那就要在鼠标和刚体之间建立连接,也就是鼠标和刚体间的约束,Matter.MouseConstraint 模块包含用于创建鼠标约束的方法,提供通过鼠标或触摸(移动端时)移动刚体的能力,可以设置什么标记的物体才能被鼠标操纵,创建鼠标约束后,可以捕获到鼠标的各类事件。

// 全局鼠标约束
const mouseConstraint = MouseConstraint.create({
  element: render.canvas
});

World.add(engine.world, mouseConstraint);
// 设置某个标记的物体才能被鼠标操纵
const categoryBall = 0x0001; // 分类

const ball = Matter.Bodies.circle(300, 350, 32, {
  density: 0.68, // 密度
  restitution: 1, // 弹性
  collisionFilter: {
    category: categoryBall
  }
});

const mouseConstraint = MouseConstraint.create({
  element: render.canvas,
  collisionFilter: {
  	mask: categoryBall
  }
});

World.add(engine.world, mouseConstraint);

Vector(向量)

Matter.Vector 模块包含用于创建和操纵向量的方法,向量是引擎有关几何操作行为的基础,修改物体的运动状态基本都是使用向量来控制,例如赋予物体一个力,或者设置物体的速度、旋转角度,并且内置了多个向量的求解函数:向量积、标量积、格式化、垂直向量等等。

Events(事件)

Matter.Events 模块包含了绑定、移除和触发对象的方法。

  • 绑定事件 Matter.Events.on(object, eventNames, callback)
  • 移除事件 Matter.Events.off(object, eventNames, callback)
  • 触发事件 Matter.Events.trigger(object, eventNames, event)

Matter.js 中的一些属性

施加力

Matter.Body.applyForce(body, position, force) 方法可以给刚体施加一个力,传入 X 和 Y 轴需要的力度值,通过这个方法你可以去模拟踢一个足球、投一个篮球的效果。

const ball = Bodies.circle(300, 100, 25, {
  density: 0.68, // 密度
  restitution: 0.8 // 弹性
});

World.add(engine.world, ball);

function addForce() {
  let forceMagnitude = 0.02 * ball.mass;
  Body.applyForce(ball, ball.position, {
  	x : (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]),
  	y : -forceMagnitude + Common.random() * -forceMagnitude
  });
}

addForce();

重力

可以设置 X、Y 轴的重力值,默认都为 1,参数在 0、1、-1 中选择使用。

// 实现反重力效果
engine.world.gravity.y = -1;

// 无重力效果
engine.world.gravity.y = 0;

睡眠状态

通过 enableSleeping: true 开启睡眠模式后,当刚体处于不受作用状态时,会进入睡眠状态,这样可以有效的提高引擎的性能,当物体被其他物体碰撞或者对刚体施加力时,刚体会被叫醒,引擎会继续对其进行计算模拟。

// 开启睡眠状态
const engine = Engine.create({
	enableSleeping: true
});

// 还可以针对进入睡眠状态的刚体进行监听,比如将刚体移出世界
Event.on(ball, "sleepStart", function() {
	World.remove(engine.world, ball);
});

摩擦力

摩擦力在 Matter.js 中分别提供了三种:摩擦力 friction、空气摩擦力 frictionAir 以及静止摩擦力 frictionStaticfriction 默认值是 0.1,取值范围在 0 - 1,当值为 0 意味着刚体可以摩擦力的无限滑动,1 意味着对刚体施加力后会立刻停止,frictionAir 默认值是 0.01,取值范围 0 - 1,当值为 0 意味着刚体在空间中移动时速度永远不会减慢,值越高时刚体在空间的移动速度越慢,frictionStatic 默认值 0.5,当值为 0 时意味着刚体几乎是静止的,值越高时意味着需要移动刚体所需的力就越大。

// 摩擦力
Bodies.rectangle(300, 70, 40, 40, {
	friction: 0.01
})

// 空气摩擦力
Bodies.rectangle(300, 70, 40, 40, {
	frictionAir: 0.05
})

// 静止摩擦力
Bodies.rectangle(300, 70, 40, 40, {
	frictionStatic: 1
})

时间缩放

可以控制全局的时间,当值为 0 时为冻结模拟,值为 0.1 给出慢动作效果,值为 1.2 时给出加速效果。

engine.timing.timeScale = 0.1;

这里就简单提及到几个属性,当然还有更多的属性比如:视图(View)、弹性(Restitution)等等,更详细的 API 可到官网查看。

Matter.js 调试

除了前面讲 Matter.Render 模块的时候提到的线框模式 wireframes 便于调试外,Matter.Render 模块其实还为我们提供了以下几种方法,便于我们自定义调试选项:

const render = Render.create({
    element: document.body,
    engine: engine,
    options: {
        width: 800,
        height: 600,
        pixelRatio: 1, // 设置像素比
        background: '#fafafa', // 全局渲染模式时背景色
        wireframeBackground: '#222', // 线框模式时背景色
        hasBounds: false,
        enabled: true,
        wireframes: true, // 线框模式
        showSleeping: true, // 刚体睡眠状态
        showDebug: false, // Debug 信息
        showBroadphase: false, // 粗测阶段
        showBounds: false, // 刚体的界限
        showVelocity: false, // 移动刚体时速度
        showCollisions: false, // 刚体碰撞点
        showSeparations: false, // 刚体分离
        showAxes: false, // 刚体轴线
        showPositions: false, // 刚体位置
        showAngleIndicator: false, // 刚体转角指示
        showIds: false, // 显示每个刚体的 ID
        showVertexNumbers: false, // 刚体顶点数
        showConvexHulls: false, // 刚体凸包点
        showInternalEdges: false, // 刚体内部边界
        showMousePosition: false // 鼠标约束线
    }
});

另外官方提供了三个调试工具,可单独使用或一起使用,如下:

工具 matter-tools

  • MatterTools.Demo 用于运行和测试 DEMO
  • MatterTools.Gui 改变引擎的属性
  • MatterTools.Inspector 检查世界

Other Resource

使用Phaser3+Matter.js实现“合成大西瓜”游戏

PolyK 用 Javascript 编写的多边形库

Slicing, splitting and cutting HTML5 physics bodies using Phaser, Matter.js and PolyK

H5游戏开发:决胜三分球

H5游戏开发:套圈圈

cannon.js - A lightweight and simple 3D physics engine for the web

pixijs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant