android游戏引擎andengine学习系列六:Physics物理碰撞效果理解


看到exmaples中的例子:CollisionDetectionExample,看到效果图如下:

android游戏引擎andengine学习系列六:Physics物理碰撞效果理解_第1张图片

 

其实这个例子跟我们前面的绘制虚拟游戏摇杆很像,不同的就是中间有两个sprite,判断碰撞的关键语句如下:

[java]  view plain copy
  1. scene.registerUpdateHandler(new IUpdateHandler() {   //场景注册一个UpdateHandler,每次update都运行一次                                @Override  
  2.             public void reset() { }  
  3.   
  4.             @Override  
  5.             public void onUpdate(final float pSecondsElapsed) {  
  6.                 if(centerRectangle.collidesWith(face)) {  
  7.                     centerRectangle.setColor(100);  //如果两个sprite相碰,则方块sprite变为红色  
  8.                 } else {  
  9.                     centerRectangle.setColor(010);   //如果没有相碰,则变为蓝色  
  10.                 }  
  11.             }  
  12.         });  


另外mCamera.isRectangularShapeVisible(face)判断face是否超出摄像机的视界。

 

 

Physics中的例子都是模仿现实世界中的重力还有碰壁的反弹等物理效果,看下代表性的例子:PhysicsExample

效果如下:

 

实现了IAccelerometerListener重力加速度、IOnSceneTouchListener触屏事件等接口

实现物理效果的步骤如下:

1、创建物理世界

[java]  view plain copy
  1. this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);  

 

2、创建墙壁并加载到scene中

[java]  view plain copy
  1. final Shape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2);  
  2.         final Shape roof = new Rectangle(00, CAMERA_WIDTH, 2);  
  3.         final Shape left = new Rectangle(002, CAMERA_HEIGHT);  
  4.         final Shape right = new Rectangle(CAMERA_WIDTH - 202, CAMERA_HEIGHT);  
  5.   
  6.         final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(00.5f, 0.5f);   //参数分别为密度,弹性,摩擦。  
  7.         PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);  
  8.         PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);  
  9.         PhysicsFactory.createBoxBody(this.mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);  
  10.         PhysicsFactory.createBoxBody(this.mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);  
  11.   
  12.         scene.getBottomLayer().addEntity(ground);  
  13.         scene.getBottomLayer().addEntity(roof);  
  14.         scene.getBottomLayer().addEntity(left);  
  15.         scene.getBottomLayer().addEntity(right);  


3、PhysicsWorld实例用scene.registerUpdateHandler注册到场景

[java]  view plain copy
  1. scene.registerUpdateHandler(this.mPhysicsWorld);  


4、当上面的物理世界创建好了以后,在外部实现IOnSceneTouchListener接口的方法,一触屏便生出一个sprite。

[java]  view plain copy
  1. public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {  
  2.         if(this.mPhysicsWorld != null) {  
  3.             if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {  
  4.                 this.runOnUpdateThread(new Runnable() {  
  5.                     @Override  
  6.                     public void run() {  
  7.                         PhysicsExample.this.addFace(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());  //备注1  
  8.                     }  
  9.                 });  
  10.                 return true;  
  11.             }  
  12.         }  
  13.         return false;  
  14.     }  


以上几步完成之后便可以完成整个的物理世界的碰撞效果了。

 

备注1:该例子中有四种不同的sprite碰撞墙壁,关键语句如下:

[java]  view plain copy
  1. if(this.mFaceCount % 4 == 0) {  
  2.             face = new AnimatedSprite(pX, pY, this.mBoxFaceTextureRegion);  
  3.             body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);  
  4.         } else if (this.mFaceCount % 4 == 1) {  
  5.             face = new AnimatedSprite(pX, pY, this.mCircleFaceTextureRegion);  
  6.             body = PhysicsFactory.createCircleBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);  
  7.         } else if (this.mFaceCount % 4 == 2) {  
  8.             face = new AnimatedSprite(pX, pY, this.mTriangleFaceTextureRegion);  
  9.             body = PhysicsExample.createTriangleBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);  
  10.         } else {  
  11.             face = new AnimatedSprite(pX, pY, this.mHexagonFaceTextureRegion);  
  12.             body = PhysicsExample.createHexagonBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);  
  13.         }  
  14.   
  15.         face.animate(200);  
  16.         face.setUpdatePhysics(false);  
  17.   
  18.         scene.getTopLayer().addEntity(face);  


关于第一种和第二种没什么多说的,和上面创建墙壁的差不多的语法。第三种和第四种创建三角形和六边形的有点复杂,需要计算,看如下原理:
android游戏引擎andengine学习系列六:Physics物理碰撞效果理解_第2张图片先看三角形的精灵的画法,可以先根据三角形sprite得到该sprite的宽和高,当然这里是把他的宽高去一般,为了方便计算,于是可以得到坐标:

      A(0,-H),  B(-W,H),  C(W,H),

这里是根据android的坐标系统来定的。得到了坐标值,于是可以确定Vector2类,关键便是的到这里的vertor2.

再来看看正六边形的原理:

android游戏引擎andengine学习系列六:Physics物理碰撞效果理解_第3张图片同样的我们可以得到W和H,根据数学知识得到BG的长度为:0.5*H,至于具体如何算,可以请教中学的数学老师,于是我们可以得到坐标:

    A(0,-H),  B(W,-0.5H),  C(W,0.5H),  D(0,H),  E(-W,0,.5H),  F(-W,-0.5H);

好了,我们坐标都得到了,可以定义我们的Vertor2的数组:

[java]  view plain copy
  1. final Vector2[] vertices = {  
  2.                 new Vector2(centerX, top),  
  3.                 new Vector2(right, higher),  
  4.                 new Vector2(right, lower),  
  5.                 new Vector2(centerX, bottom),  
  6.                 new Vector2(left, lower),  
  7.                 new Vector2(left, higher)  
  8.         };  //这里面的点的顺序是从顶点,然后按顺时针,也就是我们上面的ABCDEF顺序  

三角形也是一样的,有了vertices,我们便可以得到物理世界的不一样形状的sprite

[java]  view plain copy
  1. return PhysicsFactory.createPolygonBody(pPhysicsWorld, pShape, vertices, pBodyType, pFixtureDef);  


具体的创造六边形的方法:

[java]  view plain copy
  1. private static Body createHexagonBody(final PhysicsWorld pPhysicsWorld, final Shape pShape, final BodyType pBodyType, final FixtureDef pFixtureDef) {  
  2.         /* Remember that the vertices are relative to the center-coordinates of the Shape. */  
  3.         final float halfWidth = pShape.getWidthScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;  
  4.         final float halfHeight = pShape.getHeightScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;  
  5.   
  6.         /* The top and bottom vertex of the hexagon are on the bottom and top of hexagon-sprite. */  
  7.         final float top = -halfHeight;  
  8.         final float bottom = halfHeight;  
  9.   
  10.         final float centerX = 0;  
  11.   
  12.         /* The left and right vertices of the heaxgon are not on the edge of the hexagon-sprite, so we need to inset them a little. */  
  13.         final float left = -halfWidth + 2.5f / PIXEL_TO_METER_RATIO_DEFAULT;  
  14.         final float right = halfWidth - 2.5f / PIXEL_TO_METER_RATIO_DEFAULT;  
  15.         final float higher = top + 8.25f / PIXEL_TO_METER_RATIO_DEFAULT;  
  16.         final float lower = bottom - 8.25f / PIXEL_TO_METER_RATIO_DEFAULT;  
  17.   
  18.         final Vector2[] vertices = {  
  19.                 new Vector2(centerX, top),  
  20.                 new Vector2(right, higher),  
  21.                 new Vector2(right, lower),  
  22.                 new Vector2(centerX, bottom),  
  23.                 new Vector2(left, lower),  
  24.                 new Vector2(left, higher)  
  25.         };  
  26.   
  27.         return PhysicsFactory.createPolygonBody(pPhysicsWorld, pShape, vertices, pBodyType, pFixtureDef);  
  28.     }  


这里面有一点开始我怎么也想不通,就是定义坐标的时候,左右为什么要加减2.5,上下为什么要加减8.25,后来看了图片才知道,纹理png图上的图案并没有全部填满整个纹理png图,上下左右都有一些边距,如下:

改图是被我放大的效果,为了方便大家看得更清楚,看到这里便一下子明白了上面那个问题,至于具体的数字为什么是那么多,肯定是跟像素有关系,有兴趣的同学可以找到这个图片,然后把它放大后慢慢的去数,就会明白啦!


你可能感兴趣的:(java,游戏,android,vector,null,引擎)