下面一些内容定义来自《Box2D中文手册》
关节用于把物体约束到世界,或约束到其它物体上。在游戏中,典型例子有木偶,跷跷板和滑轮。用不同的方式将关节结合起来使用,可以创造出有趣的运动。
有些关节提供了限制(limit),使可以控制运动的范围。有些关节还提供了马达(motor),它可以以指定的速度驱动关节一直运动,直到你指定了更大的力或扭矩来抵消这种运动。
关节马达有许多不同的用途。可以使用关节来控制位置,只要提供一个与目标之距离成正比例的关节速度即可。还可以模拟关节摩擦:将关节速度置零,并且提供一个小的、但有效的最大力或扭矩;那么马达就会努力保持关节不动,直到负载变得过大为止。
每种关节类型都有各自的定义(definition),它们都派生自 JointDef。所有的关节都连接两个不同的物体,其中一个物体有可能是静态的。关节也可以连接两个 static 或者 kinematic 类型的物体,但这没有任何实际用途,只会浪费处理器时间。
可以为任何一种关节类型指定用户数据。还可以提供一个标记,用于防止用关节相连的物体之间发生碰撞。实际上, 这是默认行为。也可以通过设置 collideConnected,来允许相连的物体之间发生碰撞。
很多关节定义需要提供一些几何数据。一个关节常常需要一个锚点(anchor point)来定义,这是固定于相接物体中的点。 Box2D 要求这些点在局部坐标系中指定,这样,即便当前物体的变化违反了关节约束(joint constraint),关节还是可以被指定–这通常会发生在游戏保存或载入进度时。
另外,有些关节定义需要知道物体之间默认的相对角度。这样才能正确地约束旋转。
初始化几何数据可能有些乏味。所以很多关节提供了初始化函数,使用当前的物体的形状,来消除大部分工作。然而,这些初始化函数通常只应用于原型,在产品代码中应该直接地定义几何数据。这能使关节行为更具健壮性。
鼠标关节用于通过鼠标来操控物体,它试图将物体托向当前鼠标光标的位置,而在旋转方面就没有限制。
鼠标关节的定义需要一个目标点(target point),最大力(maximum force),频率(frequency),阻尼率(damping ratio)。目标点最开始与物体的锚点重合,最大力用于防止再多个动态物体相互作用时的激烈反应。频率和阻尼用于创造一种弹性效果。
1.com.badlogic.gdx.physics.box2d.JointDef
/** The first attached body. **/
public Body bodyA = null;
/** The second attached body **/
public Body bodyB = null;
/** Set this flag to true if the attached bodies should collide. **/
public boolean collideConnected = false;
2.com.badlogic.gdx.physics.box2d.joints.MouseJointDef
/** The initial world target point. This is assumed to coincide with the body anchor initially. 锚点 */
public final Vector2 target = new Vector2();
/** The maximum constraint force that can be exerted to move the candidate body. Usually you will express as some multiple of
* the weight (multiplier * mass * gravity). */
public float maxForce = 0;
/** The response speed. */
public float frequencyHz = 5.0f;
/** The damping ratio. 0 = no damping, 1 = critical damping. */
public float dampingRatio = 0.7f;
3.com.badlogic.gdx.physics.box2d.joints.MouseJoint extends Joint
/** A mouse joint is used to make a point on a body track a specified world point. This a soft constraint with a maximum force.
** This allows the constraint to stretch and without applying huge forces. NOTE: this joint is not documented in the manual
* because it was developed to be used in the testbed. If you want to learn how to use the mouse joint, look at the testbed. /
![这里写图片描述](http://img.blog.csdn.net/20170105225558705?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenFpYW5nXzU1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
/**
* 鼠标关节测试
*/
public class MouseJointTest extends ApplicationAdapter {
World world;
Box2DDebugRenderer box2DDebugRenderer;
Body mouseJointBody, groundBody;
Fixture fixture;
OrthographicCamera camera;
Vector3 point = new Vector3();
float scene_width = 12.8f;
float scene_height = 7.2f;
Vector2 target = new Vector2();
@Override
public void create() {
world = new World(new Vector2(0.0f, -9.8f), true);
box2DDebugRenderer = new Box2DDebugRenderer();
camera = new OrthographicCamera(scene_width, scene_height);
camera.position.set(scene_width / 2, scene_height / 2, 0);
camera.update();
groundBody = createGroundWall();
Gdx.input.setInputProcessor(new HandA());
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(3.0f, 4.8f);
bodyDef.type = BodyDef.BodyType.DynamicBody;
mouseJointBody = world.createBody(bodyDef);
PolygonShape polygonShape = new PolygonShape();
polygonShape.setAsBox(0.5f, 0.5f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = polygonShape;
fixtureDef.density = 1.0f;
fixtureDef.restitution = 0.6f;
fixture = mouseJointBody.createFixture(fixtureDef);
}
@Override
public void render() {
world.step(1 / 60f, 6, 2);
Gdx.gl.glClearColor(0.39f, 0.58f, 0.92f, 1.0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
box2DDebugRenderer.render(world, camera.combined);
}
@Override
public void dispose() {
world.dispose();
box2DDebugRenderer.dispose();
}
public Body createGroundWall() {
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(scene_width * 0.5f, 0.2f);
Body body1 = world.createBody(bodyDef);
PolygonShape polygonShape = new PolygonShape();
polygonShape.setAsBox(scene_width * 0.5f, 0.2f);
body1.createFixture(polygonShape, 0.0f);
bodyDef.position.set(0.4f, scene_height * 0.5f);
Body body2 = world.createBody(bodyDef);
polygonShape.setAsBox(0.2f, scene_height * 0.5f);
body2.createFixture(polygonShape, 0);
bodyDef.position.set(12.4f, scene_height * 0.5f);
Body body3 = world.createBody(bodyDef);
polygonShape.setAsBox(0.2f, scene_height * 0.5f);
body3.createFixture(polygonShape, 0);
bodyDef.position.set(scene_width * 0.5f, 7.0f);
Body body4 = world.createBody(bodyDef);
polygonShape.setAsBox(scene_width * 0.5f, 0.2f);
body4.createFixture(polygonShape, 0);
polygonShape.dispose();
return body1;
}
private void logInfo(String message) {
Gdx.app.log("MouseJointTest", message);
}
class HandA extends InputAdapter {
MouseJoint mouseJoint;
@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
logInfo("touchDragged");
if (mouseJoint != null) {
camera.unproject(point.set(screenX, screenY, 0));
mouseJoint.setTarget(target.set(point.x, point.y));
}
return false;
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
logInfo("touchDown");
camera.unproject(point.set(screenX, screenY, 0));
// 当鼠标点击到物体时才会创建鼠标关节,并绑定
if (fixture.testPoint(point.x, point.y)) {
if (mouseJointBody == null) return false;
MouseJointDef mouseJointDef = new MouseJointDef();
mouseJointDef.bodyA = groundBody;
mouseJointDef.bodyB = mouseJointBody;
mouseJointDef.collideConnected = true;
mouseJointDef.target.set(point.x, point.y);
mouseJointDef.maxForce = 1000.0f * mouseJointBody.getMass();
mouseJoint = (MouseJoint) world.createJoint(mouseJointDef);
mouseJointBody.setAwake(true);
}
return false;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
logInfo("touchUp");
// 鼠标关节,不再使用时要销毁
if (mouseJoint != null) {
world.destroyJoint(mouseJoint);
mouseJoint = null;
}
return false;
}
}
}