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程序设计有所帮助。