首页 > 代码库 > libgdx, mouse 关节

libgdx, mouse 关节

鼠标与body的交互就靠这个mouse 关节了。

在使用中:主要分成3步:

步1:mouseDown : 这个时期,调用world->QueryAABB。它有一个回调接口,并根据鼠标指针指定一个AABB的极小区域。

有3个细节需注意:

细节1:鼠标的xy值是屏幕坐标系统的,要转换成stage坐标系统(stage->screenToStageCoordinates),然后再转成box2d的单位xy值;

细节2:AABB极小区域是多小?当然是越小越好(比如:0.001f ,单位是米的,或者1个像素的差)x-0.001f, y-0.001f, x+0.001f,y+0.001f。这样就形成了一个极小区域。但实际测试时发现,回调函数被调用时,鼠标距离我们的目标body还有3-5个像素,这可能会造成视觉上的困惑。为解决这个问题,我一般在回调函数中再对其进行“(鼠标)点的测试”,即fixture->testPoint(x,y)方法。用它来实现测试我们的fixture是否被击中,以严格的击中测试来定位fixture击中与否,以此来建立鼠标关节会更符合视觉习惯。

细节3:bodyB是操作目标,bodyA一般是静态body;我第一次使用时将这两个搞混了,结果发生崩溃异常。(参见后面的图1)


步2:mouseDrag:在这个时间,只是简单设置目标位置就行。注意坐标的转换与单位的转换。


步3:mouseUp:这个时间是销毁鼠标关节。一般要注意将关节对象的引用置空(=null)。


最后还要根据实例的body属性,特别调节如下参数,以保证mouse关节行为不是那么怪异!

mouseJointDef.dampingRatio = 1;
mouseJointDef.frequencyHz = 60; 、、调大些,会使用命中时显的更灵敏。
mouseJointDef.maxForce = 5000;、、力要足够大,否则可能因为干不过重力而出现不期望的效果,比如“向下掉”。

mouseJointDef.collideConnected = true;、、一般都设置为true,连接的body也要有碰撞,默认值为false,如果为false,它可能会“向下掉,且掉到地板下面去了”。


下图是图1:


代码参考:

   @Override
    public boolean reportFixture(Fixture fixture) {


        // 如果不是这个类型,直接转换会抛异常
//        KwLetter kwLetter = (KwLetter)fixture.getBody().getUserData();
        // 修改成如下代码
        Object object = fixture.getBody().getUserData();
        if (object instanceof KwLetter) {
            KwLetter kwLetter = (KwLetter)object;
            if (null == m_mouseJoint && kwLetter.hit(m_mouseX2d, m_mouseY2d)) {
                Gdx.app.debug("reportFixture", "kwLetter="+kwLetter);
                MouseJointDef mouseJointDef = new MouseJointDef();
//                mouseJointDef.dampingRatio = 1;
//                mouseJointDef.frequencyHz = 1;
//                mouseJointDef.maxForce = 5;
                mouseJointDef.target.set(new Vector2(m_mouseX2d, m_mouseY2d));
                mouseJointDef.bodyA = m_kwGround.getBody();
                mouseJointDef.bodyB = kwLetter.getBody();//目标
                m_mouseJoint = (MouseJoint)m_world.createJoint(mouseJointDef);
            }
        }


        return false;
    }



    public boolean hit(float x2d, float y2d)
    {
        return m_fixture.testPoint(x2d, y2d);
    }