libgdx 3D Bullet 碰撞检测一

英文原文地址:http://blog.xoppa.com/using-the-libgdx-3d-physics-bullet-wrapper-part1/

强烈推荐看英文原版教程,通俗易懂全面精确。

============================

我先上代码:

  1 package org.forus.game.test;

  2 

  3 import com.badlogic.gdx.ApplicationListener;

  4 import com.badlogic.gdx.Gdx;

  5 import com.badlogic.gdx.graphics.Color;

  6 import com.badlogic.gdx.graphics.GL20;

  7 import com.badlogic.gdx.graphics.PerspectiveCamera;

  8 import com.badlogic.gdx.graphics.VertexAttributes;

  9 import com.badlogic.gdx.graphics.g3d.*;

 10 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;

 11 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;

 12 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;

 13 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;

 14 import com.badlogic.gdx.math.Vector3;

 15 import com.badlogic.gdx.physics.bullet.Bullet;

 16 import com.badlogic.gdx.physics.bullet.collision.*;

 17 import com.badlogic.gdx.utils.Array;

 18 

 19 /**

 20  * Created by HanHongmin on 14-8-22.

 21  */

 22 public class BulletTest implements ApplicationListener {

 23     PerspectiveCamera cam;//3D视角

 24     CameraInputController camController;//视角控制器

 25     ModelBatch modelBatch;//3D模型批渲染器

 26     Array<ModelInstance> instances;//3D实例集合

 27     Environment environment;//环境属性,光线等

 28 

 29     Model model;//模型

 30     ModelInstance ground;//长方体实例

 31     ModelInstance ball;//球形实例

 32 

 33     boolean collision;//是否碰撞的标记

 34     btCollisionShape groundShape;//对应长方体实例的碰撞形状

 35     btCollisionShape ballShape;//对应球形实例的碰撞形状

 36     btCollisionObject groundObject;//

 37     btCollisionObject ballObject;//

 38 

 39     btCollisionConfiguration collisionConfig;//

 40     btDispatcher dispatcher;

 41 

 42     @Override

 43     public void create () {

 44         Bullet.init();//使用Bullet前必须先初始化

 45         modelBatch = new ModelBatch();

 46 

 47         environment = new Environment();

 48         environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));//环境光

 49         environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));//直线光

 50 

 51         cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

 52         cam.position.set(3f, 7f, 10f);

 53         cam.lookAt(0, 4f, 0);

 54         cam.update();

 55 

 56         camController = new CameraInputController(cam);

 57         Gdx.input.setInputProcessor(camController);

 58 

 59         instances = new Array<ModelInstance>();

 60 

 61         //代码方式构造模型

 62         ModelBuilder mb = new ModelBuilder();

 63         mb.begin();

 64         mb.node().id = "ground";

 65         mb.part("box", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.RED)))

 66                 .box(5f, 1f, 5f);

 67         mb.node().id = "ball";

 68         mb.part("sphere", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.GREEN)))

 69                 .sphere(1f, 1f, 1f, 10, 10);

 70         model = mb.end();

 71         //实例化模型

 72         ground = new ModelInstance(model, "ground");

 73         ball = new ModelInstance(model, "ball");

 74         ball.transform.setToTranslation(0, 9f, 0);

 75 

 76         instances = new Array<ModelInstance>();

 77         instances.add(ground);

 78         instances.add(ball);

 79 

 80         //创建碰撞检测形状

 81         ballShape = new btSphereShape(0.5f);

 82         groundShape = new btBoxShape(new Vector3(2.5f, 0.5f, 2.5f));

 83 

 84         //创建碰撞检测体

 85         groundObject = new btCollisionObject();

 86         groundObject.setCollisionShape(groundShape);

 87         groundObject.setWorldTransform(ground.transform);

 88 

 89         ballObject = new btCollisionObject();

 90         ballObject.setCollisionShape(ballShape);

 91         ballObject.setWorldTransform(ball.transform);

 92 

 93         collisionConfig = new btDefaultCollisionConfiguration();

 94         dispatcher = new btCollisionDispatcher(collisionConfig);

 95     }

 96 

 97     @Override

 98     public void render () {

 99         final float delta = Math.min(1f/30f, Gdx.graphics.getDeltaTime());

100 

101         if (!collision) {//尚未碰撞

102             ball.transform.translate(0f, -delta, 0f);//球向下移动

103             ballObject.setWorldTransform(ball.transform);//同时移动碰撞体

104             collision = checkCollision();//碰撞检测

105         }

106 

107         camController.update();

108 

109         Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1.f);

