laya2.0 box2d系列三 关节

一、基础概念

参考拉小登博客 初识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 轮子关节:围绕节点旋转,包含弹性属性,使得刚体在节点位置发生弹性偏移
2354823-51090f2a44b203f3.png
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 参考官方文档 物理一 距离关节

2354823-c055a8a40be6a559.png
image.png

通过固定长度的关节将两刚体联系到一起,使这两个刚体始终保持一定的距离。用于木棍,骨骼,弹簧一样的约束关系。
2354823-98bab83ca24050ce.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,下面的图可以更好的解释这一点:

2354823-2977984064c15186.png
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个。

猜你喜欢

转载自blog.csdn.net/weixin_34072637/article/details/87321190
今日推荐