Matter-JS constraint 约束

目录

constraint 约束

Constraint.create


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>

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/85847561
今日推荐