110         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

111 

112         modelBatch.begin(cam);

113         modelBatch.render(instances, environment);

114         modelBatch.end();

115     }

116     boolean checkCollision() {

117         CollisionObjectWrapper co0 = new CollisionObjectWrapper(ballObject);

118         CollisionObjectWrapper co1 = new CollisionObjectWrapper(groundObject);

119 

120         btCollisionAlgorithmConstructionInfo ci = new btCollisionAlgorithmConstructionInfo();//碰撞算法信息

121         ci.setDispatcher1(dispatcher);

122         btCollisionAlgorithm algorithm = new btSphereBoxCollisionAlgorithm(null, ci, co0.wrapper, co1.wrapper, false);//碰撞算法

123 

124         btDispatcherInfo info = new btDispatcherInfo();

125         btManifoldResult result = new btManifoldResult(co0.wrapper, co1.wrapper);

126 

127         algorithm.processCollision(co0.wrapper, co1.wrapper, info, result);

128 

129         boolean r = result.getPersistentManifold().getNumContacts() > 0;

130 

131         result.dispose();

132         info.dispose();

133         algorithm.dispose();

134         ci.dispose();

135         co1.dispose();

136         co0.dispose();

137 

138         return r;

139     }

140 

141     @Override

142     public void dispose () {

143         groundObject.dispose();

144         groundShape.dispose();

145 

146         ballObject.dispose();

147         ballShape.dispose();

148 

149         dispatcher.dispose();

150         collisionConfig.dispose();

151 

152         modelBatch.dispose();

153         model.dispose();

154     }

155 

156     @Override public void pause () {}

157     @Override public void resume () {}

158     @Override public void resize (int width, int height) {}

159 }

 

Bullet是什么?百度百科:http://baike.baidu.com/view/449998.htm?fr=aladdin

Libgdx扩展库对其提供了封装,也就是说我们可以通过gdx-bullet使用java代码就可以使用Bullet的C++啦。

如果在创建工程的过程中没有勾选bullet,那么把gdx-bullet的库加进来就可以啦。

我是使用IDEA+gradle, 直接在工程的父build.gradle增加库依赖:

core:

compile "com.badlogicgames.gdx:gdx-bullet:$gdxVersion"

ios:

compile "com.badlogicgames.gdx:gdx-bullet:$gdxVersion"
natives "com.badlogicgames.gdx:gdx-bullet-platform:$gdxVersion:natives-ios"

android:

compile "com.badlogicgames.gdx:gdx-bullet:$gdxVersion"
natives "com.badlogicgames.gdx:gdx-bullet-platform:$gdxVersion:natives-armeabi"
natives "com.badlogicgames.gdx:gdx-bullet-platform:$gdxVersion:natives-armeabi-v7a"
natives "com.badlogicgames.gdx:gdx-bullet-platform:$gdxVersion:natives-x86"

desktop:

compile "com.badlogicgames.gdx:gdx-bullet-platform:$gdxVersion:natives-desktop"

html: 貌似不支持

 

代码中一目了然,每一个3D物体都有一个碰撞形状和碰撞体与之对应(注意构造碰撞形状的时候参数与3D模型的不同)。

在碰撞检测的时候,用CollisionObjectWrapper包装,构造碰撞算法,计算碰撞......

我们使用的Java是可以自己管理释放内存的,但是这里实际的计算是java调用的C++代码,so

Bullet相关的都需要dispose。

===============================

btDispatcher貌似能够通过具体碰撞形状找到合适的算法,就像上面代码我们用到的

btSphereBoxCollisionAlgorithm

在看一下改进的代码:

