最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 走进MatterJs的核心模块-MatterJs(二)

    正文概述 掘金(起小就些熊)   2021-06-14   781

    走进MatterJs的物理世界

    我们开始之前, 首先思考几个问题:

    1. 为什么被称为物理引擎?
    2. 为什么要使用物理引擎?
    3. 一个物理世界需要什么元素?
    4. 如何用代码实现一个物理引擎?

    一、思考一个物理世界的实现

    为什么被称为物理引擎?

    大家都知道:
    一辆汽车的引擎就是他的发动机, 是控制汽车能够运动的核心.
    搜索引擎就是一系列的算法的集成, 是控制互联网搜索功能的核心.

    物理引擎就是一个虚拟物理世界之所以存在和被使用的控制器. 它可以管理和更新我们的物理世界. 而我们要说的物理引擎就是一个可以模拟真实的物理世界的计算机程序, 一段核心的算法库.

    而这个「物理世界」就是运用计算机程序, 模拟出一个近乎真实的物理系统, 这个系统具备真实世界的一些例如重力、摩擦力和空气阻力等物理力学, 这个是世界中的物体会受到各种力的效果, 从而具有重力、旋转和碰撞等效果.

    在web中我们使用的是实时的物理系统, 减少了算法开支和降低了精确度, 但同样的我们收获了计算机更少的处理时间和更快的计算速度.

    而高精度的物理系统一般用于科学研究领域. (造火星探测器啥的)

    为什么要使用用物理引擎?

    作为一个客户端开发人员, 我们因何要使用物理引擎呢?

    1、开发比较复杂同时需要计算很多物理碰撞的需求
    2、需要实现一些比较真实的场景,比如跳高, 投篮, 投掷标枪等

    这些场景如果给到我们的开发人员, 如果需要写算法一步一步的实现, 那是不是就要耗费很多的时间呢?
    再说, 有能力写算法出来的(此处省略.....)

    所以我们有理由去使用一些优秀的算法库.

    一个物理世界需要什么元素?

    一个比较真实的物理世界需要什么呢?

    • 负责管理和控制物理世界正常运行和更新的控制器
    • 负责人机交互的事件管理器
    • 一系列具有物理属性的物体(刚体)
    • 一些能够随意组合的复合材料集合
    • 一些物理世界的坐标系、旋转轴等
    • 可能还需要一个实时显示的渲染器来显示我们的世界

    这些模块就可以组合出一个生动的物理世界了.

    如何用代码实现一个物理引擎?

    首先, 需要具备优秀的代码开发能力.
    其次, 需要有一定的物理学基础.
    最后, 需要具备一定的CV能力, 好的东西需要借鉴和学习嘛?.
    (笔者也在探索中~~~).

    二、MatterJs的控制核心

    Matter

    Matter是整个MatterJs最顶层的命名空间.
    定义了函数链执行顺序的方法和插件的使用.

    Matter.Engine

    引擎模块
    负责管理物理世界的运行和更新.

    options 一些属性的介绍

    属性名默认值介绍
    positionIterations6每次更新位置迭代次数, 值越大, 效果越好velocityIterations4每次更新速度迭代次数, 值越大, 效果越好constraintIterations2每次更新约束迭代次数, 值越大, 效果越好enableSleepingfalse约定是否可以允许物体休眠events[]事件集合plugin{}插件集合gridnulll网格实例gravity{ x: 0, y: 1, scale: 0.001 }x: 重力在x方向上的分量; y: 重力在y方向上的分量; scale: 重力比例系数timingtiming: {
      timestamp: 0, timeScale: 1,
    lastDelta: 0, lastElapsed: 0
    }
    计时系统属性

    计时系统timing的属性:

    属性名默认值介绍
    timestamp0当前时间戳timeScale1作用于物体上的时间的比例系数, 大于1快速, 小于1慢速, 0会冻结lastDelta0上一次更新时的时间lastElapsed0每次更新耗时, 包括更新和事件处理时间
    var defaults = {
        positionIterations: 6,
        velocityIterations: 4,
        constraintIterations: 2,
        enableSleeping: false,
        events: [],
        plugin: {},
        grid: null,
        gravity: {
            x: 0,
            y: 1,
            scale: 0.001
        },
        timing: {
            timestamp: 0,
            timeScale: 1,
            lastDelta: 0,
            lastElapsed: 0
        }
    };
    

    method 一些方法的探索


    • Engine.create = (options) => {}

    创建一个物理引擎的控制器.

    //参数
    options = {
        positionIterations: 6,
        velocityIterations: 4,
        constraintIterations: 2,
        enableSleeping: false,
        events: [],
        plugin: {},
        grid: null,
        gravity: {
            x: 0,
            y: 1,
            scale: 0.001
        },
        timing: {
            timestamp: 0,
            timeScale: 1,
            lastDelta: 0,
            lastElapsed: 0
        }
    };
    

    • Engine.update = (engine, delta, correction) => {}

    每一帧执行的方法.

    这里每一帧更新的engine, 即上面create创建的控制器.每一帧默认16.666ms执行.
    correction为时间的修正比例, 默认为1, 即不修正每一帧16.6ms

    update就是真正运行物理世界的方法.我们可以在我们的游戏引擎的游戏循环中调用该方法.
    MatterJs中循环方法也是请求序列帧requestAnimationFrame.


    • Engine.merge = (engineA, engineB) => {}

    可以合并两个物理世界.

    使用engineB的世界代替engineA, 同时保留engineA.

    engineA.world = engineB.world;
    Engine.clear(engineA);
    var bodies = Composite.allBodies(engineA.world);
    for (var i = 0; i < bodies.length; i++) {
        var body = bodies[i];
        Sleeping.set(body, false);
        body.id = Common.nextId();
    }
    

    • Engine.clear = (engine) => {}

    清除控制器engine. 同时会清除世界、碰撞对(Pairs)以及网格实例.

    var world = engine.world,
        bodies = Composite.allBodies(world);
    Pairs.clear(engine.pairs);
    Grid.clear(engine.grid);
    Grid.update(engine.grid, bodies, engine, true);
    

    Matter.Events

    事件模块.
    包含事件的监听、移除和触发的方法.


    • Matter.Events.on = (object, eventNames, callback) => {}

    监听某一个对象上派发的事件.

    可以监听多个事件名, 用空格 隔开.


    • Events.off = (object, eventNames, callback) => {}

    移除指定一个或者全部的事件.

    指定移除eventNames的事件回调, 同时移除事件缓存.
    可以移除多个事件名, eventNames用空格 隔开.
    如果不指定事件名, 则会移除对象上的全部事件.


    • Events.trigger = (object, eventNames, event) => {}

    触发一个对象上的名为eventNames的事件.

    指定触发一个对象上名为eventNames的事件, 执行其回调函数.

    Matter.Plugin

    插件模块.
    包含了自定义插件在Matter中注册和安装插件的功能.


    • Plugin.register = (plugin) => {}

    注册一个插件.


    • Plugin.resolve = (dependency) => {}

    解析一个插件.


    • Plugin.use = (module, plugins) => {}

    可以使用顶层空间Matteruse方法来使用此方法.

    module上使用插件plugins.
    Matter.Plugin模块中还有不少不重要的方法就不细讲了, 以后会再讲.
    我们可以使用一些动画插件来扩展Matter.

    Matter.Mouse

    人机交互模块, 鼠标事件和触摸事件.


    • Mouse.create = (element) => {}

    创建一个鼠标事件.
    会返回一个鼠标实例.

    element是鼠标事件挂载的节点.

    options

    属性名默认值介绍
    elementdocument.body鼠标事件挂载节点absolute{ x: 0, y: 0 }绝对位置position{ x: 0, y: 0 }鼠标位置mousedownPosition{ x: 0, y: 0 }鼠标按下位置mouseupPosition{ x: 0, y: 0 }鼠标抬起位置offset{ x: 0, y: 0 }鼠标偏移量scale{ x: 0, y: 0 }鼠标位置比例系数wheelDelta0鼠标转动变量button-1是否按钮, 触摸为0pixelRatio1分辨率

    methods

    • mousemove 鼠标移动事件
    • mousedown 鼠标按下事件
    • mouseup 鼠标抬起事件
    • mousewheel 鼠标换方向事件

    一共四个事件可以被我们监听处理.


    • Matter.Mouse.clearSourceEvents = (mouse) => {}

    清除所有的鼠标事件.

    mouse.sourceEvents.mousemove = null;
    mouse.sourceEvents.mousedown = null;
    mouse.sourceEvents.mouseup = null;
    mouse.sourceEvents.mousewheel = null;
    mouse.wheelDelta = 0;
    
    • Mouse.setElement = (mouse, element) => {}

    设置鼠标事件挂载到哪一个节点.

    同时设置触摸事件与鼠标操作同类型.

    element.addEventListener('touchmove', mouse.mousemove);
    element.addEventListener('touchstart', mouse.mousedown);
    element.addEventListener('touchend', mouse.mouseup);
    

    • Mouse.setOffset = (mouse, offset) => {}

    设置鼠标事件的偏移量.

    mouse.offset.x = offset.x;
    mouse.offset.y = offset.y;
    mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;
    mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;
    

    需要重置position.


    • Mouse.setScale = (mouse, scale) => {}

    设置鼠标的比例系数.

    mouse.scale.x = scale.x;
    mouse.scale.y = scale.y;
    mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;
    mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;
    

    需要重置position.

    一个游戏的玩法很大程度上取决于我们做的人机交互有没有恰到好处.

    Matter.Runner

    物理世界循环模块.
    主要用于开发和调试, 一般我们在使用MatterJs时, 都会配合我们自己的游戏引擎.
    这个时候我们就可以使用我们的游戏循环来达到Matter.Runner的效果.
    这里也例举一下,触类旁通?.

    options

    属性名默认值介绍
    fps60帧率correction1是否修正, 修正系数deltaSampleSize60默认间隔帧counterTimestamp0计时frameCounter0帧数自增deltaHistory[]间隔数组timePrevnull上一个时间timeScalePrev1上一个时间修正frameRequestIdnull请求序列帧的idisFixedfalse是否使用固定间隔时间, 即每一帧间隔时间是否固定enabledtrue是否在进行更新

    method


    • Runner.create = (options) => {}

    这个函数会返回一个Runner实例.

    • Runner.run = (runner, engine) => {}

    这个函数会返回一个Runner实例.
    该方法运行我们创建的engine实例.

    其实这个方法只是在循环致执行Runner.tick(runner, engine, time);

    (function render(time){
        runner.frameRequestId = _requestAnimationFrame(render);
        if (time && runner.enabled) {
            Runner.tick(runner, engine, time);
        }
    })();
    

    • Runner.tick = (runner, engine, time) => {}

    这属于Matterjs的循环机制.
    在进入方法是派发事件beforeTick.
    在计算完之后派发事件tick.
    在引擎更新前派发事件beforeUpdate.
    在引擎更新之后派发事件afterUpdateafterTick.

    其实该方法只是在每一帧执行引擎的循环方法

    Engine.update(engine, delta, correction);
    

    我们如果不用这个方法刷新, 可以在我们自己的循环机制里调用引擎的update方法.


    • Runner.stop = (runner) => {}

    循环方法的停止.


    • Runner.start = (runner, engine) => {}

    循环方法的开始.

    Runner.run(runner, engine);
    

    Matter.Sleeping

    管理刚体睡眠状态的模块.
    在物理世界中, 设置刚体的状态能有效的提升计算力.

    • Sleeping.update = (bodies, timeScale) => {}

    让刚体改变状态的方法.

    主要还是使用Sleeping.set()方法, 改变状态.
    不需要我们主动使用, 我们会在Engine.update时调用.
    前提是我们引擎的enableSleeping(休眠调度器)属性为true.


    • Sleeping.afterCollisions = (pairs, timeScale) => {}

    在碰撞之后唤醒刚体.
    唤醒条件: 非静态刚体

    if (bodyA.isSleeping || bodyB.isSleeping) {
        var sleepingBody = (bodyA.isSleeping && !bodyA.isStatic) ? bodyA : bodyB,
            movingBody = sleepingBody === bodyA ? bodyB : bodyA;
    
        if (!sleepingBody.isStatic && movingBody.motion > Sleeping._motionWakeThreshold * timeFactor) {
            Sleeping.set(sleepingBody, false);
        }
    }
    

    • Sleeping.set = (body, isSleeping) => {}

    设置一个刚体是唤醒状态还是睡眠状态.
    刚体入睡前会触发事件sleepStart, 睡眠之后会触发事件sleepEnd.

    Matter.Common

    通用公共模块.
    这个模块封装了一系列全局使用的方法, 包括继承、克隆、获取键值等方法.
    我们可以去学习它, 但并不是必须的.
    其中的很多方法可以复用和学习:

    /** 颜色转化 css hex colour into an integer **/
    Common.colorToNumber = function(colorString) {
        colorString = colorString.replace('#','');
        if (colorString.length == 3) {
            colorString = colorString.charAt(0) + colorString.charAt(0)
                        + colorString.charAt(1) + colorString.charAt(1)
                        + colorString.charAt(2) + colorString.charAt(2);
        }
        return parseInt(colorString, 16);
    };
    /** 随机数组 **/
    Common.shuffle = function(array) {
        for (var i = array.length - 1; i > 0; i--) {
            var j = Math.floor(Common.random() * (i + 1));
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    };
    

    等等, 就不列举了, 有兴趣可以自己查阅.

    三、总结

    本章节介绍了MatterJs的核心控制模块.
    一共包含7大模块:

    • Matter.Engine 物理世界驱动力
    • Matter.Mouse 鼠标交互事件
    • Matter.Events 事件管理模块
    • Matter.Plugin 可扩展插件
    • Matter.Runner 循环模块
    • Matter.Sleeping 刚体状态管理
    • Matter.Common 通用方法模块

    这些模块就是整个物理引擎的核心模块了.
    这时候我们的物理引擎也出来一个模糊的世界了.
    上面我们多次提到了「刚体」,下一章去我们将开始讲解物理世界中物体存在的模式.


    起源地下载网 » 走进MatterJs的核心模块-MatterJs(二)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元