Laya 物理引擎系列一 matter.js基礎(chǔ)

一、概述

參考Matter.js 2D 物理引擎試玩報告
物理引擎是一個計算機(jī)程序,使用質(zhì)量、速度、摩擦力和空氣阻力等變量,模擬了一個近似真實的物理系統(tǒng),為剛性物體賦予真實的物理效果,比如重力、旋轉(zhuǎn)和碰撞等效果,讓物體的行為表現(xiàn)的更加趨向真實,例如,守望先鋒的英雄在跳起時,系統(tǒng)所設(shè)置的重力參數(shù)就決定了他能跳多高,下落時的速度有多快,子彈的飛行軌跡等等。

matter.js是一個用于 Web 的 JavaScript 2D 物理引擎庫,該項目誕生于 2014 年 2 月 28 號(0.5.0-alpha 版本),目前已更新迭代了 11 個版本(最新為 0.12.0 版本),它相較于老牌的 Box2D 引擎庫,Matter.js 更為輕量級(壓縮版僅有 87 KB),并且在性能和功能方面也不遜色。

參考box2dweb和p2js性能差別有多大?
這段時間我試用了box2dweb,p2js,matterjs。
從功能來說:box2dweb > p2js > matterjs
從API友好性和社區(qū)活躍度來說 box2dweb < p2js < matterjs
性能上:box2dweb < p2js ≈ matterjs
p2js其實挺好的,就是文檔太少,很多情況需要看源碼
參考Egret Matter.js庫集成教程
egret支持的p2雖然方便,但是坑太多,剛體碰撞出錯,剛體穿透時常發(fā)生,社區(qū)也不活躍,資料少,還因為物理效果欠佳,搞得本人的單子涼了,煮熟的鴨子飛了。實在是氣不過,不過不去尋求新的物理引擎,那么matter.js成了最好的選擇??上]有現(xiàn)成的egret支付庫使用。論壇里早有大神轉(zhuǎn)投matter.js了,但都沒有放出代碼,只是偶有提及matter.js真NM好用。沒辦法,只好親自動手了。

在沒有 Matter.js 前,你想去制作一個物理游戲不僅需要扎實數(shù)學(xué)知識和物理知識,并且需要通過編程語言表示出來讓機(jī)器讀懂。而有 Matter.js 就不一樣了,它為開發(fā)者提供了許多的功能模塊,通過簡單易用的 API 就可以實現(xiàn)例如彈跳、碰撞、重力、滾動等物理效果。

在2018.09.15發(fā)布的Laya2.0中,官方內(nèi)置了Box2D

LayaAir1.0采用了輕量級的Matter物理引擎,雖然體積較小,但隨著小游戲的開放,越來越多的游戲需要物理引擎的支持,產(chǎn)生出大量的新需求,例如Matter精度不是很高、沒有防穿透支持等等,對于物理引擎需求較高的一些小游戲上,Matter物理引擎的壓力越來越大。
因此LayaAir引擎組基于市場需求出發(fā)重新評估了主流的物理引擎。最終選定并內(nèi)置了相對最為完善的Box2D物理引擎,封裝了物理組件,提供了IDE物理屬性的可視化編輯,還讓制作物理游戲更加方便快捷。
當(dāng)然,采用Box2D物理引擎后,引擎體積也會增加一些。如果對于物理引擎功能需求較為簡單,并且希望能減小引擎體積的情況下,仍然可以使用Matter物理引擎。

**

二、使用實例

參考matter.js學(xué)習(xí)筆記(一)

<script type="text/javascript" src="matter.js"></script>
<script>
//Engine是引擎,Render是渲染器,World是表演環(huán)境,Bodies可以用來創(chuàng)建各種形狀的物體。
var Engine = Matter.Engine,
    Render = Matter.Render,
    World = Matter.World,
    Bodies = Matter.Bodies;

var engine = Engine.create();
//render(渲染器)將要渲染的物理引擎是之前所創(chuàng)建的engine,而渲染的對象是html網(wǎng)頁的body
var render = Render.create({
    element: document.body,
    engine: engine
});

//參數(shù)(500,170,40,260)中,前兩個是物體坐標(biāo),后兩個分別是寬度和長度。 
//需要注意的是,這里的坐標(biāo)系統(tǒng)中,500和170是矩形的中心所在位置
//而html的canvas中坐標(biāo)描述的是矩形的左上角。
var boxA = Bodies.rectangle(200, 200, 80, 80);
//var boxB = Bodies.rectangle(450, 50, 80, 80);
//將isStatic設(shè)為true,即是靜止的
var ground = Bodies.rectangle(400, 510, 810, 60, { isStatic: true });