boolean checkCollision(btCollisionObject obj0, btCollisionObject obj1) {

        CollisionObjectWrapper co0 = new CollisionObjectWrapper(obj0);

        CollisionObjectWrapper co1 = new CollisionObjectWrapper(obj1);

        btCollisionAlgorithm algorithm = dispatcher.findAlgorithm(co0.wrapper, co1.wrapper);//看上去像是能够通过具体形状找到合适的碰撞算法

        btDispatcherInfo info = new btDispatcherInfo();

        btManifoldResult result = new btManifoldResult(co0.wrapper, co1.wrapper);

        algorithm.processCollision(co0.wrapper, co1.wrapper, info, result);



        boolean r = result.getPersistentManifold().getNumContacts() > 0;

        dispatcher.freeCollisionAlgorithm(algorithm.getCPointer());

        result.dispose();

        info.dispose();

        co1.dispose();

        co0.dispose();



        return r;

    }

这样我们只需传入两个btCollisionObject参数就可以做碰撞检测了,而无需关心他们具体是什么形状。

 

现在我们试试更多的形状,首先我们封装一下:

static class GameObject extends ModelInstance implements Disposable {

        public final btCollisionObject body;

        public boolean moving;

        public GameObject(Model model, String node, btCollisionShape shape) {

            super(model, node);

            body = new btCollisionObject();

            body.setCollisionShape(shape);

        }



        @Override

        public void dispose () {

            body.dispose();

        }

        static class Constructor implements Disposable {

            public final Model model;

            public final String node;

            public final btCollisionShape shape;

            public Constructor(Model model, String node, btCollisionShape shape) {

                this.model = model;

                this.node = node;

                this.shape = shape;

            }



            public GameObject construct() {

                return new GameObject(model, node, shape);

            }



            @Override

            public void dispose () {

                shape.dispose();

            }

        }

    }

据说这是工厂模式。

还是直接上全代码吧:

  1 package org.forus.game.test;

  2 

  3 import com.badlogic.gdx.ApplicationListener;

  4 import com.badlogic.gdx.Gdx;

  5 import com.badlogic.gdx.graphics.Color;

  6 import com.badlogic.gdx.graphics.GL20;

  7 import com.badlogic.gdx.graphics.PerspectiveCamera;

  8 import com.badlogic.gdx.graphics.VertexAttributes;

  9 import com.badlogic.gdx.graphics.g3d.*;

 10 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;

 11 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;

 12 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;

 13 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;

 14 import com.badlogic.gdx.math.MathUtils;

 15 import com.badlogic.gdx.math.Vector3;

 16 import com.badlogic.gdx.physics.bullet.Bullet;

 17 import com.badlogic.gdx.physics.bullet.collision.*;

 18 import com.badlogic.gdx.utils.Array;

 19 import com.badlogic.gdx.utils.ArrayMap;

 20 import com.badlogic.gdx.utils.Disposable;

 21 

 22 /**

 23  * Created by HanHongmin on 14-8-22.

 24  */

 25 public class BulletTest implements ApplicationListener {

 26     PerspectiveCamera cam;//3D视角

 27     CameraInputController camController;//视角控制器

 28     ModelBatch modelBatch;//3D模型批渲染器

 29     //Array<ModelInstance> instances;//3D实例集合

 30     Environment environment;//环境属性,光线等

 31 

 32     Model model;//模型

 33 

 34     float spawnTimer;//用于控制生成随机形状碰撞体

 35 

 36 

 37     btCollisionConfiguration collisionConfig;//

 38     btDispatcher dispatcher;

 39 

 40     Array<GameObject> instances;

 41     ArrayMap<String, GameObject.Constructor> constructors;

 42 

 43     @Override

 44     public void create () {

 45         Bullet.init();//使用Bullet前必须先初始化

 46         modelBatch = new ModelBatch();

 47 

 48         environment = new Environment();

 49         environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));//环境光

 50         environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));//直线光

 51 

 52         cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

 53         cam.position.set(3f, 7f, 10f);

 54         cam.lookAt(0, 4f, 0);

 55         cam.update();

 56 

 57         camController = new CameraInputController(cam);

 58         Gdx.input.setInputProcessor(camController);

 59 

 60         ModelBuilder mb = new ModelBuilder();

 61         mb.begin();

 62         mb.node().id = "ground";

 63         mb.part("ground", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.RED)))

 64                 .box(5f, 1f, 5f);

 65         mb.node().id = "sphere";

 66         mb.part("sphere", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.GREEN)))

 67                 .sphere(1f, 1f, 1f, 10, 10);

 68         mb.node().id = "box";

 69         mb.part("box", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.BLUE)))

 70                 .box(1f, 1f, 1f);

 71         mb.node().id = "cone";

 72         mb.part("cone", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.YELLOW)))

 73                 .cone(1f, 2f, 1f, 10);

 74         mb.node().id = "capsule";

 75         mb.part("capsule", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.CYAN)))

 76                 .capsule(0.5f, 2f, 10);

 77         mb.node().id = "cylinder";

 78         mb.part("cylinder", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.MAGENTA)))

 79                 .cylinder(1f, 2f, 1f, 10);

 80         model = mb.end();

 81 

 82         constructors = new ArrayMap<String, GameObject.Constructor>(String.class, GameObject.Constructor.class);

 83         constructors.put("ground", new GameObject.Constructor(model, "ground", new btBoxShape(new Vector3(2.5f, 0.5f, 2.5f))));

 84         constructors.put("sphere", new GameObject.Constructor(model, "sphere", new btSphereShape(0.5f)));

 85         constructors.put("box", new GameObject.Constructor(model, "box", new btBoxShape(new Vector3(0.5f, 0.5f, 0.5f))));

 86         constructors.put("cone", new GameObject.Constructor(model, "cone", new btConeShape(0.5f, 2f)));

 87         constructors.put("capsule", new GameObject.Constructor(model, "capsule", new btCapsuleShape(.5f, 1f)));

 88         constructors.put("cylinder", new GameObject.Constructor(model, "cylinder", new btCylinderShape(new Vector3(.5f, 1f, .5f))));

 89 

 90         instances = new Array<GameObject>();

 91         instances.add(constructors.get("ground").construct());

 92 

 93         collisionConfig = new btDefaultCollisionConfiguration();

 94         dispatcher = new btCollisionDispatcher(collisionConfig);

 95     }

 96 

 97     @Override

 98     public void render () {

 99 

100         final float delta = Math.min(1f/30f, Gdx.graphics.getDeltaTime());

101 

102         for (GameObject obj : instances) {

103             if (obj.moving) {

104                 obj.transform.trn(0f, -delta, 0f);

105                 obj.body.setWorldTransform(obj.transform);

106                 if (checkCollision(obj.body, instances.get(0).body))//get(0)是ground

107                     obj.moving = false;

108             }

109         }

110 

111         if ((spawnTimer -= delta) < 0) {

112             spawn();

113             spawnTimer = 1.5f;//每1.5s生成一个

114         }

115         camController.update();

116 

117         Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1.f);

118         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

119 

120         modelBatch.begin(cam);

121         modelBatch.render(instances, environment);

122         modelBatch.end();

123     }

124 

125     public void spawn() {

126         GameObject obj = constructors.values[1+ MathUtils.random(constructors.size - 2)].construct();//-2是除去ground

127         obj.moving = true;

128         obj.transform.setFromEulerAngles(MathUtils.random(360f), MathUtils.random(360f), MathUtils.random(360f));//旋转?

129         obj.transform.trn(MathUtils.random(-2.5f, 2.5f), 9f, MathUtils.random(-2.5f, 2.5f));//设置位置,区别于translate,trn可影响rotate参数,待测试

130         obj.body.setWorldTransform(obj.transform);

131         instances.add(obj);

132     }

133 

134     boolean checkCollision(btCollisionObject obj0, btCollisionObject obj1) {

135         CollisionObjectWrapper co0 = new CollisionObjectWrapper(obj0);

136         CollisionObjectWrapper co1 = new CollisionObjectWrapper(obj1);

137         btCollisionAlgorithm algorithm = dispatcher.findAlgorithm(co0.wrapper, co1.wrapper);//看上去像是能够通过具体形状找到合适的碰撞算法

138         btDispatcherInfo info = new btDispatcherInfo();

139         btManifoldResult result = new btManifoldResult(co0.wrapper, co1.wrapper);

140         algorithm.processCollision(co0.wrapper, co1.wrapper, info, result);

141 

142         boolean r = result.getPersistentManifold().getNumContacts() > 0;

143         dispatcher.freeCollisionAlgorithm(algorithm.getCPointer());

144         result.dispose();

145         info.dispose();

146         co1.dispose();

147         co0.dispose();

148 

149         return r;

150     }

