目录
constraint 约束
1、多个物体可以使用一根有弹性的绳子连接起来,这个绳子就相当于 constraint (约束),被约束的多个刚体连接在一起之后,移动就相互受到了牵制。
2、Matter.Constraint 模块包含了用于创建和处理约束的方法,如约束的长度、约束的强度等。
3、官网 API:http://brm.io/matter-js/docs/classes/Constraint.html
4、Matter.Constraint.create(options)→ Constraint 用于创建约束,具体使用在代码的注释中已经详细说明。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Matter-JS</title>
<!--matter-js cdnjs地址-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.js"></script>
<script type="text/javascript">
var stageWidth = 800;//舞台宽度
var stageHeight = 500;//舞台高度
window.onload = function () {
var Engine = Matter.Engine;//引擎
var Render = Matter.Render;//渲染器
var World = Matter.World;//世界
var Constraint = Matter.Constraint;//约束
var MouseConstraint = Matter.MouseConstraint;//鼠标控制
var Composites = Matter.Composites;//复合材料
var Bodies = Matter.Bodies;//物体
var engine = Engine.create();//创建引擎
var render = Render.create({//创建渲染器
engine: engine,//渲染创建好的引擎
element: document.body,//渲染页面的body元素
options: {
width: stageWidth,
height: stageHeight,
wireframes: false,//是否显示边线框(显示边线方便调试)
showVelocity: true//是否显示速度
}
});
Engine.run(engine);//运行引擎
Render.run(render);//运行渲染器
var crossArr = createCross(Bodies);
/**
* Constraint.create():创建约束,其参数是一个json对象,主要参数有:bodyA,pointA,bodyB,pointB,length,stiffness等
* 本例中:bodyA 和 bodyB 分别为跷跷板横竖两个矩形;
* pointA 和 pointB 表示约束点的位置,其值为向量,默认为0,在物体中心位置。以物体中心为原点进行量相减(三角形法则)
* 为两个向量,默认为0向量,即物体的约束点默认在物体中心位置,否则,物体的对应的约束点为中心位置加上所赋的向量值。
* crossArr[0]是跷跷板竖杆,高150,以中心为起点,y方向-75,则约束点刚好在矩形顶点中间位置
* crossArr[1]是跷跷板横杆,为设置 pointB 时,其约束点默认在物体中心{x:0,y:0}
*/
var rotate = Constraint.create({
bodyA: crossArr[0],
pointA: {x: 0, y: -75},
bodyB: crossArr[1],
length: 0,//约束点的长度
stiffness: 0.9//刚度值(0,1],值越大,物体刚度越强,越不容易拉伸
});
/**创建一个堆叠混合体——堆叠矩形,3行4列
* stack(xx, yy, columns, rows, columnGap, rowGap, callback)*/
var stack_rect = Composites.stack(stageWidth / 4, 20, 4, 3, 0, 0, function (x, y) {
return Bodies.rectangle(x, y, 100, 40);//堆叠的每个矩形宽100,高40
});
/**添加鼠标控制*/
var mouseConstraint = MouseConstraint.create(engine, {
element: document.body
});
World.add(engine.world, crossArr);//添加十字架刚体
World.add(engine.world, [stack_rect, mouseConstraint, rotate]);//添加复合体和鼠标控制以及约束
World.add(engine.world, create4Wall(Bodies));//添加4面墙到世界中
}
/**
* 创建一个跷跷板(横竖两个矩形组成)
*/
function createCross(Bodies) {
/**竖杆(矩形),这里有两个属性需要注意
* render:{visible:true,opacity:1,sprite:{xScale:1,yScale:1,xOffset:0,yOffset:0},lineWidth:0}
* collisionFilter:{category:0x0001,mask:0xFFFFFFFF,group:0}:碰撞过滤器
* group相等的物体,当group>0时,则它们始终会碰撞
* group相等的物体,当group<0时,则它们始终不碰撞
*/
var rectA = Bodies.rectangle(stageWidth / 2, stageHeight - 75, 40, 150, {
isStatic: true,//静止竖杆运动
render: {
fillStyle: "#0ff"//设置物体背景颜色
},
collisionFilter: {
group: -1//十字架的横杆与竖杆设置为始终不会碰撞,两者的group相等且小于0
}
});
var rectB = Bodies.rectangle(stageWidth / 2, 350, 500, 40, {//创建十字架横杆(矩形)
render: {
fillStyle: "#f00"
},
collisionFilter: {
group: -1
}
});
return [rectA, rectB];
}
/**
*创建4面墙-强制物体在墙内运动
*/
function create4Wall(Bodies) {
var ground_top = Bodies.rectangle(stageWidth / 2, 0, stageWidth, 40, {isStatic: true});
var ground_right = Bodies.rectangle(stageWidth, stageHeight / 2, 40, stageHeight, {isStatic: true});
var ground_bottom = Bodies.rectangle(stageWidth / 2, stageHeight, stageWidth, 40, {isStatic: true});
var ground_left = Bodies.rectangle(0, stageHeight / 2, 40, stageHeight, {isStatic: true});
return [ground_top, ground_right, ground_bottom, ground_left];
}
</script>
</head>
<body>
</body>
</html>
1、两个刚体(矩形)通过约束组合成一个混合体(跷跷板),可以看到中间约束点的绳子,stiffness(刚度)越大,物体越不容易拉伸。
2、掉下来的属于符合材料,可以参考《Matter-JS Composites 混合材料详解》中的 "stack 堆叠" 部分。
3、Matter.Constraint 约束将会是很常见的操作,也可以参考《Matter-JS Composites 混合材料 · 上》中的 "chain 链" 部分。
Constraint.create
1、Constraint.create():创建约束,其参数是一个 json 对象, 主要参数有:bodyA,pointA,bodyB,pointB,length,stiffness 等。
2、bodyA 和 bodyB 分别为被约束的两个物体。
3、pointA 和 pointB 分别表示 bodyA、bodyB 的约束点位置。pointA、pointB 的值为向量,默认为 {x:0,Y:)},在物体的中心位置。以物体中心为原点进行向量相减(三角形法则)
4、Constraint.create() 函数源码地址:http://brm.io/matter-js/docs/files/src_constraint_Constraint.js.html#l28
现在来实现上图效果:
1、3个锁链,左边为矩形堆叠组成,中间为圆形堆叠组成,右边为圆角矩形堆叠组成。
2、每条锁链中的物体相互应该不发生碰撞,则设置 collisionFilter: {group: group} group 为负数且相等即可。
3、锁链与锁链相互发生碰撞,则 group 不相等即可。
4、每条锁链顶部不是单纯的设置 {isStatic: true} 进行固定,而是使用 Constraint.create 创建约束而成,因为顶部可以看到约束的绳子。
亲测Matter.js 的0.14.2版本效果如上,老版本可能会有区别,实现代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Matter-JS</title>
<!--matter-js cdnjs地址-->
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.js"></script>-->
<script src="../js/matter_0.14.2.js"></script>
<script type="text/javascript">
var stageWidth = 800;//舞台宽度
var stageHeight = 500;//舞台高度
var Engine = Matter.Engine;//引擎
var Render = Matter.Render;//渲染器
var World = Matter.World;//世界
var Constraint = Matter.Constraint;//约束
var MouseConstraint = Matter.MouseConstraint;//鼠标控制
var Bodies = Matter.Bodies;//内置常见刚体
var Composites = Matter.Composites;//符合材料
var Composite = Matter.Composite;//混合体
var Common = Matter.Common;//公用模块
var Body = Matter.Body;//刚体
window.onload = function () {
matterJS();
}
/**Matter-JS*/
function matterJS() {
var engine = Engine.create();//创建引擎
var render = Render.create({//创建渲染器
engine: engine,//渲染创建好的引擎
/**渲染页面的body元素,即会在body标签自动新建<canvas>画布,同理如果element的值是某个div元素-
* 则会在div下自动新建canvas,canvas的尺寸是options中的width、height
* */
element: document.body,
options: {
width: stageWidth,//画布的宽度
height: stageHeight,//画布的高度
wireframes: true,//线框模式,默认false不使用线框模式
showAngleIndicator: true,//是否显示角度,默认false
showVelocity: true,//是否显示速度,默认false
showCollisions: true,//是否显示碰撞点,默认false
}
});
Engine.run(engine);//运行引擎
Render.run(render);//运行渲染器
/**设置鼠标控制*/
var mouseConstraint = MouseConstraint.create(engine, {});
/**---------第------1-------条-------链(矩形)*/
/**Body.nextGroup(isNonColliding):下一个组ip值,
* isNonColliding:表示非碰撞,为true时,第一次调用 nextGroup 时返回 -1,每调用一次则递减1
* isNonColliding=false时,第一次调用 nextGroup 时返回 1,每调用一次则递加1*/
var group = Body.nextGroup(true);
/**参加竖向的堆叠材料*/
var stack_1 = Composites.stack(stageWidth / 4, 40, 1, 9, 0, 0, function (x, y) {
/**使用矩形组成链条,链条中所有物体属于同一个group,且为负数,这样相互就不会发生碰撞*/
return Bodies.rectangle(x, y, 20, 40, {collisionFilter: {group: group}});
});
/**使用复合材料链将堆叠体链接起来
* 注意:堆叠体只是将多个物体堆叠在一起,但是相互仍然是隔离的,相互没有约束的
* 而chain链是进行constraint(约束)的,所以链条是一个有约束的整体
* stiffness:设置链条的刚度,相当于设置链条的弹性;length:链条的长度*/
Composites.chain(stack_1, 0, 0.5, 0, -0.5, {stiffness: 0.7, length: 2});
/**将锁链固定在舞台上:
* 思路一是将链条上的第一个物体设置 {isStatic: true} 属性即可固定住整个链条
* 思路二是将第一个物体创建约束Constraint.create。这里对3个物体都是要这种方式,从而抽取出公共方法
* */
var fixed_1 = constraintChain(stack_1);
/**为链条上的每个物体设置一个初始偏移值,这样一开始就会动起来*/
for (var i = 0; i < stack_1.bodies.length; i++) {
Body.translate(stack_1.bodies[i], {x: -i * 20, y: -50});
}
/**---------第------2-------条-------链(圆形)*/
/**true表示非碰撞体,链条内部不碰撞,但是链条与链条应该发生碰撞,所以重新取值*/
group = Body.nextGroup(true);
var stack_2 = Composites.stack(stageWidth / 2, 40, 1, 9, 0, 0, function (x, y) {
return Bodies.circle(x, y, 20, {collisionFilter: {group: group}});
});
Composites.chain(stack_2, 0, 0.5, 0, -0.5, {stiffness: 0.9, length: 2});
var fixed_2 = constraintChain(stack_2);
for (var i = 0; i < stack_2.bodies.length; i++) {
Body.translate(stack_2.bodies[i], {x: -i * 20, y: -80});
}
/**---------第------3-------条-------链(圆角矩形)*/
group = Body.nextGroup(true);
var stack_3 = Composites.stack(stageWidth * (3 / 4), 30, 1, 9, 0, 0, function (x, y) {
return Bodies.rectangle(x, y, 20, 60, {collisionFilter: {group: group}, chamfer: 10});
});
/**length=0时,只能看到约束的点,却看不到约束的绳子*/
Composites.chain(stack_3, 0, 0.3, 0, -0.3, {stiffness: 0.9, length: 0});
var fixed_3 = constraintChain(stack_3);
/**将物体以及鼠标控制添加到世界中*/
World.add(engine.world, [mouseConstraint, stack_1, stack_2, stack_3]);
/**将链条的约束添加到世界中*/
World.add(engine.world, [fixed_1, fixed_2, fixed_3]);
/**为世界4周添加4面墙*/
World.add(engine.world, create4Wall(Bodies));
}
/**为链条添加约束*/
function constraintChain(stack) {
/**将stack(链条)约束(固定)在 pointA的位置*/
var fixed = Constraint.create({
/**stack.bodies返回的Body数组,.position返回物体当前位置的向量Vector,Default: { x: 0, y: 0 }*/
pointA: {x: stack.bodies[0].position.x, y: stack.bodies[0].position.y - 30},
bodyB: stack.bodies[0],
pointB: {x: 0, y: -20},
length: 20,//约束点的长度
stiffness: 0.3//刚度值( 0,1],值越大,物体刚度越强,越不容易拉伸
});
return fixed;
}
/**创建4面墙-强制物体在墙内运动*/
function create4Wall(Bodies) {
var ground_top = Bodies.rectangle(stageWidth / 2, 5, stageWidth, 40, {isStatic: true});
var ground_right = Bodies.rectangle(stageWidth, stageHeight / 2, 40, stageHeight, {isStatic: true});
var ground_bottom = Bodies.rectangle(stageWidth / 2, stageHeight - 5, stageWidth, 40, {isStatic: true});
var ground_left = Bodies.rectangle(10, stageHeight / 2, 40, stageHeight, {isStatic: true});
return [ground_top, ground_right, ground_bottom, ground_left];
}
</script>
</head>
<body>
</body>
</html>