// add all of the bodies to the world
World.add(engine.world, [boxA, ground]);
Engine.run(engine);
Render.run(render);
</script>

1.Engine(引擎)和 World(世界)
Matter.Engine 模塊包含了創(chuàng)建和處理引擎的方法,引擎是負(fù)責(zé)管理和更新模擬世界的控制器,引擎可以控制時間的縮放,可以檢測所有的碰撞事件,并且拿到所有碰撞的物體對(pairs)。

在 Matter.js 中任何的物體都需要一個容身處,而存放這些物體的地方,我們稱之為世界,物體必須添加到世界里,然后由引擎運(yùn)行這個世界。而創(chuàng)建世界需要使用到 Matter.World 模塊,該模塊包含了用于創(chuàng)建和操作世界的方法,一個 Matter.World 相當(dāng)于一個復(fù)合物體,物體、約束、復(fù)合物體的聚合體,其次世界還有額外的一些屬性,比如重力、邊界。

Matter.Render 是將實例渲染到 Canvas 中的渲染器,控制視圖層的樣式,它的主要作用是用于開發(fā)和調(diào)試,默認(rèn)情況下 Matter.Render 將只顯示物體的線框(輪廓),這對于開發(fā)和調(diào)試很有幫助,但如果需要使用到全局實體渲染則需要將線框模式關(guān)閉 render.options.wireframes = false,另外它同樣也適合制作一些簡單的游戲,因為它包括了一些繪圖選項、線框、向量、Sprite 精靈和視窗功能。

image.png

2.Body(剛體)

物體或者叫剛體,在物理引擎里特指堅硬的物體,具有固定的形狀,不能形變。剛體可以用于表示一個箱子、一個球或是一塊木頭,每個物體都有自己的物理屬性,質(zhì)量、速度、摩擦力、角度等,還可以設(shè)置剛體的標(biāo)記。Matter.Bodies 模塊中內(nèi)置了幾種剛體,矩形 Matter.rectangle、多邊形 Matter.polygon、圓形 Matter.circle 、梯形 Matter.trapezoid 等等。

// 創(chuàng)建剛體
var 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]);

參考matter.js學(xué)習(xí)筆記(九)--Body的parts屬性創(chuàng)造十字形物品

    //添加鼠標(biāo)控制
    var mouseConstraint=MouseConstraint.create(engine,{});
    var boxA=Bodies.rectangle(300,300,500,100),
        boxB=Bodies.rectangle(300,300,100,500);
    //Body.create() 會生成物體,如果不傳入?yún)?shù),
    //會在(0,0)處生成一個物體。傳入?yún)?shù)parts,
    //將兩個部分結(jié)合生成新的物體
    var cup=Body.create({
        parts:[boxA,boxB]
    });

    World.add(world,[cup,mouseConstraint]);

3.Composite(復(fù)合體)

由剛體和復(fù)合材料通過約束組合在一起的就叫做復(fù)合體。復(fù)合體對外當(dāng)作一個剛體,復(fù)合體的物理屬性是通過所包含的剛體的屬性綜合計算出來的。Matter.Composite 模塊包含用于創(chuàng)建和處理復(fù)合體的方法,另外還有一個 Matter.Composites 模塊,提供了幾種特別的復(fù)合材料,例如 鏈 Composites.chain、牛頓擺球 Composites.newtonsCradle、軟體 Composites.softBody、汽車 Composites.car 、堆疊 Composites.stack 等等。
參考matter.js學(xué)習(xí)筆記(二)--Composites.stack()分析

<script type="text/javascript" src="matter.js"></script>
<script>
//Engine是引擎,Render是渲染器,World是表演環(huán)境,Bodies可以用來創(chuàng)建各種形狀的物體。
var Engine = Matter.Engine,
    Render = Matter.Render,
    World = Matter.World,
    Composites=Matter.Composites,
    Bodies = Matter.Bodies;

var engine = Engine.create(),
world=engine.world;

//render(渲染器)將要渲染的物理引擎是之前所創(chuàng)建的engine,而渲染的對象是html網(wǎng)頁的body
var render = Render.create({
    element: document.body,
    engine: engine
});

Engine.run(engine);
Render.run(render);

//第一個物體在位置(50,100),共6列3行,每個物體為長50寬20的矩形所夠成的物體堆
var stack=Composites.stack(50,100,6,3,0,0,function (x,y) {
        return Bodies.rectangle(x,y,50,20);
    });
//生成每個物體為圓的堆
var stack_circle=Composites.stack(80,100,7,5,0,0,function (x,y) {
        return Bodies.circle(x,y,20);
    });
var ground=Bodies.rectangle(500,500,1000,100,{isStatic:true});
World.add(world,[stack,stack_circle,ground]);

</script>

參考matter.js學(xué)習(xí)筆記(五)--Composites.chain()制造鐵索橋
Composites.chain()可以將已有的stack物體堆鏈接在一起,構(gòu)成一個整體,里面的參數(shù)為已有的物體堆stack,鏈接點距離物體中心的x和y方向的偏移量。
Composites.chain = function(composite, xOffsetA, yOffsetA, xOffsetB, yOffsetB, options)
參數(shù)composite即為傳入的物體堆,從第一個物體開始,到倒數(shù)第二個物體截止,每個物體和下一個物體鏈接。
xOffsetA, yOffsetA為每對鏈接的第一個物體的鏈接點距離中心位置的偏移百分比,之所以是百分比,是因為pointA: { x: bodyAWidth * xOffsetA, y: bodyAHeight * yOffsetA },pointA的x和y屬性為實際的偏移量,是由物體的實際寬度乘以偏移百分比而得到。

    var Engine=Matter.Engine,
        Render=Matter.Render,
        World=Matter.World,
        Constraint=Matter.Constraint,
        MouseConstraint=Matter.MouseConstraint,
        Composites=Matter.Composites,
        Bodies=Matter.Bodies;

    var engine=Engine.create(),
        world=engine.world;

    var render=Render.create({
       engine:engine,
       element:document.body,
       options:{
           width:$(window).width(),
           height:$(window).width(),
           wireframes:false
       }
    });

    Engine.run(engine);
    Render.run(render);

    var rectA=Bodies.rectangle(333,$(window).height()-100,40,200,{
        isStatic:true,
        render:{
            fillStyle:"#f00"
        },
        collisionFilter:{
            group:-1
        }
    });
    var rectB=Bodies.rectangle(333,$(window).height()-180,400,40,{
        render:{
            fillStyle:"#00f"
        },
        collisionFilter:{
            group:-1
        }
    });
    var rotate=Constraint.create({
        bodyA:rectA,
        pointA:{x:0,y:-80},
        bodyB:rectB,
        length:0,
        stiffness:0.9
    });
    console.log(rotate.bodyA);

    var ground=Bodies.rectangle($(window).width()/2,
     $(window).height()-10,$(window).width(),20,{
        isStatic:true,
        render:{
            fillStyle:"#9fa"
        }
    });

    var stack_rect=Composites.stack(300,100,4,3,0,0,function(x,y){
        return Bodies.rectangle(x,y,150,40);
    });
    var stack_circle=Composites.stack(1200,10,1,5,2,8,function (x,y) {
        return Bodies.circle(x,y,30);
    });

    //創(chuàng)造兩個橋墩
    var wallA=Bodies.rectangle(630,730,50,400,{isStatic:true});
    var wallB=Bodies.rectangle(1580,730,50,400,{isStatic:true});

    //橋上的木板 參數(shù)分析。這里的666和600分別是第一塊木板的x和y坐標(biāo),
    //10和1分別為10列1行,9和0分別為每塊木板之間的列間隙和行間隙,
    //chamfer:15 將矩形添加圓角。
    var chains=Composites.stack(666,600,10,1,9,0,function (x, y) {
        return Bodies.rectangle(x,y,80,30,{
            chamfer:15
        })
    });

    //三條鏈接鐵索,將第一條鐵索復(fù)制,并分別改變縱向的偏移百分比即可
    //chains為木板堆,
    //第一個鏈接點在橫向上距離木板中心有向右的寬度的0.4倍的偏移量,
    //縱向上與木板中心平行。
    //第二個鏈接點在橫向上距離木板中心有向左的寬度的0.4倍的偏移量,
    //縱向上與木板中心平行。
    Composites.chain(chains,0.4,0,-0.4,0,{});
    Composites.chain(chains,0.4,0.3,-0.4,0.3,{});
    Composites.chain(chains,0.4,-0.3,-0.4,-0.3,{});

    //左側(cè)固定在橋墩上
    var fixLeft=Constraint.create({
       bodyA:wallA,
       pointA:{x:0,y:-90},
       bodyB:chains.bodies[0],
       pointB:{x:-25,y:0}
    });
    //右側(cè)固定在橋墩上
    var fixRight=Constraint.create({
        bodyA:chains.bodies[chains.bodies.length-1],
        pointA:{x:25,y:0},
        bodyB:wallB,
        pointB:{x:0,y:-90}
    });

    var mouseConstraint=MouseConstraint.create(engine,{
        element:document.body
    });

    World.add(world,[rectA,rectB,ground,stack_rect,stack_circle,mouseConstraint,rotate]);
    //橋墩,鐵索固定的木板加入到世界中
    World.add(world,[wallA,wallB,chains,fixLeft,fixRight]);

參考matter.js學(xué)習(xí)筆記(六)--Composites.softBody()制造布料或球網(wǎng)
softBody,顧名思義,創(chuàng)造出軟體。Creates a simple soft body like object。

var Engine=Matter.Engine,
        Render=Matter.Render,
        World=Matter.World,
        Bodies=Matter.Bodies,
        Composites=Matter.Composites,
        Constraint=Matter.Constraint,
        MouseConstraint=Matter.MouseConstraint;

    var engine=Engine.create(),
        world=engine.world;

    var render=Render.create({
        engine:engine,
        element:document.body,
        options:{
            width:$(window).width(),
            height:$(window).height(),
            wireframes:false
        }

    });

    Engine.run(engine);
    Render.run(render);

    //添加鼠標(biāo)控制
    var mouseConstraint=MouseConstraint.create(engine,{});
    
    //第一個物體中心在(100,100)坐標(biāo)處,創(chuàng)造出的球形共6列10行,
    //行間隙和列間隙都為2,球半徑為22,為了隱藏這些球,
    //將particleOptions參數(shù)的render屬性的visible屬性設(shè)為false。
    //將collisionFilter屬性的group屬性設(shè)為-1,
    //可以避免這些球之間相互碰撞。
    //constraintOptions屬性傳入空對象,設(shè)為默認(rèn)。
    var cloth=Composites.softBody(100,100,6,10,2,2,false,22,{
        render:{
            visible:false
        },
        collisionFilter:{
            group:-1
        }
    },{});
    //將最上方的6個球固定。
    for(var i=0;i<6;i++){
        cloth.bodies[i].isStatic=true;
    }
    var ground=Bodies.rectangle(600,700,1800,100,{
        isStatic:true
    });

    World.add(world,[ground,cloth,mouseConstraint]);

參考matter.js學(xué)習(xí)筆記(七)--Composites.car()制造汽車
內(nèi)置Composites.car()函數(shù),可以生成簡易小車。由一個矩形和兩個圓形構(gòu)成。兩個圓形的圓心在矩形的兩條寬的中心。

    //前兩個參數(shù)為小車中心的x坐標(biāo)和y坐標(biāo)。
    //第三個和第四個參數(shù)為矩形車身的長和寬。
    //最后的參數(shù)為輪子的半徑。
    var audi=Composites.car(300,100,200,50,50);
    //audi.bodies[0].render.showAngleIndicator=true;

    //生成兩個斜面與地面
    var ground=Bodies.rectangle(800,900,1800,100,{
        isStatic:true
    });
    var stickA=Bodies.rectangle(400,400,50,700,{
        isStatic:true,
        angle:-Math.PI*0.4
    });
    var stickB=Bodies.rectangle(700,700,50,700,{
        isStatic:true,
        angle:Math.PI*0.4
    });

參考matter.js學(xué)習(xí)筆記(八)--Composites.newtonsCradle()制造牛頓擺
Composites.newtonsCradle()為內(nèi)置函數(shù),可以生產(chǎn)牛頓擺。

    //前兩個參數(shù)為第一個擺的懸掛點的橫縱坐標(biāo)值,
    //7為擺球數(shù)量,50為擺球半徑,500為懸掛繩的長度
    var newtonC=Composites.newtonsCradle(600,100,7,50,500);

    World.add(world,[newtonC,mouseConstraint]);

參考matter.js學(xué)習(xí)筆記(九)--Body的parts屬性創(chuàng)造十字形物品