151 

152     @Override

153     public void dispose () {

154 

155         for (GameObject obj : instances)

156             obj.dispose();

157         instances.clear();

158 

159         for (GameObject.Constructor ctor : constructors.values())

160             ctor.dispose();

161         constructors.clear();

162 

163         dispatcher.dispose();

164         collisionConfig.dispose();

165 

166         modelBatch.dispose();

167         model.dispose();

168     }

169 

170     @Override public void pause () {}

171     @Override public void resume () {}

172     @Override public void resize (int width, int height) {}

173 

174     static class GameObject extends ModelInstance implements Disposable {

175         public final btCollisionObject body;

176         public boolean moving;

177         public GameObject(Model model, String node, btCollisionShape shape) {

178             super(model, node);

179             body = new btCollisionObject();

180             body.setCollisionShape(shape);

181         }

182 

183         @Override

184         public void dispose () {

185             body.dispose();

186         }

187         static class Constructor implements Disposable {

188             public final Model model;

189             public final String node;

190             public final btCollisionShape shape;

191             public Constructor(Model model, String node, btCollisionShape shape) {//据说是工厂模式

192                 this.model = model;

193                 this.node = node;

194                 this.shape = shape;

195             }

196 

197             public GameObject construct() {

198                 return new GameObject(model, node, shape);

199             }

200 

201             @Override

202             public void dispose () {

203                 shape.dispose();

204             }

205         }

206     }

207 }

待续...

ContactListener 接触监听

