您的位置:首页 > 编程语言

LIBGDX学习]LibGDX代码详解(三十九)Bullet Ragdoll

2018-03-01 15:17 477 查看
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.Ray;
import com.badlogic.gdx.physics.bullet.collision.Collision;
import com.badlogic.gdx.physics.bullet.collision.btCapsuleShape;
import com.badlogic.gdx.physics.bullet.collision.ClosestRayResultCallback;
import com.badlogic.gdx.physics.bullet.dynamics.btConeTwistConstraint;
import com.badlogic.gdx.physics.bullet.dynamics.btConstraintSetting;
import com.badlogic.gdx.physics.bullet.dynamics.btDynamicsWorld;
import com.badlogic.gdx.physics.bullet.dynamics.btHingeConstraint;
import com.badlogic.gdx.physics.bullet.dynamics.btPoint2PointConstraint;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody;
import com.badlogic.gdx.physics.bullet.dynamics.btTypedConstraint;
import com.badlogic.gdx.utils.Array;

/** @author xoppa */
public class RayPickRagdollTest extends BaseBulletTest {

final Array<btTypedConstraint> constraints = new Array<btTypedConstraint>();
btPoint2PointConstraint pickConstraint = null;
btRigidBody pickedBody = null;
float pickDistance;
Vector3 tmpV = new Vector3();

@Override
public void create () {
super.create();
instructions = "Tap to shoot\nDrag ragdoll to pick\nLong press to toggle debug mode\nSwipe for next test\nCtrl+drag to rotate\nScroll to zoom";

camera.position.set(4f, 2f, 4f);
camera.lookAt(0f, 1f, 0f);
camera.update();

world.addConstructor("pelvis", new BulletConstructor(createCapsuleModel(0.15f, 0.2f), 1f, new btCapsuleShape(0.15f, 0.2f)));
world
.addConstructor("spine", new BulletConstructor(createCapsuleModel(0.15f, 0.28f), 1f, new btCapsuleShape(0.15f, 0.28f)));
world.addConstructor("head", new BulletConstructor(createCapsuleModel(0.1f, 0.05f), 1f, new btCapsuleShape(0.1f, 0.05f)));
world.addConstructor("upperleg", new BulletConstructor(createCapsuleModel(0.07f, 0.45f), 1f, new btCapsuleShape(0.07f,
0.45f)));
world.addConstructor("lowerleg", new BulletConstructor(createCapsuleModel(0.05f, 0.37f), 1f, new btCapsuleShape(0.05f,
0.37f)));
world.addConstructor("upperarm", new BulletConstructor(createCapsuleModel(0.05f, 0.33f), 1f, new btCapsuleShape(0.05f,
0.33f)));
world.addConstructor("lowerarm", new BulletConstructor(createCapsuleModel(0.04f, 0.25f), 1f, new btCapsuleShape(0.04f,
0.25f)));

world.add("ground", 0f, 0f, 0f).setColor(0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(),
0.25f + 0.5f * (float)Math.random(), 1f);

addRagdoll(0, 3f, 0);
addRagdoll(1f, 6f, 0);
addRagdoll(-1f, 12f, 0);
}

@Override
public void dispose () {
for (int i = 0; i < constraints.size; i++) {
((btDynamicsWorld)world.collisionWorld).removeConstraint(constraints.get(i));
constraints.get(i).dispose();
}
constraints.clear();
super.dispose();
}

@Override
public boolean touchDown (int screenX, int screenY, int pointer, int button) {
boolean result = false;
if (button == Buttons.LEFT) {
Ray ray = camera.getPickRay(screenX, screenY);
tmpV1.set(ray.direction).scl(10f).add(ray.origin);
ClosestRayResultCallback cb = new ClosestRayResultCallback(ray.origin, tmpV1);
world.collisionWorld.rayTest(ray.origin, tmpV1, cb);
if (cb.hasHit()) {
btRigidBody body = (btRigidBody)(cb.getCollisionObject());
//if (body != null && !body.isStaticObject() && !body.isKinematicObject()) {
if (body != null) {
pickedBody = body;
body.setActivationState(Collision.DISABLE_DEACTIVATION);

cb.getHitPointWorld(tmpV);
tmpV.mul(body.getCenterOfMassTransform().inv());

// constraint相当于夹子?
pickConstraint = new btPoint2PointConstraint(body, tmpV);

btConstraintSetting setting = pickConstraint.getSetting();
setting.setImpulseClamp(30f);
//setting.setTau(0.001f);
setting.setTau(0.001f);
pickConstraint.setSetting(setting);

((btDynamicsWorld)world.collisionWorld).addConstraint(pickConstraint);

pickDistance = tmpV1.sub(camera.position).len();
result = true;
}
}
cb.dispose();
}
return result ? result : super.touchDown(screenX, screenY, pointer, button);
}

@Override
public boolean touchUp (int screenX, int screenY, int pointer, int button) {
boolean result = false;
if (button == Buttons.LEFT) {
if (pickConstraint != null) {
((btDynamicsWorld)world.collisionWorld).removeConstraint(pickConstraint);
pickConstraint.dispose();
pickConstraint = null;
result = true;
}
if (pickedBody != null) {
pickedBody.forceActivationState(Collision.ACTIVE_TAG);
pickedBody.setDeactivationTime(0f);
pickedBody = null;
}
}
return result ? result : super.touchUp(screenX, screenY, pointer, button);
}

@Override
public boolean touchDragged (int screenX, int screenY, int pointer) {
boolean result = false;
if (pickConstraint != null) {
Ray ray = camera.getPickRay(screenX, screenY);
tmpV1.set(ray.direction).scl(pickDistance).add(camera.position);
pickConstraint.setPivotB(tmpV1);
result = true;
}
return result ? result : super.touchDragged(screenX, screenY, pointer);
}

@Override
public boolean tap (float x, float y, int count, int button) {
shoot(x, y);
return true;
}

final static float PI = MathUtils.PI;
final static float PI2 = 0.5f * PI;
final static float PI4 = 0.25f * PI;

public void addRagdoll (final float x, final float y, final float z) {
final Matrix4 tmpM = new Matrix4();
btRigidBody pelvis = (btRigidBody)world.add("pelvis", x, y + 1, z).body;
btRigidBody spine = (btRigidBody)world.add("spine", x, y + 1.2f, z).body;
btRigidBody head = (btRigidBody)world.add("head", x, y + 1.6f, z).body;
btRigidBody leftupperleg = (btRigidBody)world.add("upperleg", x - 0.18f, y + 0.65f, z).body;
btRigidBody leftlowerleg = (btRigidBody)world.add("lowerleg", x - 0.18f, y + 0.2f, z).body;
btRigidBody rightupperleg = (btRigidBody)world.add("upperleg", x + 0.18f, y + 0.65f, z).body;
btRigidBody rightlowerleg = (btRigidBody)world.add("lowerleg", x + 0.18f, y + 0.2f, z).body;

// x转90度?
btRigidBody leftupperarm = (btRigidBody)world.add("upperarm",
tmpM.setFromEulerAnglesRad(PI2, 0, 0).trn(x - 0.35f, y + 1.45f, z)).body;
btRigidBody leftlowerarm = (btRigidBody)world.add("lowerarm", tmpM.setFromEulerAnglesRad(PI2, 0, 0)
.trn(x - 0.7f, y + 1.45f, z)).body;
btRigidBody rightupperarm = (btRigidBody)world.add("upperarm",
tmpM.setFromEulerAnglesRad(-PI2, 0, 0).trn(x + 0.35f, y + 1.45f, z)).body;
btRigidBody rightlowerarm = (btRigidBody)world.add("lowerarm",
tmpM.setFromEulerAnglesRad(-PI2, 0, 0).trn(x + 0.7f, y + 1.45f, z)).body;

final Matrix4 localA = new Matrix4();
final Matrix4 localB = new Matrix4();
btHingeConstraint hingeC = null;
btConeTwistConstraint coneC = null;

// PelvisSpine
//localA.setFromEulerAnglesRad(0, PI2, 0).trn(0, 0.15f, 0);
localA.setFromEulerAnglesRad(0, PI2, 0).trn(0, 0.15f, 0);
localB.setFromEulerAnglesRad(0, PI2, 0).trn(0, -0.15f, 0);
constraints.add(hingeC = new btHingeConstraint(pelvis, spine, localA, localB));
hingeC.setLimit(-PI4, PI2);// 可以旋转的角度?
((btDynamicsWorld)world.collisionWorld).addConstraint(hingeC, true);

// SpineHead
//localA.setFromEulerAnglesRad(PI2, 0, 0).trn(0, 0.3f, 0);
localA.setFromEulerAnglesRad(PI2, 0, 0).trn(0, 0.3f, 0);
localB.setFromEulerAnglesRad(PI2, 0, 0)
4000
.trn(0, -0.14f, 0);
constraints.add(coneC = new btConeTwistConstraint(spine, head, localA, localB));
coneC.setLimit(PI4, PI4, PI2);
((btDynamicsWorld)world.collisionWorld).addConstraint(coneC, true);

// LeftHip
localA.setFromEulerAnglesRad(-PI4 * 5f, 0, 0).trn(-0.18f, -0.1f, 0);
localB.setFromEulerAnglesRad(-PI4 * 5f, 0, 0).trn(0, 0.225f, 0);
constraints.add(coneC = new btConeTwistConstraint(pelvis, leftupperleg, localA, localB));
coneC.setLimit(PI4, PI4, 0);
((btDynamicsWorld)world.collisionWorld).addConstraint(coneC, true);

// LeftKnee
localA.setFromEulerAnglesRad(0, PI2, 0).trn(0, -0.225f, 0);
localB.setFromEulerAnglesRad(0, PI2, 0).trn(0, 0.185f, 0);
constraints.add(hingeC = new btHingeConstraint(leftupperleg, leftlowerleg, localA, localB));
hingeC.setLimit(0, PI2);
((btDynamicsWorld)world.collisionWorld).addConstraint(hingeC, true);

// RightHip
localA.setFromEulerAnglesRad(-PI4 * 5f, 0, 0).trn(0.18f, -0.1f, 0);
localB.setFromEulerAnglesRad(-PI4 * 5f, 0, 0).trn(0, 0.225f, 0);
constraints.add(coneC = new btConeTwistConstraint(pelvis, rightupperleg, localA, localB));
coneC.setLimit(PI4, PI4, 0);
((btDynamicsWorld)world.collisionWorld).addConstraint(coneC, true);

// RightKnee
localA.setFromEulerAnglesRad(0, PI2, 0).trn(0, -0.225f, 0);
localB.setFromEulerAnglesRad(0, PI2, 0).trn(0, 0.185f, 0);
constraints.add(hingeC = new btHingeConstraint(rightupperleg, rightlowerleg, localA, localB));
hingeC.setLimit(0, PI2);
((btDynamicsWorld)world.collisionWorld).addConstraint(hingeC, true);

// LeftShoulder
localA.setFromEulerAnglesRad(PI, 0, 0).trn(-0.2f, 0.15f, 0);
localB.setFromEulerAnglesRad(PI2, 0, 0).trn(0, -0.18f, 0);
constraints.add(coneC = new btConeTwistConstraint(pelvis, leftupperarm, localA, localB));
coneC.setLimit(PI2, PI2, 0);
((btDynamicsWorld)world.collisionWorld).addConstraint(coneC, true);

// LeftElbow
localA.setFromEulerAnglesRad(0, PI2, 0).trn(0, 0.18f, 0);
localB.setFromEulerAnglesRad(0, PI2, 0).trn(0, -0.14f, 0);
constraints.add(hingeC = new btHingeConstraint(leftupperarm, leftlowerarm, localA, localB));
hingeC.setLimit(0, PI2);
((btDynamicsWorld)world.collisionWorld).addConstraint(hingeC, true);

// RightShoulder
localA.setFromEulerAnglesRad(PI, 0, 0).trn(0.2f, 0.15f, 0);
localB.setFromEulerAnglesRad(PI2, 0, 0).trn(0, -0.18f, 0);
constraints.add(coneC = new btConeTwistConstraint(pelvis, rightupperarm, localA, localB));
coneC.setLimit(PI2, PI2, 0);
((btDynamicsWorld)world.collisionWorld).addConstraint(coneC, true);

// RightElbow
localA.setFromEulerAnglesRad(0, PI2, 0).trn(0, 0.18f, 0);
localB.setFromEulerAnglesRad(0, PI2, 0).trn(0, -0.14f, 0);
constraints.add(hingeC = new btHingeConstraint(rightupperarm, rightlowerarm, localA, localB));
hingeC.setLimit(0, PI2);
((btDynamicsWorld)world.collisionWorld).addConstraint(hingeC, true);
}

protected Model createCapsuleModel (float radius, float height) {
//final Model result = modelBuilder.createCapsule(radius, height + radius * 2f, 16,
final Model result = modelBuilder.createCapsule(radius, height + radius * 2f, 16,// 第三个参数是分成多少个面,越多越像半圆
new Material(ColorAttribute.createDiffuse(Color.WHITE), ColorAttribute.createSpecular(Color.WHITE)), Usage.Position
| Usage.Normal);
disposables.add(result);
return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: