Android游戏开发学习之引擎用法实例详解
程序员文章站
2023-11-12 10:05:10
本文实例讲述了android游戏开发学习之引擎用法。分享给大家供大家参考。具体如下:
汽车引擎是汽车的心脏,其决定了汽车的性能和稳定性,是人们在购车时相当关注的。而游戏中...
本文实例讲述了android游戏开发学习之引擎用法。分享给大家供大家参考。具体如下:
汽车引擎是汽车的心脏,其决定了汽车的性能和稳定性,是人们在购车时相当关注的。而游戏中的物理引擎就如汽车的引擎一样,占据了非常重要的位置。一款好的物理引擎可以非常真实地模拟现实世界,使得游戏更加逼真,提供更好的娱乐体验。
一、jbox2d简介
jbox2d是开源物理引擎box2d的java版本,可以直接用于android。由于jbox2d的图形渲染使用的是processing库,因此在android平台上使用jbox2d时,图形渲染工作只能自行开发。该引擎能够根据开发人员设定的参数,如重力、密度、摩擦系数和弹性系数等,自动地进行2d刚体物理运动的全方位模拟。
二、示例
1.小球弹跳进阶版
在第1节中小球的下落、碰撞、弹起都是用代码来维护的,下面使用物理引擎来实现,并且加入了刚体之间的碰撞。
(1)常量类constant
package box2d.bheap; public class constant { public static final float rate=10; //屏幕与现实世界的比例 public static final boolean draw_thread_flag=true; //绘制线程工作标识位 public static final float time_step=2.0f/60.0f; //模拟的频率 public static final int itera=10; //迭代次数 public static int screen_width; //屏幕宽度 public static int screen_height; //屏幕高度 }
(2)抽象类mybody
该类为自定义的抽象类,是所有自定义刚体类的基类。由于jbox2d中的刚体类对象仅具有物理仿真计算的功能,并没有提供android平台下的绘制功能,直接使用不是很方便。因此,这里定义了mybody对自定义刚体的绘制及jbox2d物理仿真对象进行了封装。
package box2d.bheap; import org.jbox2d.dynamics.body; import android.graphics.canvas; import android.graphics.paint; public abstract class mybody { body body; //jbox2d物理引擎中的刚体 int color; //刚体的颜色 public abstract void drawself(canvas canvas,paint paint); //绘制的方法 }
(3)圆形刚体类mycirclecolor
package box2d.bheap; import org.jbox2d.dynamics.body; import android.graphics.canvas; import android.graphics.paint; import android.graphics.paint.style; import static box2d.bheap.constant.*; //静态导入 public class mycirclecolor extends mybody { float radius; //圆形半径 public mycirclecolor(body body,float radius,int color) { this.body=body; this.radius=radius; this.color=color; } @override public void drawself(canvas canvas, paint paint) { paint.setcolor(color&0xcffffff); //设置颜色 float x=body.getposition().x*rate; float y=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
package box2d.bheap; import static box2d.bheap.constant.rate; import org.jbox2d.dynamics.body; import android.graphics.canvas; import android.graphics.matrix; import android.graphics.paint; public class myrectcolor extends mybody { float halfwidth;//半宽 float halfheight;//半高 public myrectcolor(body body,float halfwidth,float halfheight,int color) { this.body=body; this.halfwidth=halfwidth; this.halfheight=halfheight; this.color=color; } public void drawself(canvas canvas,paint paint) { paint.setcolor(color&0x8cffffff); float x=body.getposition().x*rate; float y=body.getposition().y*rate; float angle=body.getangle(); canvas.save(); matrix m1=new matrix(); 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
package box2d.bheap; import static box2d.bheap.constant.rate; import org.jbox2d.collision.circledef; import org.jbox2d.collision.polygondef; import org.jbox2d.dynamics.body; import org.jbox2d.dynamics.bodydef; import org.jbox2d.dynamics.world; public class box2dutil { /** * 创建矩形物体(颜色) */ public static myrectcolor createbox ( float x, float y, float halfwidth, float halfheight, boolean isstatic, //是否为静止的 world world, int color ) { polygondef shape=new polygondef(); //创建多边形描述对象 if(isstatic) { shape.density=0; } else { shape.density=1.0f; } shape.friction=0.0f; //设置摩擦系数 shape.restitution=0.6f; //设置能量损失率 shape.setasbox(halfwidth/rate, halfheight/rate); bodydef bodydef=new bodydef(); //创建刚体描述对象 bodydef.position.set(x/rate,y/rate); //设置位置 body bodytemp=world.createbody(bodydef); //在世界中创建刚体 bodytemp.createshape(shape); //指定刚体形状 bodytemp.setmassfromshapes(); //设置物体质量 return new myrectcolor(bodytemp, halfwidth, halfheight, color); } /** * 创建圆形物体(颜色) */ public static mycirclecolor createcircle ( float x, float y, float radius, world world, int color ) { circledef shape=new circledef(); //创建圆描述对象 shape.density=2; //设置密度 shape.friction=0.0f; //设置摩擦系数 shape.restitution=0.95f; //设置能量损失率 shape.radius=radius/rate;//设置半径 bodydef bodydef=new bodydef(); //创建刚体描述对象 bodydef.position.set(x/rate,y/rate); //设置位置 body bodytemp=world.createbody(bodydef); //在世界中创建刚体 bodytemp.createshape(shape); //指定刚体形状 bodytemp.setmassfromshapes(); //设置物体质量 return new mycirclecolor(bodytemp, radius, color); } }
(6)颜色工具类colorutil
package box2d.bheap; public class colorutil { static int[][] 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}, }; public static int getcolor(int index) { int[] rgb=result[index%result.length]; int result=0xff000000; result=result|(rgb[0]<<16); result=result|(rgb[1]<<8); result=result|(rgb[2]); return result; } }
(7)主控制类mybox2dactivity
package box2d.bheap; import java.util.arraylist; import java.util.random; import org.jbox2d.collision.aabb; import org.jbox2d.common.vec2; import org.jbox2d.dynamics.world; import android.app.activity; import android.content.pm.activityinfo; import android.os.bundle; import android.util.displaymetrics; import android.view.window; import android.view.windowmanager; import static box2d.bheap.constant.*; public class mybox2dactivity extends activity { aabb worldaabb;//创建 一个管理碰撞的世界 world world; random random=new random(); //物体列表 arraylist<mybody> bl=new arraylist<mybody>(); public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); //设置为全屏 requestwindowfeature(window.feature_no_title); getwindow().setflags(windowmanager.layoutparams. flag_fullscreen , windowmanager.layoutparams. flag_fullscreen); //设置为横屏模式 setrequestedorientation(activityinfo.screen_orientation_portrait); //获取屏幕尺寸 displaymetrics dm=new displaymetrics(); 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 = new aabb(); //上下界,以屏幕的左上方为 原点,如果创建的刚体到达屏幕的边缘的话,会停止模拟 worldaabb.lowerbound.set(-100.0f,-100.0f); worldaabb.upperbound.set(100.0f, 100.0f);//注意这里使用的是现实世界的单位 vec2 gravity = new vec2(0.0f,10.0f); boolean dosleep = true; //创建世界 world = new world(worldaabb, gravity, dosleep); //创建4边 final int kd=40;//宽度或高度 myrectcolor mrc=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块 final int bs=20; final int bw=(int)((screen_width-2*kd-11*bs)/18); //============================================================ for(int i=2;i<10;i++) { if((i%2)==0) { //左侧蓝木块 for(int j=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(int j=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(int j=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); //创建球 mycirclecolor ball=box2dutil.createcircle(screen_width/2-24, kd, kd/2, world,colorutil.getcolor(math.abs(random.nextint()))); bl.add(ball); ball.body.setlinearvelocity(new vec2(0,50)); gameview gv= new gameview(this); setcontentview(gv); } }
(8)显示界面类gameview
package box2d.bheap; import android.graphics.canvas; import android.graphics.paint; import android.view.surfaceholder; import android.view.surfaceholder.callback; import android.view.surfaceview; public class gameview extends surfaceview implements callback{ mybox2dactivity activity; paint paint; drawthread dt; public gameview(mybox2dactivity activity) { super(activity); this.activity=activity; this.getholder().addcallback(this); paint =new paint(); paint.setantialias(true); dt=new drawthread(this); dt.start(); } public void ondraw(canvas canvas) { if(canvas==null) { return ; } canvas.drawargb(255, 255, 255, 255); //设置背景颜色白色 for (mybody mb : activity.bl) { mb.drawself(canvas, paint); } } @override public void surfacechanged(surfaceholder holder, int format, int width, int height) { } @override public void surfacecreated(surfaceholder holder) { repaint(); } @override public void surfacedestroyed(surfaceholder holder) { } public void repaint() { surfaceholder holder=this.getholder(); canvas canvas=holder.lockcanvas(); try { synchronized(holder){ ondraw(canvas); } } catch(exception e){ e.printstacktrace(); } finally { if(canvas!=null) { holder.unlockcanvasandpost(canvas); } } } }
(9)绘制线程类drawthread
package box2d.bheap; import static box2d.bheap.constant.*; //绘制线程 public class drawthread extends thread { gameview gv; public drawthread(gameview gv) { this.gv=gv; } @override public void run() { while(draw_thread_flag) { gv.activity.world.step(time_step, itera);//开始模拟 gv.repaint(); try { thread.sleep(20); } catch (interruptedexception e) { e.printstacktrace(); } } } }
希望本文所述对大家的jsp程序设计有所帮助。