将碰撞逻辑从渲染中分离除去

  1 package org.forus.game.test;

  2 

  3 import com.badlogic.gdx.ApplicationListener;

  4 import com.badlogic.gdx.Gdx;

  5 import com.badlogic.gdx.graphics.Color;

  6 import com.badlogic.gdx.graphics.GL20;

  7 import com.badlogic.gdx.graphics.PerspectiveCamera;

  8 import com.badlogic.gdx.graphics.VertexAttributes;

  9 import com.badlogic.gdx.graphics.g3d.*;

 10 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;

 11 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;

 12 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;

 13 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;

 14 import com.badlogic.gdx.math.MathUtils;

 15 import com.badlogic.gdx.math.Vector3;

 16 import com.badlogic.gdx.physics.bullet.Bullet;

 17 import com.badlogic.gdx.physics.bullet.collision.*;

 18 import com.badlogic.gdx.utils.Array;

 19 import com.badlogic.gdx.utils.ArrayMap;

 20 import com.badlogic.gdx.utils.Disposable;

 21 

 22 /**

 23  * Created by HanHongmin on 14-8-22.

 24  */

 25 public class BulletTest implements ApplicationListener {

 26     PerspectiveCamera cam;//3D视角

 27     CameraInputController camController;//视角控制器

 28     ModelBatch modelBatch;//3D模型批渲染器

 29     //Array<ModelInstance> instances;//3D实例集合

 30     Environment environment;//环境属性,光线等

 31 

 32     Model model;//模型

 33 

 34     float spawnTimer;//用于控制生成随机形状碰撞体

 35 

 36 

 37     btCollisionConfiguration collisionConfig;//

 38     btDispatcher dispatcher;

 39 

 40     Array<GameObject> instances;

 41     ArrayMap<String, GameObject.Constructor> constructors;

 42 

 43  MyContactListener contactListener;  44 

 45     @Override

 46     public void create () {

 47         Bullet.init();//使用Bullet前必须先初始化

 48         modelBatch = new ModelBatch();

 49 

 50         environment = new Environment();

 51         environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));//环境光

 52         environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));//直线光

 53 

 54         cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

 55         cam.position.set(3f, 7f, 10f);

 56         cam.lookAt(0, 4f, 0);

 57         cam.update();

 58 

 59         camController = new CameraInputController(cam);

 60         Gdx.input.setInputProcessor(camController);

 61 

 62         ModelBuilder mb = new ModelBuilder();

 63         mb.begin();

 64         mb.node().id = "ground";

 65         mb.part("ground", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.RED)))

 66                 .box(5f, 1f, 5f);

 67         mb.node().id = "sphere";

 68         mb.part("sphere", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.GREEN)))

 69                 .sphere(1f, 1f, 1f, 10, 10);

 70         mb.node().id = "box";

 71         mb.part("box", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.BLUE)))

 72                 .box(1f, 1f, 1f);

 73         mb.node().id = "cone";

 74         mb.part("cone", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.YELLOW)))

 75                 .cone(1f, 2f, 1f, 10);

 76         mb.node().id = "capsule";

 77         mb.part("capsule", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.CYAN)))

 78                 .capsule(0.5f, 2f, 10);

 79         mb.node().id = "cylinder";

 80         mb.part("cylinder", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.MAGENTA)))

 81                 .cylinder(1f, 2f, 1f, 10);

 82         model = mb.end();

 83 

 84         constructors = new ArrayMap<String, GameObject.Constructor>(String.class, GameObject.Constructor.class);

 85         constructors.put("ground", new GameObject.Constructor(model, "ground", new btBoxShape(new Vector3(2.5f, 0.5f, 2.5f))));

 86         constructors.put("sphere", new GameObject.Constructor(model, "sphere", new btSphereShape(0.5f)));

 87         constructors.put("box", new GameObject.Constructor(model, "box", new btBoxShape(new Vector3(0.5f, 0.5f, 0.5f))));

 88         constructors.put("cone", new GameObject.Constructor(model, "cone", new btConeShape(0.5f, 2f)));

 89         constructors.put("capsule", new GameObject.Constructor(model, "capsule", new btCapsuleShape(.5f, 1f)));

 90         constructors.put("cylinder", new GameObject.Constructor(model, "cylinder", new btCylinderShape(new Vector3(.5f, 1f, .5f))));

 91 

 92         instances = new Array<GameObject>();

 93         instances.add(constructors.get("ground").construct());

 94 

 95         collisionConfig = new btDefaultCollisionConfiguration();

 96         dispatcher = new btCollisionDispatcher(collisionConfig);

 97 

 98         contactListener = new MyContactListener();  99     }

100 

101     @Override

102     public void render () {

103 

104         final float delta = Math.min(1f/30f, Gdx.graphics.getDeltaTime());

105 

106         for (GameObject obj : instances) {

107             if (obj.moving) {

108                 obj.transform.trn(0f, -delta, 0f);

109                 obj.body.setWorldTransform(obj.transform);

110                 //if (checkCollision(obj.body, instances.get(0).body))//get(0)是ground

111                     //obj.moving = false;

112                 checkCollision(obj.body, instances.get(0).body); 113             }

114         }

115 

116 

117         if ((spawnTimer -= delta) < 0) {

118             spawn();

119             spawnTimer = 1.5f;//每1.5s生成一个

120         }

121         camController.update();

122 

123         Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1.f);

124         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

125 

126         modelBatch.begin(cam);

127         modelBatch.render(instances, environment);

128         modelBatch.end();

129     }

130 

131     public void spawn() {

132         GameObject obj = constructors.values[1+ MathUtils.random(constructors.size - 2)].construct();//-2是除去ground

133         obj.moving = true;

134         obj.transform.setFromEulerAngles(MathUtils.random(360f), MathUtils.random(360f), MathUtils.random(360f));//旋转?

135         obj.transform.trn(MathUtils.random(-2.5f, 2.5f), 9f, MathUtils.random(-2.5f, 2.5f));//设置位置,区别于translate,trn可影响rotate参数,待测试

136         obj.body.setWorldTransform(obj.transform);

137 

138  obj.body.setUserValue(instances.size); 139         obj.body.setCollisionFlags(obj.body.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); 140 

141         instances.add(obj);

142     }

143 