4.Constraint(約束)
約束可理解為通過一條線,將剛體 A 和剛體 B 兩個剛體連接起來,被約束的兩個剛體由于被連接在了一起,移動就相互受到了限制。Matter.Constraint 模塊包含了用于創(chuàng)建和處理約束的方法,這個約束可以很寬松,也可以很緊繃,還可以定義約束的距離,約束具有彈性,可以用來當(dāng)作橡皮筋。
參考matter.js學(xué)習(xí)筆記(四)--Constraint.create()制造蹺蹺板
制造蹺蹺板有兩個關(guān)鍵點,一是設(shè)置兩塊板子不能互相碰撞,二是一個板子要固定,另外一個要可以自由活動,并且中心點固定。

    var Engine=Matter.Engine,
        Render=Matter.Render,
        World=Matter.World,
        Vector=Matter.Vector,
        Constraint=Matter.Constraint,
        MouseConstraint=Matter.MouseConstraint,
        Composites=Matter.Composites,
        Bodies=Matter.Bodies;

    var engine=Engine.create(),
        world=engine.world;

    var render=Render.create({
       engine:engine,
       element:document.body,
       options:{
           width:$(window).width(),
           height:$(window).width(),
           wireframes:false
       }
    });

    Engine.run(engine);
    Render.run(render);

    //為了設(shè)置兩塊板子呈分離狀態(tài),即不能互相碰撞,需要設(shè)置collisionFilter:{ group:-1 } 
    //字面上理解為碰撞過濾器,它可以設(shè)置哪些物體可以互相碰撞,哪些不能互相碰撞,
    //兩個物體的collisionFilter屬性的group屬性都設(shè)為-1,則這兩個物體不會發(fā)生碰撞。
    var rectA=Bodies.rectangle(666,$(window).height()-100,40,200,{
        isStatic:true,//靜止
        render:{
            fillStyle:"#f00"http://設(shè)為紅色
        },
        collisionFilter:{
            group:-1
        }
    });
    var rectB=Bodies.rectangle(666,$(window).height()-180,400,40,{
        render:{
            fillStyle:"#00f"http://設(shè)為藍(lán)色
        },
        collisionFilter:{
            group:-1
        }
    });
    //Constraint.create()需要的參數(shù)主要有:bodyA,pointA,bodyB,pointB,length,stiffness. 
    //在蹺蹺板案例中,bodyA和bodyB分別為兩個板子,pointA和pointB為兩個向量,如果不賦值
        //,則默認(rèn)為0向量,物體的約束點默認(rèn)在中心位置,否則,物體的對應(yīng)的約束點為中心位置加上所賦的向量值。 
    //物體rectA 的約束點設(shè)置在其中心位置向上平移80的位置,此位置也是物體rectB的中心位置,pointB未設(shè)置,默認(rèn)為{x:0,y:0}
    var rotate=Constraint.create({
        bodyA:rectA,
        pointA:{x:0,y:-80},
        bodyB:rectB,
        length:0,
        stiffness:0.9
    });

    var ground=Bodies.rectangle($(window).width()/2,$(window).height()-10,$(window).width(),20,{
        isStatic:true,
        render:{
            fillStyle:"#9fa"
        }
    });

    var stack_rect=Composites.stack(300,100,4,3,0,0,function(x,y){
        return Bodies.rectangle(x,y,150,40);
    });
    var stack_circle=Composites.stack(1200,100,1,5,2,3,function (x,y) {
        return Bodies.circle(x,y,30);
    });

    var mouseConstraint=MouseConstraint.create(engine,{
        element:document.body
    });

    World.add(world,[rectA,rectB,ground,stack_rect,stack_circle,mouseConstraint,rotate]);

5.MouseConstraint(鼠標(biāo)約束)
如果你想讓剛體與用戶之間有交互,那就要在鼠標(biāo)和剛體之間建立連接,也就是鼠標(biāo)和剛體間的約束,Matter.MouseConstraint 模塊包含用于創(chuàng)建鼠標(biāo)約束的方法,提供通過鼠標(biāo)或觸摸(移動端時)移動剛體的能力,可以設(shè)置什么標(biāo)記的物體才能被鼠標(biāo)操縱,創(chuàng)建鼠標(biāo)約束后,可以捕獲到鼠標(biāo)的各類事件。

