看到exmaples中的例子:CollisionDetectionExample,看到效果图如下:
其实这个例子跟我们前面的绘制虚拟游戏摇杆很像,不同的就是中间有两个sprite,判断碰撞的关键语句如下:
- scene.registerUpdateHandler(new IUpdateHandler() {
- public void reset() { }
-
- @Override
- public void onUpdate(final float pSecondsElapsed) {
- if(centerRectangle.collidesWith(face)) {
- centerRectangle.setColor(1, 0, 0);
- } else {
- centerRectangle.setColor(0, 1, 0);
- }
- }
- });
另外mCamera.isRectangularShapeVisible(face)判断face是否超出摄像机的视界。
Physics中的例子都是模仿现实世界中的重力还有碰壁的反弹等物理效果,看下代表性的例子:PhysicsExample
效果如下:
实现了IAccelerometerListener重力加速度、IOnSceneTouchListener触屏事件等接口
实现物理效果的步骤如下:
1、创建物理世界
- this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
2、创建墙壁并加载到scene中
- final Shape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2);
- final Shape roof = new Rectangle(0, 0, CAMERA_WIDTH, 2);
- final Shape left = new Rectangle(0, 0, 2, CAMERA_HEIGHT);
- final Shape right = new Rectangle(CAMERA_WIDTH - 2, 0, 2, CAMERA_HEIGHT);
-
- final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f);
- PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);
- PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
- PhysicsFactory.createBoxBody(this.mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
- PhysicsFactory.createBoxBody(this.mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);
-
- scene.getBottomLayer().addEntity(ground);
- scene.getBottomLayer().addEntity(roof);
- scene.getBottomLayer().addEntity(left);
- scene.getBottomLayer().addEntity(right);
3、把PhysicsWorld实例用scene.registerUpdateHandler注册到场景
- scene.registerUpdateHandler(this.mPhysicsWorld);
4、当上面的物理世界创建好了以后,在外部实现IOnSceneTouchListener接口的方法,一触屏便生出一个sprite。
- public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
- if(this.mPhysicsWorld != null) {
- if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
- this.runOnUpdateThread(new Runnable() {
- @Override
- public void run() {
- PhysicsExample.this.addFace(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
- }
- });
- return true;
- }
- }
- return false;
- }
以上几步完成之后便可以完成整个的物理世界的碰撞效果了。
备注1:该例子中有四种不同的sprite碰撞墙壁,关键语句如下:
- if(this.mFaceCount % 4 == 0) {
- face = new AnimatedSprite(pX, pY, this.mBoxFaceTextureRegion);
- body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
- } else if (this.mFaceCount % 4 == 1) {
- face = new AnimatedSprite(pX, pY, this.mCircleFaceTextureRegion);
- body = PhysicsFactory.createCircleBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
- } else if (this.mFaceCount % 4 == 2) {
- face = new AnimatedSprite(pX, pY, this.mTriangleFaceTextureRegion);
- body = PhysicsExample.createTriangleBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
- } else {
- face = new AnimatedSprite(pX, pY, this.mHexagonFaceTextureRegion);
- body = PhysicsExample.createHexagonBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
- }
-
- face.animate(200);
- face.setUpdatePhysics(false);
-
- scene.getTopLayer().addEntity(face);
关于第一种和第二种没什么多说的,和上面创建墙壁的差不多的语法。第三种和第四种创建三角形和六边形的有点复杂,需要计算,看如下原理:
先看三角形的精灵的画法,可以先根据三角形sprite得到该sprite的宽和高,当然这里是把他的宽高去一般,为了方便计算,于是可以得到坐标:
A(0,-H), B(-W,H), C(W,H),
这里是根据android的坐标系统来定的。得到了坐标值,于是可以确定Vector2类,关键便是的到这里的vertor2.
再来看看正六边形的原理:
同样的我们可以得到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的数组:
- final Vector2[] vertices = {
- new Vector2(centerX, top),
- new Vector2(right, higher),
- new Vector2(right, lower),
- new Vector2(centerX, bottom),
- new Vector2(left, lower),
- new Vector2(left, higher)
- };
三角形也是一样的,有了vertices,我们便可以得到物理世界的不一样形状的sprite
- return PhysicsFactory.createPolygonBody(pPhysicsWorld, pShape, vertices, pBodyType, pFixtureDef);
具体的创造六边形的方法:
- private static Body createHexagonBody(final PhysicsWorld pPhysicsWorld, final Shape pShape, final BodyType pBodyType, final FixtureDef pFixtureDef) {
-
- final float halfWidth = pShape.getWidthScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
- final float halfHeight = pShape.getHeightScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
-
-
- final float top = -halfHeight;
- final float bottom = halfHeight;
-
- final float centerX = 0;
-
-
- final float left = -halfWidth + 2.5f / PIXEL_TO_METER_RATIO_DEFAULT;
- final float right = halfWidth - 2.5f / PIXEL_TO_METER_RATIO_DEFAULT;
- final float higher = top + 8.25f / PIXEL_TO_METER_RATIO_DEFAULT;
- final float lower = bottom - 8.25f / PIXEL_TO_METER_RATIO_DEFAULT;
-
- final Vector2[] vertices = {
- new Vector2(centerX, top),
- new Vector2(right, higher),
- new Vector2(right, lower),
- new Vector2(centerX, bottom),
- new Vector2(left, lower),
- new Vector2(left, higher)
- };
-
- return PhysicsFactory.createPolygonBody(pPhysicsWorld, pShape, vertices, pBodyType, pFixtureDef);
- }
这里面有一点开始我怎么也想不通,就是定义坐标的时候,左右为什么要加减2.5,上下为什么要加减8.25,后来看了图片才知道,纹理png图上的图案并没有全部填满整个纹理png图,上下左右都有一些边距,如下:
改图是被我放大的效果,为了方便大家看得更清楚,看到这里便一下子明白了上面那个问题,至于具体的数字为什么是那么多,肯定是跟像素有关系,有兴趣的同学可以找到这个图片,然后把它放大后慢慢的去数,就会明白啦!