1. 程式人生 > >Matter-JS collisionFilter 碰撞過濾器

Matter-JS collisionFilter 碰撞過濾器

collisionFilter 碰撞過濾器

1、Matter.js 建立的物體可以為它們設定碰撞規則,如哪些物體相互應該碰撞,而哪些物體相互之間則不應該發生碰撞。

2、Body(剛體)提供了一個 collisionFilter 屬性,其值是一個 json 陣列,可選值有:group,category,mask。預設值如下:

collisionFilter: {
        category: 0x0001,
        mask: 0xFFFFFFFF,
        group: 0
}

3、使用這三個屬性,可以設計出很複雜的碰撞關係,其中碰撞規則如下:

物體的 group 相等,且 group > 0 時,則物體之間會發生碰撞;Matter.Body.nextGroup(false)可以生成從-1開始遞減的整數

物體的 group 相等,且 group < 0 時,則物體之間不發生碰撞;Matter.Body.nextGroup(true)可以生成從1開始遞增的整數

--不滿足上述兩種情況時,則根據category和mask進行判斷--
category 代表一個碰撞分類,其值可為1,2,4,8...直到 2^31,mask 為碰撞集合(category集合)

a 和 b碰撞情況:a 的 mask 必須包含 b 的 category,同時 b 的 mask 也必須包含 a 的 category,即
(a.category & b.mask) !== 0 && (b.category & a.mask) !== 0

group 組

通過這個例子就可以直觀的看到到底如何才算是物體碰撞。

<!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 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
                    showBroadphase: false,//是否顯示寬頻,用於除錯,預設false
                    showMousePosition: false // 滑鼠約束線
                }
            });
            Engine.run(engine);//執行引擎
            Render.run(render);//執行渲染器
            /**設定滑鼠控制*/
            var mouseConstraint = MouseConstraint.create(engine, {});

            /**Body.nextGroup(isNonColliding):下一個組ip值,
             * isNonColliding:表示非碰撞,為true時,第一次呼叫 nextGroup 時返回 -1,每呼叫一次則遞減1
             * isNonColliding=false時,第一次呼叫 nextGroup 時返回 1,每呼叫一次則遞加1
             */
            var group = Body.nextGroup(true);
            console.log("group=" + group);
            var stack = Composites.stack(20, 20, 12, 4, 0, 0, function (x, y) {
                switch (Math.round(Common.random(0, 1, 2))) {
                /**為0時建立矩形*/
                    case 0:
                        return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50), {
                            collisionFilter: {group: group}
                        });
                /**為1時建立多邊形*/
                    case 1:
                        return Bodies.polygon(x, y, Math.round(Common.random(3, 8)), Common.random(20, 50), {
                            collisionFilter: {group: group}
                        });
                /**為2時建立圓形*/
                    case 2:
                        return Bodies.circle(x, y, Common.random(10, 20), {
                            collisionFilter: {group: group}
                        });
                }
            });
            /**將物體以及滑鼠控制新增到世界中*/
            World.add(engine.world, [mouseConstraint, stack]);
            /**為世界4周新增4面牆*/
            World.add(engine.world, create4Wall(Bodies));
        }

        /**建立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>

如上所示 collisionFilter: {group: group},因為 Body.nextGroup(true) 只調用了1次,則所有物體的 group 值為-1,此時物體相互之間是沒有碰撞的。

當 var group = Body.nextGroup(false); 時,因為 Body.nextGroup(false) 只調用了1次,則所有物體的 group 值為 1,此時物體相互之間會發生碰撞。