// 全局鼠標(biāo)約束
var mouseConstraint = MouseConstraint.create({
    element: render.canvas
});
World.add(engine.world, mouseConstraint);

// 設(shè)置某個標(biāo)記的物體才能被鼠標(biāo)操縱
var categoryBall = 0x0001; // 分類
var ball = Matter.Bodies.circle(300, 350, 32, {
    density: 0.68, // 密度
    restitution: 1, // 彈性
    collisionFilter: {
        category: categoryBall
    }
});
var mouseConstraint = MouseConstraint.create({
    element: render.canvas,
    collisionFilter: {
        mask: categoryBall
    }
});
World.add(engine.world, mouseConstraint);

這里有個更詳細(xì)的例子,參考matter.js學(xué)習(xí)筆記(三)--mouseConstraint鼠標(biāo)控制。在這個例子中,也可以學(xué)到控制顏色和全屏:
為render的options添加wireframes:false可以為世界里的物品添加顏色,如果不對物品設(shè)置渲染顏色的話,引擎會默認(rèn)物體顏色隨機(jī)。如果要指定物體的顏色,可以在生成物體時設(shè)置render:render:{fillStyle:"#9fa"}。

在生成render時,可以設(shè)置options選項,其中,有width和height屬性,分別設(shè)置為$(window)的width()和height()即可。同時,要對body設(shè)置style:

body{
   margin:0;
   overflow: hidden;
}

代碼全文如下:

<script type="text/javascript" src="matter.js"></script>
<script type="text/javascript" src="
https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <style>
        body{
            margin:0;
            overflow: hidden;
        }
    </style>
<script>
    var Engine=Matter.Engine,
        Render=Matter.Render,
        World=Matter.World,
        Mouse=Matter.Mouse,
        MouseConstraint=Matter.MouseConstraint,
        Composites=Matter.Composites,
        Bodies=Matter.Bodies;

    var engine=Engine.create(),
        world=engine.world;

    var render=Render.create({
       engine:engine,
       element:document.body,
       options:{
           width:$(window).width(),
           height:$(window).width(),
           wireframes:false
       }
    });

    Engine.run(engine);
    Render.run(render);

    var rectA=Bodies.rectangle(100,20,200,40,{
        render:{
            fillStyle:"#f0c"
        }
    });
    var ground=Bodies.rectangle($(window).width()/2,
    $(window).height()-10,$(window).width(),20,{
        isStatic:true,
        render:{
            fillStyle:"#9fa"
        }
    });

    var stack_rect=Composites.stack(300,100,4,3,0,0,function(x,y){
        return Bodies.rectangle(x,y,150,40);
    });
    var stack_circle=Composites.stack(600,100,5,5,2,3,function (x,y) {
        return Bodies.circle(x,y,30);
    });

    var mouseConstraint=MouseConstraint.create(engine,{});

    World.add(world,[rectA,ground,stack_rect,stack_circle,mouseConstraint]);
</script>

6.Vector(向量)

Matter.Vector 模塊包含用于創(chuàng)建和操縱向量的方法,向量是引擎有關(guān)幾何操作行為的基礎(chǔ),修改物體的運(yùn)動狀態(tài)基本都是使用向量來控制,例如賦予物體一個力,或者設(shè)置物體的速度、旋轉(zhuǎn)角度,并且內(nèi)置了多個向量的求解函數(shù):向量積、標(biāo)量積、格式化、垂直向量等等。

7.Events(事件)
Matter.Events 模塊包含了綁定、移除和觸發(fā)對象的方法。

  • 綁定事件 Matter.Events.on(object, eventNames, callback)
  • 移除事件 Matter.Events.off(object, eventNames, callback)
  • 觸發(fā)事件 Matter.Events.trigger(object, eventNames, event)

8.施加力

Matter.Body.applyForce(body, position, force) 方法可以給剛體施加一個力,傳入 X 和 Y 軸需要的力度值,通過這個方法你可以去模擬踢一個足球、投一個籃球的效果。

