美文网首页
laya2.0 box2d系列三 关节

laya2.0 box2d系列三 关节

作者: 合肥黑 | 来源:发表于2019-01-17 09:55 被阅读36次
    一、基础概念

    参考拉小登博客 初识Box2D关节b2Joint

    1.刚体rigidbody :刚体是指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体。可参考laya2.0 box2d系列一 基础概念和刚体

    2.碰撞体collider:碰撞体是给物体加一个判定框,当碰撞框重叠的时候,两物体发生碰撞。碰撞体是检测物理碰撞的框架,他永远跟随物体的刚体移动,不会产生偏差。碰撞体有四种:矩形碰撞体,圆形碰撞体,线形碰撞体,多边形碰撞体。每个碰撞体都是继承自碰撞体基类。可参考laya2.0 box2d系列二 碰撞体

    3.关节joint:关节可以对两个或多个物体进行一种约束。

    • JointBase->Component 关节基类
    • DistanceJoint 距离关节:两个物体上面各自有一点,两点之间的距离固定不变
    • GearJoint 齿轮关节:用来模拟两个齿轮间的约束关系,齿轮旋转时,产生的动量有两种输出方式,一种是齿轮本身的角速度,另一种是齿轮表面的线速度
    • MotorJoint 马达发动机关节:用来限制两个刚体,使其相对位置和角度保持不变
    • MouseJoint 鼠标关节:鼠标关节用于通过鼠标来操控物体。它试图将物体拖向当前鼠标光标的位置。而在旋转方面就没有限制。
    • PrismaticJoint 平移关节:移动关节允许两个物体沿指定轴相对移动,它会阻止相对旋转
    • PulleyJoint 滑轮关节:它将两个物体接地(ground)并彼此连接,当一个物体上升,另一个物体就会下降
    • RevoluteJoint 旋转关节:旋转关节强制两个物体共享一个锚点,两个物体相对旋转
    • RopeJoint 绳索关节:限制了两个点之间的最大距离。它能够阻止连接的物体之间的拉伸,即使在很大的负载下
    • WeldJoint 焊接关节:焊接关节的用途是使两个物体不能相对运动,受到关节的限制,两个刚体的相对位置和角度都保持不变,看上去像一个整体
    • WheelJoint 轮子关节:围绕节点旋转,包含弹性属性,使得刚体在节点位置发生弹性偏移
    image.png

    在医学上,骨与骨之间连接的地方称为关节。在Box2D中,刚体与刚体之间连接的线段叫做关节,不难理解吧。实际上,刚体可以看做是骨头,不过医学上的骨头都是同轴的,也就是说,它们都围着同一点旋转,不信看看你自己的手腕、膝盖、手指,哈哈。如果你发现自己的两个骨头不是围着同一个轴旋转,赶紧去医院,因为你脱臼了!!Box2D中的关节就没那么多限制了,可以是同轴,也可以是’脱臼”。

    要创建b2Joint实例,首先要创建b2JointDef关节需求,这一点跟b2Body的创建过程是类似的;然后调用initialize()函数设置并实例化关节;b2JointDef有很多的子类(如b2DistanceJointDef, b2FrictionJointDef, b2GearJointDef, b2LineJointDef等等),这些子类都继承了initialize()方法,它们也都用这个方法来创建,不过,需要根据具体的关节需求,设置一些特殊的属性

    二、laya实现

    1.JointBase

    override protected function _onEnable():void {
        _createJoint();
    }
    
    override protected function _onAwake():void {
        _createJoint();
    }
    
    protected function _createJoint():void {
    }
    

    都留着子类去重写了

    2.DistanceJoint 参考官方文档 物理一 距离关节

    image.png
    通过固定长度的关节将两刚体联系到一起,使这两个刚体始终保持一定的距离。用于木棍,骨骼,弹簧一样的约束关系。
    image.png
    • otherBody
      [首次设置有效]关节的连接刚体,可不设置,默认为左上角空刚体。

    • otherAnchor
      [首次设置有效]链接刚体链接点,是相对于otherBody的左上角位置偏移。

    • selfAnchor
      [首次设置有效]自身刚体链接点,是相对于自身刚体的左上角位置偏移。

    • frequency
      弹簧系统的震动频率,可以视为弹簧的弹性系数

    • damping
      刚体在回归到节点过程中受到的阻尼,建议取值0~1。

    • length
      约束的目标静止长度。

    • collideConnect
      [首次设置有效]两个刚体是否可以发生碰撞,默认为false。(截图为true注意不要混淆)

    官方的例子也很好理解,如果设置其中一个kinematic,不受重力影响,就会固定在一点,成为一个钟摆;如果都是动态的,则会掉下来,看起来像是自行车的两个轮子。

    3.MouseJoint鼠标关节
    可以点击刚体,然后把它拖走。拖走之后,不松鼠标,停下来时,能看到鼠标吸附在刚体的那个位置,它就是anchor属性,表示关节的链接点。这是一个x,y属性值 ,表示相对于自身刚体左上角的位置偏移,如果不设置则鼠标点到刚体哪里,连接点就是哪里。注意这个值是laya坐标值。

    override protected function _createJoint():void {
        if (!_joint) {
            selfBody ||= owner.getComponent(RigidBody);
            if (!selfBody) throw "selfBody can not be empty";
            
            var box2d:* = window.box2d;
            var def:* = _temp || (_temp = new box2d.b2MouseJointDef());
            if (anchor) {
                var anchorPos:Point = Sprite(selfBody.owner).localToGlobal(
                    Point.TEMP.setTo(anchor[0], anchor[1]), false, Physics.I.worldRoot);
            } else {
                anchorPos = Physics.I.worldRoot.globalToLocal(
                    Point.TEMP.setTo(Laya.stage.mouseX, Laya.stage.mouseY));
            }
            var anchorVec:* = new box2d.b2Vec2(
                anchorPos.x / Physics.PIXEL_RATIO, anchorPos.y / Physics.PIXEL_RATIO);
            def.bodyA = Physics.I._emptyBody;
            def.bodyB = selfBody.getBody();
            def.target = anchorVec;
            def.frequencyHz = _frequency;
            def.damping = _damping;
            def.maxForce = _maxForce;
            _joint = Physics.I._createJoint(def);
        }
    }
    

    拉小登博客 让刚体听我的——鼠标拖动Box2D刚体使用了b2World世界的QueryPoint方法,来编历world中所有的刚体,判断p点是否在刚体上。如果是,则将刚体对应的b2Fixture传入到callBack函数中。然后我可以利用b2Fixture.GetBody()方法获取刚体,具体代码如下:

    private function getBodyAtMouse():b2Body
    {
        //转换鼠标坐标单位,除以30从m该为px
        var mouseVector:b2Vec2 = new b2Vec2(mouseX / 30, mouseY / 30);
        //鼠标下的刚体
        var bodyAtMouse:b2Body = null;
        //queryPoint函数中要用到的回调函数,注意,它必须有一个b2Fixture参数
        function callBack(fixture:b2Fixture):void {
            if ( fixture == null) return;
            //如果fixture不为null,设置为鼠标下的刚体
            bodyAtMouse = fixture.GetBody();
        }
        //利用QueryPoint方法查找鼠标滑过的刚体
        world.QueryPoint(callBack, mouseVector);
        //返回找到的刚体
        return bodyAtMouse;
    }
    

    4.RevoluteJoint 旋转关节
    参考拉小登博客 Box2D 关节——”马达关节” b2RevoluteJoint
    注:虽然 拉小登 在说马达关节,其实在laya中对应的是旋转关节。
    “马达关节”b2RevoluteJoint同样连接了两个刚体bodyA和bodyB。它只有一个节点anchor,所以两个刚体都只能围绕这一个节点选择。另外,我们可以在这个节点anchor位置施加一个作用力maxMotorTorque,这样节点就会想马达一样转起来,所以我把它叫做”马达关节”。还是不好理解,对吧!那就再打个比方,我把b2RevoluteJoint关节比作….电风扇。风扇叶是bodyA,马达是anchor,底座是bodyB,下面的图可以更好的解释这一点:

    image.png
    revoluteJoint.Initialize( bodyA, bodyB, new b2Vec2(posA.x / 30, posA.y / 30));
    在LAYA中是这样封装的:
    //if (!otherBody) throw "otherBody can not be empty";
    selfBody ||= owner.getComponent(RigidBody);
    if (!selfBody) throw "selfBody can not be empty";
    
    var box2d:* = window.box2d;
    var def:* = _temp || (_temp = new box2d.b2RevoluteJointDef());
    var anchorPos:Point = Sprite(selfBody.owner).localToGlobal(
        Point.TEMP.setTo(anchor[0], anchor[1]), false, Physics.I.worldRoot);
    var anchorVec:* = new box2d.b2Vec2(
        anchorPos.x / Physics.PIXEL_RATIO, anchorPos.y / Physics.PIXEL_RATIO);
    def.Initialize(otherBody ? otherBody.getBody() : 
        Physics.I._emptyBody, selfBody.getBody(), anchorVec);
    def.enableMotor = _enableMotor;
    def.motorSpeed = _motorSpeed;
    def.maxMotorTorque = _maxMotorTorque;
    def.enableLimit = _enableLimit;
    def.lowerAngle = _lowerAngle;
    def.upperAngle = _upperAngle;
    def.collideConnected = collideConnected;
    
    _joint = Physics.I._createJoint(def);
    }
    

    拉小登博客 Box2D如何固定动态刚体使用旋转关节,实现了一个传送皮带的效果。

    5.平移关节PrismaticJoint
    没什么好说的,anchor是[首次设置有效]关节的控制点,是相对于自身刚体的左上角位置偏移。设成1,1会向着右下角移动。

    6.GearJoint 齿轮关节:用来模拟两个齿轮间的约束关系,齿轮旋转时,产生的动量有两种输出方式,一种是齿轮本身的角速度,另一种是齿轮表面的线速度

    齿轮绑定了两个关节,类型必须是RevoluteJoint或者PrismaticJoint。

    override protected function _createJoint():void {
        if (!_joint) {
            if (!joint1) throw "Joint1 can not be empty";
            if (!joint2) throw "Joint2 can not be empty";
            
            var box2d:* = window.box2d;
            var def:* = _temp || (_temp = new box2d.b2GearJointDef());
            def.bodyA = joint1.owner.getComponent(RigidBody).getBody();
            def.bodyB = joint2.owner.getComponent(RigidBody).getBody();
            def.joint1 = joint1.joint;
            def.joint2 = joint2.joint;
            def.ratio = _ratio;
            def.collideConnected = collideConnected;
            _joint = Physics.I._createJoint(def);
        }
    }
    

    源代码很少,属性就2个。

    相关文章

      网友评论

          本文标题:laya2.0 box2d系列三 关节

          本文链接:https://www.haomeiwen.com/subject/hwwakqtx.html