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

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
















评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值