var ball = Bodies.circle(300, 100, 25, {
    density: 0.68, // 密度
    restitution: 0.8 // 彈性
});
World.add(engine.world, ball);
function addForce() {
    var 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();

9.重力
可以設(shè)置 X、Y 軸的重力值,默認(rèn)都為 1,參數(shù)在 0、1、-1 中選擇使用。

// 實現(xiàn)反重力效果
engine.world.gravity.y = -1;
// 無重力效果
engine.world.gravity.y = 0;

10.睡眠狀態(tài)

通過 enableSleeping: true 開啟睡眠模式后,當(dāng)剛體處于不受作用狀態(tài)時,會進(jìn)入睡眠狀態(tài),這樣可以有效的提高引擎的性能,當(dāng)物體被其他物體碰撞或者對剛體施加力時,剛體會被叫醒,引擎會繼續(xù)對其進(jìn)行計算模擬。

// 開啟睡眠狀態(tài)
var engine = Engine.create({
    enableSleeping: true
});
// 還可以針對進(jìn)入睡眠狀態(tài)的剛體進(jìn)行監(jiān)聽,比如將剛體移出世界
Event.on(ball, "sleepStart", function() {
    World.remove(engine.world, ball);
});

11.摩擦力
摩擦力在 Matter.js 中分別提供了三種:摩擦力 friction、空氣摩擦力 frictionAir 以及靜止摩擦力 frictionStatic。friction 默認(rèn)值是 0.1,取值范圍在 0 - 1,當(dāng)值為 0 意味著剛體可以摩擦力的無限滑動,1 意味著對剛體施加力后會立刻停止,frictionAir 默認(rèn)值是 0.01,取值范圍 0 - 1,當(dāng)值為 0 意味著剛體在空間中移動時速度永遠(yuǎn)不會減慢,值越高時剛體在空間的移動速度越慢,frictionStatic 默認(rèn)值 0.5,當(dāng)值為 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
})

12.時間縮放
可以控制全局的時間,當(dāng)值為 0 時為凍結(jié)模擬,值為 0.1 給出慢動作效果,值為 1.2 時給出加速效果。

engine.timing.timeScale = 0.1;

13.Matter.js 調(diào)試
除了前面講 Matter.Render 模塊的時候提到的線框模式 wireframes 便于調(diào)試外,Matter.Render 模塊其實還為我們提供了以下幾種方法,便于我們自定義調(diào)試選項:

var render = Render.create({
    element: document.body,
    engine: engine,
    options: {
        width: 800,
        height: 600,
        pixelRatio: 1, // 設(shè)置像素比
        background: '#fafafa', // 全局渲染模式時背景色
        wireframeBackground: '#222', // 線框模式時背景色
        hasBounds: false,
        enabled: true,
        wireframes: true, // 線框模式
        showSleeping: true, // 剛體睡眠狀態(tài)
        showDebug: false, // Debug 信息
        showBroadphase: false, // 粗測階段
        showBounds: false, // 剛體的界限
        showVelocity: false, // 移動剛體時速度
        showCollisions: false, // 剛體碰撞點
        showSeparations: false, // 剛體分離
        showAxes: false, // 剛體軸線
        showPositions: false, // 剛體位置
        showAngleIndicator: false, // 剛體轉(zhuǎn)角指示
        showIds: false, // 顯示每個剛體的 ID
        showVertexNumbers: false, // 剛體頂點數(shù)
        showConvexHulls: false, // 剛體凸包點
        showInternalEdges: false, // 剛體內(nèi)部邊界
        showMousePosition: false // 鼠標(biāo)約束線
    }
});

14.參考Matter.js設(shè)置碰撞規(guī)則
Matter相互碰撞提供了collisionFilter屬性,支持三種屬性,分別是

  • group
  • category
  • mask

使用三種屬性,就能設(shè)計出很復(fù)雜的碰撞關(guān)系。其中規(guī)則如下:

第一種情況,在兩個group相等的前提下,如果任意group大于零,則兩者始終碰撞,比如大家都是1,這大家相互直接始終碰撞;如果任意group小于0,比如大家都是-1,則大家永遠(yuǎn)也不碰撞。除上述兩種情況,則根據(jù)category和mask進(jìn)行判定

第二張情況,在兩個group不相等的前提下,根據(jù)category和mask進(jìn)行判定,category,mask判定規(guī)則:
category代表一個碰撞分類,其值可為1,2,4,8...直到 2^31,每個剛體設(shè)置一個值
mask為碰撞集合(category集合),是category相與的結(jié)果值,比如接受2,4類型,其值為6

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

總結(jié)如下:
簡單的碰撞關(guān)系,直接設(shè)置group即可。復(fù)雜的碰撞關(guān)系,可以通過設(shè)置category和和mask值進(jìn)行搭配,做出很高級的碰撞關(guān)系

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容