/******************************************************************************* * Copyright 2015 See AUTHORS file. * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.mygdx.game.objects; import com.badlogic.gdx.graphics.g3d.Model; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.physics.bullet.collision.Collision; import com.badlogic.gdx.physics.bullet.collision.btCollisionObject; import com.badlogic.gdx.physics.bullet.collision.btCollisionShape; import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody; import com.badlogic.gdx.physics.bullet.dynamics.btTypedConstraint; import com.badlogic.gdx.physics.bullet.linearmath.btMotionState; import com.badlogic.gdx.utils.Array; /** * @author jsjolund */ public class GameModelBody extends GameModel { /** * Synchronizes the model world transform with the rigid body world transform */ public class PhysicsMotionState extends btMotionState { public final Matrix4 transform; public PhysicsMotionState(Matrix4 transform) { this.transform = transform; } @Override public void getWorldTransform(Matrix4 worldTrans) { worldTrans.set(transform); } @Override public void setWorldTransform(Matrix4 worldTrans) { transform.set(worldTrans); } } private final static Vector3 localInertia = new Vector3(); /** * Bullet rigid body */ public final btRigidBody body; /** * Flag for which collision layers this body belongs to */ public final short belongsToFlag; /** * Flag for which collision layers this body collides with */ public final short collidesWithFlag; /** * Collision shape which was used to create the rigid body. */ public final btCollisionShape shape; /** * Provides information to create a rigid body */ public final btRigidBody.btRigidBodyConstructionInfo constructionInfo; /** * {@see PhysicsMotionState} */ public final PhysicsMotionState motionState; /** * Mass of the rigid body. From Bullet docs, works best if in range (0:1] */ public final float mass; /** * Physics constraints belonging to this rigid body */ public Array<btTypedConstraint> constraints = new Array<btTypedConstraint>(); /** * Creates a model with rigid body * * @param model Model to instantiate * @param name Name of model * @param location World position at which to place the model instance * @param rotation The rotation of the model instance in degrees * @param scale Scale of the model instance * @param shape Collision shape with which to construct a rigid body * @param mass Mass of the body * @param belongsToFlag Flag for which collision layers this body belongs to * @param collidesWithFlag Flag for which collision layers this body collides with * @param callback If this body should trigger collision contact callbacks. * @param noDeactivate If this body should never 'sleep' */ public GameModelBody(Model model, String name, Vector3 location, Vector3 rotation, Vector3 scale, btCollisionShape shape, float mass, short belongsToFlag, short collidesWithFlag, boolean callback, boolean noDeactivate) { super(model, name, location, rotation, scale); this.mass = mass; this.shape = shape; this.belongsToFlag = belongsToFlag; this.collidesWithFlag = collidesWithFlag; if (mass > 0f) { shape.calculateLocalInertia(mass, localInertia); } else { localInertia.set(0, 0, 0); } this.constructionInfo = new btRigidBody.btRigidBodyConstructionInfo( mass, null, shape, localInertia); body = new btRigidBody(constructionInfo); if (mass > 0f) { motionState = new PhysicsMotionState(modelInstance.transform); body.setMotionState(motionState); } else { motionState = null; } body.setContactCallbackFlag(belongsToFlag); if (callback) { body.setCollisionFlags(body.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); } if (noDeactivate) { body.setActivationState(Collision.DISABLE_DEACTIVATION); } body.setWorldTransform(modelInstance.transform); } public void dispose() { super.dispose(); // Let the calling class be responsible for shape dispose since it can be reused // shape.dispose(); constructionInfo.dispose(); body.dispose(); if (motionState != null) { motionState.dispose(); } for (btTypedConstraint constraint : constraints) { constraint.dispose(); } constraints.clear(); } }