运行示例窗口
示例窗口提示
- 红色按钮
恢复原始状态
- 黄色按钮
缩小/恢复
- 绿色按钮
开启画中画
- 可通过标题栏拖动窗口。
- 可拖动窗口右下角改变窗口大小。
- 可通过清除按钮清除世界内的所有物体。
开始
安装
npm install matter-js
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
示例
- 创建引擎
- 创建渲染器,将引擎和画布关联起来
- 创建物体
- 添加物体到世界
- 运行世界
// class MatterJsExample
this.Engine = Matter.Engine; // 引擎
this.Render = Matter.Render; // 渲染器
this.Runner = Matter.Runner; // 运行器
this.Bodies = Matter.Bodies; // 物体
this.Composite = Matter.Composite; // 组合
// 创建一个引擎
this.engine = this.Engine.create();
// 创建一个渲染器
this.render = this.Render.create({
element: document.querySelector("#matter-js-canvas"), // 指定渲染的元素
engine: this.engine, // 指定引擎
options: {
width: 600, // 设置画布宽
height: 600, // 设置画布高
wireframes: false, // 关闭线框模式
}
});
let boxA = this.Bodies.rectangle(40, 40, 80, 80); // 矩形
this.Composite.add(this.engine.world, boxA);
// 运行渲染器
this.Render.run(this.render);
// 创建一个 runner
this.runner = this.Runner.create();
// 运行引擎
this.Runner.run(this.runner, this.engine);
创造物体
矩形(rectangle)
x
和y
为矩形中心点,width
和height
是矩形的宽高,options
为物体的属性配置,在后面会详细介绍。
this.Bodies.rectangle(x, y, width, height, options);
x
y
width
height
options
圆形(circle)
x
和y
是圆心坐标,radius
是半径,options
为物体的属性配置,在后面会详细介绍。
this.Bodies.circle(x, y, radius, options);
x
y
radius
options
梯形(trapezoid)
x
和y
定义了梯形的中心点坐标,width
和height
是梯形的宽高,slope
是斜率,options
为物体的属性配置,在后面会详细介绍。
this.Bodies.trapezoid(x, y, width, height, slope, options);
x
y
width
height
slope
options
多边形(polygon)
x
和y
定义了梯形的中心点坐标,sides
是多边形的边数,radius
是多边形的半径,options
为物体的属性配置,在后面会详细介绍。
this.Bodies.polygon(x, y, sides, radius, options);
x
y
sides
radius
options
由顶点绘制图形(fromVertices)
x
和y
定义了图形的中心点坐标,vertexSets
是顶点集合,如[{ x: 0, y: 0 }, { x: 20, y: 0 },{ x: 70, y: 80 }, { x: 30, y: 80 }]
,options
为物体的属性配置,在后面会详细介绍。
this.Bodies.fromVertices(x, y, vertexSets, options);
x
y
vertexSets
options
物体属性配置
填充颜色
render.fillStyle
为填充颜色,render.strokeStyle
为边框颜色,render.lineWidth
为边框宽度。
this.Bodies.rectangle(40, 40, 80, 80, {
render: {
fillStyle: '#FFFFFF', // 填充颜色
strokeStyle: '#FF0000', // 边框颜色
lineWidth: 4 // 边框宽度
}
});
纹理
render.sprite
为纹理配置,texture
是纹理图片路径,xScale
和yScale
是纹理图片的缩放比例,xOffset
和yOffset
是纹理图片的偏移量。
this.Bodies.rectangle(300, 300, 128, 128, {
render: {
sprite: {
texture: './img/fill.png',
xScale: 0.25,
yScale: 0.25,
xOffset: 0,
yOffset: 0
}
}
});
透明度
render.opacity
为物体的透明度。
this.Bodies.rectangle(300, 300, 128, 128, {
render: {
opacity: 0.1
}
});
是否显示
render.visible
为物体是否显示。
this.Bodies.rectangle(300, 300, 128, 128, {
render: {
visible: false
}
});
旋转
angle
为旋转角度。
this.Bodies.rectangle(300, 300, 100, 100, {
angle: Math.PI / 180 * 45
});
静止
isStatic
可以设置物体是否静止。
let ground = this.Bodies.rectangle(300, 590, 600, 20, {
isStatic: true,
render: {
fillStyle: '#FFFFFF'
}
});
空气阻力
frictionAir
可以设置物体的空气阻力。
let boxH = this.Bodies.rectangle(300, 300, 100, 100, {
frictionAir: 0.01
});
摩擦力
friction
可以设置物体的摩擦力。
let boxH = this.Bodies.rectangle(300, 300, 100, 100, {
friction: 1
});
弹力
restitution
可以设置物体的弹力。
this.Bodies.rectangle(300, 300, 100, 100, {
restitution: 2
});
质量
mass
可以设置物体的质量。
this.Bodies.rectangle(300, 300, 100, 100, {
mass: 100
});
堆
xx
和yy
为堆的起始位置,columns
和rows
为堆的列数和行数,columnGap
和rowGap
为堆的列间距和行间距,callback
为堆中每个物体的回调函数。
Matter.Composites.stack(xx, yy, columns, rows, columnGap, rowGap, callback)
示例
Matter.Composites.stack(100, 100, 3, 3, 10, 10, (x, y) => {
return this.Bodies.rectangle(x, y, 50, 50, {
restitution: 0.8,
mass: 0.5
});
});
约束
示例一
let bodyA = this.Bodies.rectangle(310, 530, 20, 100, {
isStatic: true,
render: {
fillStyle: '#f00'
},
collisionFilter: {
group: -1
}
});
let bodyB = this.Bodies.rectangle(340, 530, 550, 10, {
render: {
fillStyle: '#00f'
},
collisionFilter: {
group: -1
}
});
let rotateConstraint = Matter.Constraint.create({
bodyA: bodyA,
bodyB: bodyB,
length: 0
})
let stack_boxA = Matter.Composites.stack(10, 30, 4, 3, 10, 20, function (x, y) {
return Matter.Bodies.rectangle(x, y, 40, 20)
});
let stack_boxB = Matter.Composites.stack(320, 30, 3, 4, 10, 20, function (x, y) {
return Matter.Bodies.rectangle(x, y, 40, 20)
});
let ground = this.Bodies.rectangle(300, 590, 600, 20, {
isStatic: true,
render: {
fillStyle: '#FFFFFF'
}
});
this.add([bodyA, bodyB, rotateConstraint, stack_boxA, stack_boxB, ground])
示例二
let circleA = this.Bodies.circle(400, 100, 20, {
isStatic: true
});
let circleB = this.Bodies.circle(400, 300, 20);
let spring = Matter.Constraint.create({
bodyA: circleA,
bodyB: circleB,
pointA: Matter.Vector.create(0, 0),
pointB: Matter.Vector.create(0, 0),
length: 100,
stiffness: 0.1,
damping: 0.1
});
this.add([circleA, circleB, spring]);
Matter.Constraint.create(options)
的配置对象包含以下属性:
bodyA
:类型为Matter.Body
,约束连接的第一个物体。pointA
:类型为Matter.Vector
,约束连接的第一个物体上的点。bodyB
:类型为Matter.Body
,约束连接的第二个物体。pointB
:类型为Matter.Vector
,约束连接的第二个物体上的点。length
:类型为number
,约束的初始长度。stiffness
:类型为number
,约束的刚度系数。damping
:类型为number
,约束的阻尼系数。render
:约束的渲染选项。render.visible
:类型为boolean
,表示约束是否可见,默认为 true。render.lineWidth
:类型为number
,表示约束线条的宽度。render.strokeStyle
:类型为string
,表示约束线条的颜色。
鼠标约束
let mouse = Matter.Mouse.create(this.render.canvas);
// 添加鼠标约束
let mouseConstraint = Matter.MouseConstraint.create(this.engine, {
mouse: mouse,
constraint: {
render: {
visible: false // 默认为 true,会显示鼠标拖拽轨迹
}
}
});
this.add(mouseConstraint);
引擎
重力
engine.gravity
可以改变重力向量。scale
可以改变重力大小,x
和y
可以改变重力方向。
this.engine.gravity.scale = 0.001;
this.engine.gravity.y = -1;
this.engine.gravity.x = 0;
x
y
scale
时间
engine.timing.timeScale
可以设置时间缩放。
this.engine.timing.timeScale = 1;
timeScale
事件监听
鼠标事件
// 监听鼠标按下事件
Matter.Events.on(mouseConstraint, 'mousedown', function(event) {
console.log('按下')
})
// 监听鼠标移动事件
Matter.Events.on(mouseConstraint, "mousemove", function(event) {
console.log('移动')
})
// 监听鼠标抬起事件
Matter.Events.on(mouseConstraint, "mouseup", function(event) {
console.log('抬起')
})
// 监听鼠标拖拽刚体 - 开始拖拽
Matter.Events.on(mouseConstraint, 'startdrag', function(event) {
console.log('开始拖拽')
})
// 监听鼠标拖拽刚体 - 结束拖拽
Matter.Events.on(mouseConstraint, 'enddrag', function(event) {
console.log('结束拖拽')
})
碰撞事件
// 碰撞开始事件
Matter.Events.on(this.engine, 'collisionStart', function(event) {
console.log('碰撞开始', event)
});
// 碰撞持续事件
Matter.Events.on(this.engine, 'collisionActive', function(event) {
console.log('碰撞', event)
});
// 碰撞结束事件
Matter.Events.on(this.engine, 'collisionEnd', function(event) {
console.log('碰撞结束', event)
});
渲染事件
Matter.Events.on(this.render, 'beforeRender', function() {
console.log('渲染前')
});
Matter.Events.on(this.render, 'afterRender', function() {
console.log('渲染后')
});
更新事件
Matter.Events.on(this.engine, 'beforeUpdate', function() {
console.log('更新前')
});
Matter.Events.on(this.engine, 'afterUpdate', function() {
console.log('更新后')
});
一些例子
弹弓
let ground = this.Bodies.rectangle(300, 590, 600, 20, { isStatic: true, render: { fillStyle: '#FFFFFF' } });
let rockOptions = {
frictionAir: 0.001
};
let rock = this.Bodies.circle(150, 450, 25, rockOptions);
let tempRock = this.Bodies.circle(150, 450, 1, {
isStatic: true,
render: { visible: false },
collisionFilter: {
mask: 0x0000
}
});
let anchor = { x: 150, y: 450 }
let elastic = Matter.Constraint.create({
pointA: anchor,
bodyB: rock,
pointB: { x: 0, y: 0 },
length: 0.1,
damping: 0.01,
stiffness: 0.05
});
this.add([ground, rock, elastic])
let mouse = Matter.Mouse.create(this.render.canvas);
let mouseConstraint = Matter.MouseConstraint.create(this.engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false
}
}
});
this.add(mouseConstraint);
Matter.Events.on(this.engine, 'afterUpdate', () => {
if (mouseConstraint.mouse.button === -1 && (rock.position.x > 190 || rock.position.y < 430) && elastic.bodyB === rock) {
if (Matter.Body.getSpeed(rock) > 45) {
Matter.Body.setSpeed(rock, 45);
}
elastic.bodyB = tempRock;
setTimeout(() => {
rock = this.Bodies.circle(150, 450, 25, rockOptions);
this.add(rock);
elastic.bodyB = rock;
}, 1000);
}
})
文字
let canvas = document.createElement('canvas');
canvas.width = 120;
canvas.height = 50;
let ctx = canvas.getContext('2d');
ctx.fillStyle = '#fff';
ctx.font = '50px Arial';
ctx.textAlign = 'left';
ctx.fillText('Hello', 0, 50);
let dataurl = canvas.toDataURL("image/png");
let text = this.Bodies.rectangle(300, 300, 120, 50, {
render: {
sprite: {
texture: dataurl,
xScale: 1,
yScale: 1,
xOffset: 0,
yOffset: 0
}
}
});
this.add(text);