Android游戏开发学习之引擎用法实例详解
本文实例讲述了Android游戏开发学习之引擎用法。分享给大家供大家参考。具体如下:
汽车引擎是汽车的心脏,其决定了汽车的性能和稳定性,是人们在购车时相当关注的。而游戏中的物理引擎就如汽车的引擎一样,占据了非常重要的位置。一款好的物理引擎可以非常真实地模拟现实世界,使得游戏更加逼真,提供更好的娱乐体验。
一、JBox2D简介
JBox2D是开源物理引擎Box2D的Java版本,可以直接用于Android。由于JBox2D的图形渲染使用的是Processing库,因此在Android平台上使用JBox2D时,图形渲染工作只能自行开发。该引擎能够根据开发人员设定的参数,如重力、密度、摩擦系数和弹性系数等,自动地进行2D刚体物理运动的全方位模拟。
二、示例
1.小球弹跳进阶版
在第1节中小球的下落、碰撞、弹起都是用代码来维护的,下面使用物理引擎来实现,并且加入了刚体之间的碰撞。
(1)常量类Constant
packagebox2d.bheap; publicclassConstant{ publicstaticfinalfloatRATE=10;//屏幕与现实世界的比例 publicstaticfinalbooleanDRAW_THREAD_FLAG=true;//绘制线程工作标识位 publicstaticfinalfloatTIME_STEP=2.0f/60.0f;//模拟的频率 publicstaticfinalintITERA=10;//迭代次数 publicstaticintSCREEN_WIDTH;//屏幕宽度 publicstaticintSCREEN_HEIGHT;//屏幕高度 }
(2)抽象类MyBody
该类为自定义的抽象类,是所有自定义刚体类的基类。由于JBox2D中的刚体类对象仅具有物理仿真计算的功能,并没有提供Android平台下的绘制功能,直接使用不是很方便。因此,这里定义了MyBody对自定义刚体的绘制及JBox2D物理仿真对象进行了封装。
packagebox2d.bheap; importorg.jbox2d.dynamics.Body; importandroid.graphics.Canvas; importandroid.graphics.Paint; publicabstractclassMyBody{ Bodybody;//JBox2D物理引擎中的刚体 intcolor;//刚体的颜色 publicabstractvoiddrawSelf(Canvascanvas,Paintpaint);//绘制的方法 }
(3)圆形刚体类MyCircleColor
packagebox2d.bheap; importorg.jbox2d.dynamics.Body; importandroid.graphics.Canvas; importandroid.graphics.Paint; importandroid.graphics.Paint.Style; importstaticbox2d.bheap.Constant.*;//静态导入 publicclassMyCircleColorextendsMyBody{ floatradius;//圆形半径 publicMyCircleColor(Bodybody,floatradius,intcolor){ this.body=body; this.radius=radius; this.color=color; } @Override publicvoiddrawSelf(Canvascanvas,Paintpaint){ paint.setColor(color&0xCFFFFFF);//设置颜色 floatx=body.getPosition().x*RATE; floaty=body.getPosition().y*RATE; canvas.drawCircle(x,y,radius,paint);//画圆 paint.setStyle(Style.STROKE);//设置空心无填充 paint.setStrokeWidth(1); paint.setColor(color);//画边 canvas.drawCircle(x,y,radius,paint); paint.reset();//恢复画笔设置 } }
(4)矩形刚体类MyRectColor
packagebox2d.bheap; importstaticbox2d.bheap.Constant.RATE; importorg.jbox2d.dynamics.Body; importandroid.graphics.Canvas; importandroid.graphics.Matrix; importandroid.graphics.Paint; publicclassMyRectColorextendsMyBody{ floathalfWidth;//半宽 floathalfHeight;//半高 publicMyRectColor(Bodybody,floathalfWidth,floathalfHeight,intcolor) { this.body=body; this.halfWidth=halfWidth; this.halfHeight=halfHeight; this.color=color; } publicvoiddrawSelf(Canvascanvas,Paintpaint) { paint.setColor(color&0x8CFFFFFF); floatx=body.getPosition().x*RATE; floaty=body.getPosition().y*RATE; floatangle=body.getAngle(); canvas.save(); Matrixm1=newMatrix(); m1.setRotate((float)Math.toDegrees(angle),x,y); canvas.setMatrix(m1); canvas.drawRect(x-halfWidth,y-halfHeight,x+halfWidth,y+halfHeight,paint); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(1);//设置线条宽度 paint.setColor(color); canvas.drawRect(x-halfWidth,y-halfHeight,x+halfWidth,y+halfHeight,paint); paint.reset(); canvas.restore(); } }
(5)生成刚体形状的工具类Box2DUtil
packagebox2d.bheap; importstaticbox2d.bheap.Constant.RATE; importorg.jbox2d.collision.CircleDef; importorg.jbox2d.collision.PolygonDef; importorg.jbox2d.dynamics.Body; importorg.jbox2d.dynamics.BodyDef; importorg.jbox2d.dynamics.World; publicclassBox2DUtil{ /** *创建矩形物体(颜色) */ publicstaticMyRectColorcreateBox( floatx, floaty, floathalfWidth, floathalfHeight, booleanisStatic,//是否为静止的 Worldworld, intcolor ){ PolygonDefshape=newPolygonDef();//创建多边形描述对象 if(isStatic){ shape.density=0; }else{ shape.density=1.0f; } shape.friction=0.0f;//设置摩擦系数 shape.restitution=0.6f;//设置能量损失率 shape.setAsBox(halfWidth/RATE,halfHeight/RATE); BodyDefbodyDef=newBodyDef();//创建刚体描述对象 bodyDef.position.set(x/RATE,y/RATE);//设置位置 BodybodyTemp=world.createBody(bodyDef);//在世界中创建刚体 bodyTemp.createShape(shape);//指定刚体形状 bodyTemp.setMassFromShapes();//设置物体质量 returnnewMyRectColor(bodyTemp,halfWidth,halfHeight,color); } /** *创建圆形物体(颜色) */ publicstaticMyCircleColorcreateCircle( floatx, floaty, floatradius, Worldworld, intcolor ){ CircleDefshape=newCircleDef();//创建圆描述对象 shape.density=2;//设置密度 shape.friction=0.0f;//设置摩擦系数 shape.restitution=0.95f;//设置能量损失率 shape.radius=radius/RATE;//设置半径 BodyDefbodyDef=newBodyDef();//创建刚体描述对象 bodyDef.position.set(x/RATE,y/RATE);//设置位置 BodybodyTemp=world.createBody(bodyDef);//在世界中创建刚体 bodyTemp.createShape(shape);//指定刚体形状 bodyTemp.setMassFromShapes();//设置物体质量 returnnewMyCircleColor(bodyTemp,radius,color); } }
(6)颜色工具类ColorUtil
packagebox2d.bheap; publicclassColorUtil{ staticint[][]result= { {56,225,254}, {41,246,239}, {34,244,197}, {44,241,161}, {65,239,106}, {45,238,59}, {73,244,51}, {99,233,58}, {129,243,34}, {142,245,44}, {187,243,32}, {232,250,28}, {242,230,46}, {248,196,51}, {244,125,31}, {247,88,46}, {249,70,40}, {249,70,40}, {248,48,48}, {250,30,30}, {252,15,15}, {255,0,0}, }; publicstaticintgetColor(intindex) { int[]rgb=result[index%result.length]; intresult=0xff000000; result=result|(rgb[0]<<16); result=result|(rgb[1]<<8); result=result|(rgb[2]); returnresult; } }
(7)主控制类MyBox2dActivity
packagebox2d.bheap; importjava.util.ArrayList; importjava.util.Random; importorg.jbox2d.collision.AABB; importorg.jbox2d.common.Vec2; importorg.jbox2d.dynamics.World; importandroid.app.Activity; importandroid.content.pm.ActivityInfo; importandroid.os.Bundle; importandroid.util.DisplayMetrics; importandroid.view.Window; importandroid.view.WindowManager; importstaticbox2d.bheap.Constant.*; publicclassMyBox2dActivityextendsActivity { AABBworldAABB;//创建一个管理碰撞的世界 Worldworld; Randomrandom=newRandom(); //物体列表 ArrayList<MyBody>bl=newArrayList<MyBody>(); publicvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); //设置为全屏 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置为横屏模式 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //获取屏幕尺寸 DisplayMetricsdm=newDisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); if(dm.widthPixels<dm.heightPixels) { SCREEN_WIDTH=dm.widthPixels; SCREEN_HEIGHT=dm.heightPixels; } else { SCREEN_WIDTH=dm.heightPixels; SCREEN_HEIGHT=dm.widthPixels; } worldAABB=newAABB(); //上下界,以屏幕的左上方为原点,如果创建的刚体到达屏幕的边缘的话,会停止模拟 worldAABB.lowerBound.set(-100.0f,-100.0f); worldAABB.upperBound.set(100.0f,100.0f);//注意这里使用的是现实世界的单位 Vec2gravity=newVec2(0.0f,10.0f); booleandoSleep=true; //创建世界 world=newWorld(worldAABB,gravity,doSleep); //创建4边 finalintkd=40;//宽度或高度 MyRectColormrc=Box2DUtil.createBox(kd/4,SCREEN_HEIGHT/2,kd/4,SCREEN_HEIGHT/2,true,world,0xFFe6e4FF); bl.add(mrc); mrc=Box2DUtil.createBox(SCREEN_WIDTH-kd/4,SCREEN_HEIGHT/2,kd/4,SCREEN_HEIGHT/2,true,world,0xFFe6e4FF); bl.add(mrc); mrc=Box2DUtil.createBox(SCREEN_WIDTH/2,kd/4,SCREEN_WIDTH/2,kd/4,true,world,0xFFe6e4FF); bl.add(mrc); mrc=Box2DUtil.createBox(SCREEN_WIDTH/2,SCREEN_HEIGHT-kd/4,SCREEN_WIDTH/2,kd/4,true,world,0xFFe6e4FF); bl.add(mrc); //创建砖块 //砖块间距行间距为20模块宽度为10最多一行为9块 finalintbs=20; finalintbw=(int)((SCREEN_WIDTH-2*kd-11*bs)/18); //============================================================ for(inti=2;i<10;i++) { if((i%2)==0) { //左侧蓝木块 for(intj=0;j<9-i;j++) { mrc=Box2DUtil.createBox ( kd/2+bs+bw/2+i*(kd+5)/2+j*(kd+5)+3, SCREEN_HEIGHT+bw-i*(bw+kd)/2, bw/2, kd/2, false, world, ColorUtil.getColor(Math.abs(random.nextInt())) ); bl.add(mrc); } //右侧蓝木块 for(intj=0;j<9-i;j++) { mrc=Box2DUtil.createBox ( 3*kd/2+bs-bw/2+i*(kd+5)/2+j*(kd+5)-3, SCREEN_HEIGHT+bw-i*(bw+kd)/2, bw/2, kd/2, false, world, ColorUtil.getColor(Math.abs(random.nextInt())) ); bl.add(mrc); } } if((i%2)!=0) { for(intj=0;j<10-i;j++) { mrc=Box2DUtil.createBox ( kd/2+bs+kd/2+(i-1)*(kd+5)/2+j*(kd+5), SCREEN_HEIGHT-(kd-bw)/2-(i-1)*(bw+kd)/2, kd/2, bw/2, false, world, ColorUtil.getColor(Math.abs(random.nextInt())) ); bl.add(mrc); } } } mrc=Box2DUtil.createBox ( 5*kd+bs+20, SCREEN_HEIGHT-(kd+bw)*4-kd, bw/2, kd/2, false, world, ColorUtil.getColor(Math.abs(random.nextInt())) ); bl.add(mrc); //创建球 MyCircleColorball=Box2DUtil.createCircle(SCREEN_WIDTH/2-24,kd,kd/2,world,ColorUtil.getColor(Math.abs(random.nextInt()))); bl.add(ball); ball.body.setLinearVelocity(newVec2(0,50)); GameViewgv=newGameView(this); setContentView(gv); } }
(8)显示界面类GameView
packagebox2d.bheap; importandroid.graphics.Canvas; importandroid.graphics.Paint; importandroid.view.SurfaceHolder; importandroid.view.SurfaceHolder.Callback; importandroid.view.SurfaceView; publicclassGameViewextendsSurfaceViewimplementsCallback{ MyBox2dActivityactivity; Paintpaint; DrawThreaddt; publicGameView(MyBox2dActivityactivity){ super(activity); this.activity=activity; this.getHolder().addCallback(this); paint=newPaint(); paint.setAntiAlias(true); dt=newDrawThread(this); dt.start(); } publicvoidonDraw(Canvascanvas){ if(canvas==null){ return; } canvas.drawARGB(255,255,255,255);//设置背景颜色白色 for(MyBodymb:activity.bl){ mb.drawSelf(canvas,paint); } } @Override publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth, intheight){ } @Override publicvoidsurfaceCreated(SurfaceHolderholder){ repaint(); } @Override publicvoidsurfaceDestroyed(SurfaceHolderholder){ } publicvoidrepaint(){ SurfaceHolderholder=this.getHolder(); Canvascanvas=holder.lockCanvas(); try{ synchronized(holder){ onDraw(canvas); } }catch(Exceptione){ e.printStackTrace(); }finally{ if(canvas!=null){ holder.unlockCanvasAndPost(canvas); } } } }
(9)绘制线程类DrawThread
packagebox2d.bheap; importstaticbox2d.bheap.Constant.*; //绘制线程 publicclassDrawThreadextendsThread { GameViewgv; publicDrawThread(GameViewgv) { this.gv=gv; } @Override publicvoidrun() { while(DRAW_THREAD_FLAG) { gv.activity.world.step(TIME_STEP,ITERA);//开始模拟 gv.repaint(); try { Thread.sleep(20); }catch(InterruptedExceptione) { e.printStackTrace(); } } } }
希望本文所述对大家的jsp程序设计有所帮助。