[AndEngine学习教程] 第10节 box2D 物理碰撞系统

转自:http://blog.csdn.net/cen616899547/article/details/8190603

 

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张图片,四个精灵和一张背景,内部成员变量如下设计

  1. private staticfinal int CAMERA_WIDTH =800;
  2. private staticfinal int CAMERA_HEIGHT =480;
  3. private staticfinal FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(1,0.5f, 0.5f);
  4. private TiledTextureRegion mBoxRegion;
  5. private TiledTextureRegion mCircleRegion;
  6. private TiledTextureRegion mTriangleRegion;
  7. private TiledTextureRegion mHexagonRegion;
  8. private SpriteBackground mBackground;
  9. private PhysicsWorld mPhysicsWorld;
  10. private int mSpriteCount =0;
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.接着初始化相应的资源

  1. @Override
  2. public EngineOptions onCreateEngineOptions() {
  3. // TODO Auto-generated method stub
  4. SmoothCamera mCamera = new SmoothCamera(0,0, CAMERA_WIDTH, CAMERA_HEIGHT, 10,10, 5);
  5. EngineOptions mEngineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED,new RatioResolutionPolicy(CAMERA_WIDTH,CAMERA_HEIGHT),mCamera);
  6. return mEngineOptions;
  7. }
  8. @Override
  9. public void onCreateResources(
  10. OnCreateResourcesCallback pOnCreateResourcesCallback)
  11. throws Exception {
  12. // TODO Auto-generated method stub
  13. final BitmapTextureAtlas mTexture =new BitmapTextureAtlas(getTextureManager(),1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);;
  14. final TiledTextureRegion mBackgroundRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture,this, "bg.png",0, 0,1, 1);
  15. mBackground = new SpriteBackground(new Sprite(0,0,CAMERA_WIDTH ,CAMERA_HEIGHT , mBackgroundRegion, getVertexBufferObjectManager()));
  16. mBoxRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture,this, "face_box_tiled.png",0, 640,2, 1);
  17. mCircleRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture,this, "face_circle_tiled.png",64, 640,2, 1);
  18. mTriangleRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture,this, "face_triangle_tiled.png",128, 640,2, 1);
  19. mHexagonRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture,this, "face_hexagon_tiled.png",192, 640,2, 1);
  20. mTexture.load();
  21. pOnCreateResourcesCallback.onCreateResourcesFinished();
  22. }
@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参数

  1. Scene mScene = new Scene();
  2. mScene.setBackground(mBackground);
  3. this.enableAccelerationSensor(this);
  4. mScene.setOnSceneTouchListener(this);
                Scene mScene = new Scene();
		mScene.setBackground(mBackground);
		this.enableAccelerationSensor(this);
		mScene.setOnSceneTouchListener(this);


4.有了场景的框架后,我们就开始创建模式的物理世界了,这个世界是有范围的,

我们把它限制在的整个屏幕内:通过屏幕的四条边框进行限制;

  1. this.mPhysicsWorld = new PhysicsWorld(new Vector2(0,SensorManager.GRAVITY_EARTH),false);
  2. final IAreaShape ground = new Rectangle(0, CAMERA_HEIGHT -2, CAMERA_WIDTH, 2, getVertexBufferObjectManager());
  3. final IAreaShape roof =new Rectangle(0,0, CAMERA_WIDTH, 2,getVertexBufferObjectManager());
  4. final IAreaShape left = new Rectangle(0,0,2,CAMERA_HEIGHT,getVertexBufferObjectManager());
  5. final IAreaShape right =new Rectangle(CAMERA_WIDTH-2,0,2,CAMERA_HEIGHT,getVertexBufferObjectManager());
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.在模拟的物理世界中创建精灵实体

  1. final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0,0.5f, 0.5f);
  2. PhysicsFactory.createBoxBody(mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);
  3. PhysicsFactory.createBoxBody(mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
  4. PhysicsFactory.createBoxBody(mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
  5. PhysicsFactory.createBoxBody(mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);
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,是用来描述实体的:比如密度,弹性,和摩擦.这些内容我们在物理学中都有了解的

  1. public static FixtureDef createFixtureDef(finalfloat pDensity, finalfloat pElasticity, finalfloat pFriction) {
  2. return PhysicsFactory.createFixtureDef(pDensity, pElasticity, pFriction,false);
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.把各种角色加载到场景中去:

  1. mScene.attachChild(ground);
  2. mScene.attachChild(roof);
  3. mScene.attachChild(left);
  4. mScene.attachChild(right);
  5. mScene.registerUpdateHandler(this.mPhysicsWorld);
  6. pOnCreateSceneCallback.onCreateSceneFinished(mScene);
mScene.attachChild(ground);
		mScene.attachChild(roof);
		mScene.attachChild(left);
		mScene.attachChild(right);
		
		mScene.registerUpdateHandler(this.mPhysicsWorld);
		
		pOnCreateSceneCallback.onCreateSceneFinished(mScene);


 

5.画龙点睛

1.使用手机上的g-sensor,让物理世界按照实际的倾斜来模拟

  1. @Override
  2. public void onAccelerationAccuracyChanged(AccelerationData pAccelerationData) {
  3. // TODO Auto-generated method stub
  4. }
  5. @Override
  6. public void onAccelerationChanged(AccelerationData pAccelerationData) {
  7. // TODO Auto-generated method stub
  8. this.mPhysicsWorld.setGravity(new Vector2(pAccelerationData.getX(),pAccelerationData.getY()));
  9. }
@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.实现点击屏幕,就在该处产生一个精灵:

  1. @Override
  2. public boolean onSceneTouchEvent(Scene pScene,final TouchEvent pSceneTouchEvent) {
  3. // TODO Auto-generated method stub
  4. if(this.mPhysicsWorld !=null){
  5. if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
  6. this.runOnUpdateThread(new Runnable(){
  7. @Override
  8. public void run() {
  9. // TODO Auto-generated method stub
  10. MyPhysics.this.addFace(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
  11. }
  12. });
  13. }
  14. return true;
  15. }
  16. return false;
  17. }
@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函数

  1. private void addFace(final float pX,final float pY){
  2. final Scene scene = this.mEngine.getScene();
  3. this.mSpriteCount++;
  4. final AnimatedSprite face;
  5. final Body body;
  6. if(this.mSpriteCount %4 == 0){//矩形
  7. face = new AnimatedSprite(pX, pY, mBoxRegion, getVertexBufferObjectManager());
  8. body = PhysicsFactory.createBoxBody(mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
  9. face.animate(250);
  10. scene.attachChild(face);
  11. PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
  12. this.mPhysicsWorld.registerPhysicsConnector(connector);
  13. }
  14. else if(this.mSpriteCount %4 == 1){//圆形
  15. face = new AnimatedSprite(pX,pY,mCircleRegion,getVertexBufferObjectManager() );
  16. body = PhysicsFactory.createCircleBody(mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
  17. face.animate(250);
  18. scene.attachChild(face);
  19. PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
  20. this.mPhysicsWorld.registerPhysicsConnector(connector);
  21. }
  22. else if(this.mSpriteCount %4 == 2){//三角形
  23. face = new AnimatedSprite(pX,pY,mTriangleRegion,getVertexBufferObjectManager() );
  24. final float halfWidth = face.getWidthScaled() *0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
  25. final float halfHeight = face.getHeightScaled() *0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
  26. ArrayList<Vector2> vectors = new ArrayList<Vector2>();
  27. vectors.add(new Vector2(0, - halfHeight));
  28. vectors.add(new Vector2(-halfWidth,halfHeight));
  29. vectors.add(new Vector2(halfWidth, halfHeight));
  30. body = PhysicsFactory.createTrianglulatedBody(mPhysicsWorld, face,vectors,BodyType.DynamicBody, FIXTURE_DEF);
  31. face.animate(250);
  32. scene.attachChild(face);
  33. PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
  34. this.mPhysicsWorld.registerPhysicsConnector(connector);
  35. }
  36. else if(this.mSpriteCount %4 == 3){//六边形
  37. face = new AnimatedSprite(pX,pY,mHexagonRegion,getVertexBufferObjectManager() );
  38. final float halfWidth = face.getWidthScaled() *0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
  39. final float halfHeight = face.getHeightScaled() *0.5f / PIXEL_TO_METER_RATIO_DEFAULT;
  40. /* The top and bottom vertex of the hexagon are on the bottom and top of hexagon-sprite. */
  41. final float top = -halfHeight;
  42. final float bottom = halfHeight;
  43. final float centerX =0;
  44. /* 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. */
  45. final float left = -halfWidth +2.5f / PIXEL_TO_METER_RATIO_DEFAULT;
  46. final float right = halfWidth -2.5f / PIXEL_TO_METER_RATIO_DEFAULT;
  47. final float higher = top +8.25f / PIXEL_TO_METER_RATIO_DEFAULT;
  48. final float lower = bottom -8.25f / PIXEL_TO_METER_RATIO_DEFAULT;
  49. final Vector2[] vertices = {
  50. new Vector2(centerX, top),
  51. new Vector2(right, higher),
  52. new Vector2(right, lower),
  53. new Vector2(centerX, bottom),
  54. new Vector2(left, lower),
  55. new Vector2(left, higher)
  56. };
  57. body = PhysicsFactory.createPolygonBody(mPhysicsWorld, face,vertices,BodyType.DynamicBody, FIXTURE_DEF);
  58. face.animate(250);
  59. scene.attachChild(face);
  60. PhysicsConnector connector = new PhysicsConnector(face,body,true,true);
  61. this.mPhysicsWorld.registerPhysicsConnector(connector);
  62. }
  63. }
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





 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值