1.要点
顾着忙工作的事情,两周多没有写微博了,在上一节,基于AndEngine做了个碰撞检测的例子.这个例子对学习基本原理的作用还是有的,
但是用在游戏上就逊色点了,这节,主要基于Box2D系统来做碰撞检测.
Box2D是一个用于模拟2D刚体物体的c++引擎,这里使用的是AndEngine的扩张插件,为了能够高效高速的使用它,底层的实现都是c++编写的,然后通过jni
调用实现的.所以虽然使用java编写代码,但是运行的也很流畅的.
2.本节学习内容
本节主要学习在AndEngine下引入Box2D插件.然后构建的基本物理实体碰撞.本例子主要实现4中外形的实体碰撞:
矩形实体,圆形实体,三角形实体和正六边形实体;同过触摸屏幕可循环
动态地添加这几种实体.在一个模拟的重力环境下,根据g-sensor的数据来碰撞运动
3.工程配置准备
在本例程的开始,已经讲解了如何配置AndEngine的开发环境.现在主要介绍如何使用Box2D扩张插件
1.到官网下载Box2D插件,网址:https://github.com/nicolasgramlich/AndEnginePhysicsBox2DExtension
2.解压后放到AndEngine同一个目录下,在eclipse下通过file->new->project->Android Project from Exist code,
下一步找到box2d解压的文件夹
点击finish.这是回到eclipse,回出现错误,因为没有包含AndEngine库进去,把鼠标放到box2d工程上,右键:
build path->configurate build path.然后按照下图的方法,导入AndEngine的库
接着把box2d工程下libs的andenginephysicsbox2dextension.jar拷贝到你的工程目录下的libs下面.这样字就完成了最基本可以使用的配置了
如果想要在自己的工程中很好的使用eclipse中提供的自动完成功能,建议在自己的工程中进行如下设置:
1.在工程中右键:build path->configurate build path.选中上边的libraries面板,然后点击add library,如下图所示:
接着next,点击user libraries->new->输入"Box2D"名称
Ok后点击add JARs..,一路点击OK finish就可以了.,最后到初始界面,把Box2D的顺序网上挪动到第二个,就是在AndEngine下面就可以了,这样方便编译.
4.代码编写
1.折腾完基础的东西后,当然华丽丽的写代码啦,本例子主要用到5张图片,四个精灵和一张背景,内部成员变量如下设计
private static final int CAMERA_WIDTH = 800;
private static final int CAMERA_HEIGHT = 480;
private static final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);
private TiledTextureRegion mBoxRegion;
private TiledTextureRegion mCircleRegion;
private TiledTextureRegion mTriangleRegion;
private TiledTextureRegion mHexagonRegion;
private SpriteBackground mBackground;
private PhysicsWorld mPhysicsWorld;
private int mSpriteCount = 0;
PhysicsWorld是这节内容的重点,是基于
Box2D插件来的,具体的内容可以看源代码
2.接着初始化相应的资源
@Override
public EngineOptions onCreateEngineOptions() {
// TODO Auto-generated method stub
SmoothCamera mCamera = new SmoothCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT, 10, 10, 5);
EngineOptions mEngineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED,new RatioResolutionPolicy(CAMERA_WIDTH,CAMERA_HEIGHT),mCamera);
return mEngineOptions;
}
@Override
public void onCreateResources(
OnCreateResourcesCallback pOnCreateResourcesCallback)
throws Exception {
// TODO Auto-generated method stub
final BitmapTextureAtlas mTexture = new BitmapTextureAtlas(getTextureManager(), 1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);;
final TiledTextureRegion mBackgroundRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "bg.png", 0, 0, 1, 1);
mBackground = new SpriteBackground(new Sprite(0, 0,CAMERA_WIDTH ,CAMERA_HEIGHT , mBackgroundRegion, getVertexBufferObjectManager()));
mBoxRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_box_tiled.png", 0, 640, 2, 1);
mCircleRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_circle_tiled.png", 64, 640, 2, 1);
mTriangleRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_triangle_tiled.png", 128, 640, 2, 1);
mHexagonRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_hexagon_tiled.png", 192, 640, 2, 1);
mTexture.load();
pOnCreateResourcesCallback.onCreateResourcesFinished();
}
3.创建场景,配置sensor和touch参数
Scene mScene = new Scene();
mScene.setBackground(mBackground);
this.enableAccelerationSensor(this);
mScene.setOnSceneTouchListener(this);
4.有了场景的框架后,我们就开始创建模式的物理世界了,这个世界是有范围的,
我们把它限制在的整个屏幕内:通过屏幕的四条边框进行限制;
this.mPhysicsWorld = new PhysicsWorld(new Vector2(0,SensorManager.GRAVITY_EARTH), false);
final IAreaShape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2, getVertexBufferObjectManager());
final IAreaShape roof = new Rectangle(0, 0, CAMERA_WIDTH, 2,getVertexBufferObjectManager());
final IAreaShape left = new Rectangle(0,0,2,CAMERA_HEIGHT,getVertexBufferObjectManager());
final IAreaShape right = new Rectangle(CAMERA_WIDTH-2,0,2,CAMERA_HEIGHT,getVertexBufferObjectManager());
5.在模拟的物理世界中创建精灵实体
final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f);
PhysicsFactory.createBoxBody(mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
PhysicsFactory.createBoxBody(mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);
在这里的
Fixture,是用来描述实体的:比如密度,弹性,和摩擦.这些内容我们在物理学中都有了解的
public static FixtureDef createFixtureDef(final float pDensity, final float pElasticity, final float pFriction) {
return PhysicsFactory.createFixtureDef(pDensity, pElasticity, pFriction, false);
BodyType选择的是
StaticBody,因为这里要求的限制框不能随着重力,碰撞等进行移动的,如果要移动的,像我们的精灵一样的,就要使用
BodyType.DynamicBody类型
的啦
6.把各种角色加载到场景中去:
mScene.attachChild(ground);
mScene.attachChild(roof);
mScene.attachChild(left);
mScene.attachChild(right);
mScene.registerUpdateHandler(this.mPhysicsWorld);
pOnCreateSceneCallback.onCreateSceneFinished(mScene);
5.画龙点睛
1.使用手机上的g-sensor,让物理世界按照实际的倾斜来模拟
@Override
public void onAccelerationAccuracyChanged(AccelerationData pAccelerationData) {
// TODO Auto-generated method stub
}
@Override
public void onAccelerationChanged(AccelerationData pAccelerationData) {
// TODO Auto-generated method stub
this.mPhysicsWorld.setGravity(new Vector2(pAccelerationData.getX(),pAccelerationData.getY()));
}
2.实现点击屏幕,就在该处产生一个精灵:
@Override
public boolean onSceneTouchEvent(Scene pScene, final TouchEvent pSceneTouchEvent) {
// TODO Auto-generated method stub
if(this.mPhysicsWorld != null){
if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
this.runOnUpdateThread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
MyPhysics.this.addFace(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
}
});
}
return true;
}
return false;
}
3.实现addFace函数
private void addFace( final float pX, final float pY){
final Scene scene = this.mEngine.getScene();
this.mSpriteCount++;
final AnimatedSprite face;
final Body body;
if(this.mSpriteCount % 4 == 0){//矩形
face = new AnimatedSprite(pX, pY, mBoxRegion, getVertexBufferObjectManager());
body = PhysicsFactory.createBoxBody(mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
face.animate(250);
scene.attachChild(face);
PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
this.mPhysicsWorld.registerPhysicsConnector(connector);
}
else if(this.mSpriteCount % 4 == 1){//圆形
face = new AnimatedSprite(pX,pY,mCircleRegion,getVertexBufferObjectManager() );
body = PhysicsFactory.createCircleBody(mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
face.animate(250);
scene.attachChild(face);
PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
this.mPhysicsWorld.registerPhysicsConnector(connector);
}
else if(this.mSpriteCount % 4 == 2){//三角形
face = new AnimatedSprite(pX,pY,mTriangleRegion,getVertexBufferObjectManager() );
final float halfWidth = face.getWidthScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
final float halfHeight = face.getHeightScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
ArrayList<Vector2> vectors = new ArrayList<Vector2>();
vectors.add(new Vector2(0, - halfHeight));
vectors.add(new Vector2(-halfWidth,halfHeight));
vectors.add(new Vector2(halfWidth, halfHeight));
body = PhysicsFactory.createTrianglulatedBody(mPhysicsWorld, face,vectors,BodyType.DynamicBody, FIXTURE_DEF);
face.animate(250);
scene.attachChild(face);
PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
this.mPhysicsWorld.registerPhysicsConnector(connector);
}
else if(this.mSpriteCount % 4 == 3){//六边形
face = new AnimatedSprite(pX,pY,mHexagonRegion,getVertexBufferObjectManager() );
final float halfWidth = face.getWidthScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
final float halfHeight = face.getHeightScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
/* The top and bottom vertex of the hexagon are on the bottom and top of hexagon-sprite. */
final float top = -halfHeight;
final float bottom = halfHeight;
final float centerX = 0;
/* 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. */
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)
};
body = PhysicsFactory.createPolygonBody(mPhysicsWorld, face,vertices,BodyType.DynamicBody, FIXTURE_DEF);
face.animate(250);
scene.attachChild(face);
PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
this.mPhysicsWorld.registerPhysicsConnector(connector);
}
}
6.运行游戏,看结果
本例子的源代码:http://download.csdn.net/detail/cen616899547/4773538