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

  • 相关阅读:
    [译]kendoui
    [LeetCode] 74 Search a 2D Matrix(二分查找)
    [LeetCode] N皇后问题
    [LeetCode] 5 Longest Palindromic Substring
    [LeetCode] 98 Validate Binary Search Tree
    [LeetCode] 119 Pascal's Triangle II
    [LeetCode] 二叉树相关题目(不完全)
    排序方法的分类和实现
    已知前序(后序)遍历序列和中序遍历序列构建二叉树(Leetcode相关题目)
    拓扑排序(附LeetCode题目)
  • 原文地址:https://www.cnblogs.com/hanhongmin/p/3929968.html
Copyright © 2020-2023  润新知