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了吧。

 

转载于:https://www.cnblogs.com/hanhongmin/p/3929968.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值