144     boolean checkCollision(btCollisionObject obj0, btCollisionObject obj1) {

145         CollisionObjectWrapper co0 = new CollisionObjectWrapper(obj0);

146         CollisionObjectWrapper co1 = new CollisionObjectWrapper(obj1);

147         btCollisionAlgorithm algorithm = dispatcher.findAlgorithm(co0.wrapper, co1.wrapper);//看上去像是能够通过具体形状找到合适的碰撞算法

148         btDispatcherInfo info = new btDispatcherInfo();

149         btManifoldResult result = new btManifoldResult(co0.wrapper, co1.wrapper);

150         algorithm.processCollision(co0.wrapper, co1.wrapper, info, result);

151 

152         boolean r = result.getPersistentManifold().getNumContacts() > 0;

153         dispatcher.freeCollisionAlgorithm(algorithm.getCPointer());

154         result.dispose();

155         info.dispose();

156         co1.dispose();

157         co0.dispose();

158 

159         return r;

160     }

161 

162     @Override

163     public void dispose () {

164 

165         for (GameObject obj : instances)

166             obj.dispose();

167         instances.clear();

168 

169         for (GameObject.Constructor ctor : constructors.values())

170             ctor.dispose();

171         constructors.clear();

172 

173         dispatcher.dispose();

174         collisionConfig.dispose();

175 

176         modelBatch.dispose();

177         model.dispose();

178  contactListener.dispose(); 179     }

180 

181     @Override public void pause () {}

182     @Override public void resume () {}

183     @Override public void resize (int width, int height) {}

184 

185     static class GameObject extends ModelInstance implements Disposable {

186         public final btCollisionObject body;

187         public boolean moving;

188         public GameObject(Model model, String node, btCollisionShape shape) {

189             super(model, node);

190             body = new btCollisionObject();

191             body.setCollisionShape(shape);

192         }

193 

194         @Override

195         public void dispose () {

196             body.dispose();

197         }

198         static class Constructor implements Disposable {

199             public final Model model;

200             public final String node;

201             public final btCollisionShape shape;

202             public Constructor(Model model, String node, btCollisionShape shape) {//据说是工厂模式

203                 this.model = model;

204                 this.node = node;

205                 this.shape = shape;

206             }

207 

208             public GameObject construct() {

209                 return new GameObject(model, node, shape);

210             }

211 

212             @Override

213             public void dispose () {

214                 shape.dispose();

215             }

216         }

217     }

218 

219     class MyContactListener extends ContactListener { 220  @Override 221         public boolean onContactAdded (btManifoldPoint cp, btCollisionObjectWrapper colObj0Wrap, int partId0, int index0, 222                                        btCollisionObjectWrapper colObj1Wrap, int partId1, int index1) { 223             instances.get(colObj0Wrap.getCollisionObject().getUserValue()).moving = false; 224             instances.get(colObj1Wrap.getCollisionObject().getUserValue()).moving = false; 225             return true; 226  } 227  } 228 }

注意要设置CF_CUSTOM_MATERIAL_CALLBACK。

碰撞逻辑,我们只是单纯的把moving标记改了一下,目前很简单,但是很显然我们已经把逻辑分清楚了。什么逻辑就要写到什么地方,这很重要。

这个监听貌似实例化出来就可以用了。可能是因为它里面实质上是C++的原理吧。

 

优化:

1. 我们现在不需要btManifoldPoint,所以我们不需要btCollisionObjectWrapper包装,可以改为

class MyContactListener extends ContactListener {

    @Override

    public boolean onContactAdded (btCollisionObject colObj0, int partId0, int index0, btCollisionObject colObj1, int partId1,

        int index1) {

        instances.get(colObj0.getUserValue()).moving = false;

        instances.get(colObj1.getUserValue()).moving = false;

        return true;

    }

}

2. 实际上我们具体在碰撞逻辑上只用到了user value,onContactAdded方法也可以做到的。

class MyContactListener extends ContactListener {

    @Override

    public boolean onContactAdded (int userValue0, int partId0, int index0, int userValue1, int partId1, int index1) {

        instances.get(userValue0).moving = false;

        instances.get(userValue1).moving = false;

        return true;

    }

}

据说这样,C++在回调的时候会省很多事,可能不需要再找java object了吧。

 

你可能感兴趣的:(libgdx)