Android游戲開(kāi)發(fā)學(xué)習(xí)之引擎用法實(shí)例詳解
本文實(shí)例講述了Android游戲開(kāi)發(fā)學(xué)習(xí)之引擎用法。分享給大家供大家參考。具體如下:
汽車引擎是汽車的心臟,其決定了汽車的性能和穩(wěn)定性,是人們?cè)谫?gòu)車時(shí)相當(dāng)關(guān)注的。而游戲中的物理引擎就如汽車的引擎一樣,占據(jù)了非常重要的位置。一款好的物理引擎可以非常真實(shí)地模擬現(xiàn)實(shí)世界,使得游戲更加逼真,提供更好的娛樂(lè)體驗(yàn)。
一、JBox2D簡(jiǎn)介
JBox2D是開(kāi)源物理引擎Box2D的Java版本,可以直接用于Android。由于JBox2D的圖形渲染使用的是Processing庫(kù),因此在Android平臺(tái)上使用JBox2D時(shí),圖形渲染工作只能自行開(kāi)發(fā)。該引擎能夠根據(jù)開(kāi)發(fā)人員設(shè)定的參數(shù),如重力、密度、摩擦系數(shù)和彈性系數(shù)等,自動(dòng)地進(jìn)行2D剛體物理運(yùn)動(dòng)的全方位模擬。
二、示例
1.小球彈跳進(jìn)階版
在第1節(jié)中小球的下落、碰撞、彈起都是用代碼來(lái)維護(hù)的,下面使用物理引擎來(lái)實(shí)現(xiàn),并且加入了剛體之間的碰撞。
(1)常量類Constant
package box2d.bheap; public class Constant { public static final float RATE=10; //屏幕與現(xiàn)實(shí)世界的比例 public static final boolean DRAW_THREAD_FLAG=true; //繪制線程工作標(biāo)識(shí)位 public static final float TIME_STEP=2.0f/60.0f; //模擬的頻率 public static final int ITERA=10; //迭代次數(shù) public static int SCREEN_WIDTH; //屏幕寬度 public static int SCREEN_HEIGHT; //屏幕高度 }
(2)抽象類MyBody
該類為自定義的抽象類,是所有自定義剛體類的基類。由于JBox2D中的剛體類對(duì)象僅具有物理仿真計(jì)算的功能,并沒(méi)有提供Android平臺(tái)下的繪制功能,直接使用不是很方便。因此,這里定義了MyBody對(duì)自定義剛體的繪制及JBox2D物理仿真對(duì)象進(jìn)行了封裝。
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.*; //靜態(tài)導(dǎo)入 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); //設(shè)置顏色 float x=body.getPosition().x*RATE; float y=body.getPosition().y*RATE; canvas.drawCircle(x, y, radius, paint); //畫(huà)圓 paint.setStyle(Style.STROKE); //設(shè)置空心無(wú)填充 paint.setStrokeWidth(1); paint.setColor(color); //畫(huà)邊 canvas.drawCircle(x, y, radius, paint); paint.reset(); //恢復(fù)畫(huà)筆設(shè)置 } }
(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);//設(shè)置線條寬度 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 { /** * 創(chuàng)建矩形物體(顏色) */ public static MyRectColor createBox ( float x, float y, float halfWidth, float halfHeight, boolean isStatic, //是否為靜止的 World world, int color ) { PolygonDef shape=new PolygonDef(); //創(chuàng)建多邊形描述對(duì)象 if(isStatic) { shape.density=0; } else { shape.density=1.0f; } shape.friction=0.0f; //設(shè)置摩擦系數(shù) shape.restitution=0.6f; //設(shè)置能量損失率 shape.setAsBox(halfWidth/RATE, halfHeight/RATE); BodyDef bodyDef=new BodyDef(); //創(chuàng)建剛體描述對(duì)象 bodyDef.position.set(x/RATE,y/RATE); //設(shè)置位置 Body bodyTemp=world.createBody(bodyDef); //在世界中創(chuàng)建剛體 bodyTemp.createShape(shape); //指定剛體形狀 bodyTemp.setMassFromShapes(); //設(shè)置物體質(zhì)量 return new MyRectColor(bodyTemp, halfWidth, halfHeight, color); } /** * 創(chuàng)建圓形物體(顏色) */ public static MyCircleColor createCircle ( float x, float y, float radius, World world, int color ) { CircleDef shape=new CircleDef(); //創(chuàng)建圓描述對(duì)象 shape.density=2; //設(shè)置密度 shape.friction=0.0f; //設(shè)置摩擦系數(shù) shape.restitution=0.95f; //設(shè)置能量損失率 shape.radius=radius/RATE;//設(shè)置半徑 BodyDef bodyDef=new BodyDef(); //創(chuàng)建剛體描述對(duì)象 bodyDef.position.set(x/RATE,y/RATE); //設(shè)置位置 Body bodyTemp=world.createBody(bodyDef); //在世界中創(chuàng)建剛體 bodyTemp.createShape(shape); //指定剛體形狀 bodyTemp.setMassFromShapes(); //設(shè)置物體質(zhì)量 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;//創(chuàng)建 一個(gè)管理碰撞的世界 World world; Random random=new Random(); //物體列表 ArrayList<MyBody> bl=new ArrayList<MyBody>(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //設(shè)置為全屏 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN , WindowManager.LayoutParams. FLAG_FULLSCREEN); //設(shè)置為橫屏模式 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(); //上下界,以屏幕的左上方為 原點(diǎn),如果創(chuàng)建的剛體到達(dá)屏幕的邊緣的話,會(huì)停止模擬 worldAABB.lowerBound.set(-100.0f,-100.0f); worldAABB.upperBound.set(100.0f, 100.0f);//注意這里使用的是現(xiàn)實(shí)世界的單位 Vec2 gravity = new Vec2(0.0f,10.0f); boolean doSleep = true; //創(chuàng)建世界 world = new World(worldAABB, gravity, doSleep); //創(chuàng)建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); //創(chuàng)建磚塊 //磚塊間距 行間距為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) { //左側(cè)藍(lán)木塊 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); } //右側(cè)藍(lán)木塊 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); //創(chuàng)建球 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); //設(shè)置背景顏色白色 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);//開(kāi)始模擬 gv.repaint(); try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } } }
希望本文所述對(duì)大家的jsp程序設(shè)計(jì)有所幫助。
- Android游戲源碼分享之2048
- Android 游戲開(kāi)發(fā)之Canvas畫(huà)布的介紹及方法
- Android游戲開(kāi)發(fā)實(shí)踐之人物移動(dòng)地圖的平滑滾動(dòng)處理
- 解析Android游戲中獲取電話狀態(tài)進(jìn)行游戲暫?;蚶^續(xù)的解決方法
- Unity3D游戲引擎實(shí)現(xiàn)在Android中打開(kāi)WebView的實(shí)例
- Android 游戲引擎libgdx 資源加載進(jìn)度百分比顯示案例分析
- android游戲載入的activity跳轉(zhuǎn)到游戲主菜單的activity具體實(shí)現(xiàn)
- Android游戲開(kāi)發(fā)學(xué)習(xí)①?gòu)椞∏驅(qū)崿F(xiàn)方法
- 以一個(gè)著色游戲展開(kāi)講解Android中區(qū)域圖像填色的方法
- 最常見(jiàn)的猜拳小游戲Android代碼實(shí)現(xiàn)
相關(guān)文章
深入學(xué)習(xí)Kotlin?枚舉的簡(jiǎn)潔又高效進(jìn)階用法
這篇文章主要為大家介紹了深入學(xué)習(xí)Kotlin?枚舉簡(jiǎn)潔又高效的進(jìn)階用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Android開(kāi)發(fā)之Animations動(dòng)畫(huà)用法實(shí)例詳解
這篇文章主要介紹了Android開(kāi)發(fā)之Animations動(dòng)畫(huà)用法,結(jié)合實(shí)例形式詳細(xì)分析了Animations動(dòng)畫(huà)的類型、組成、模式及對(duì)應(yīng)的使用技巧,需要的朋友可以參考下2016-02-02Android?Activity生命周期調(diào)用的理解
大家好。本篇文章主要講的是Android?Activity生命周期調(diào)用的理解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12Android仿硅谷商城實(shí)現(xiàn)購(gòu)物車實(shí)例代碼
這篇文章主要介紹了Android購(gòu)物車編輯實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,一起跟隨小編過(guò)來(lái)看看吧2018-05-05Android自定義RadioGroupX實(shí)現(xiàn)多行多列布局
這篇文章主要為大家詳細(xì)介紹了Android自定義RadioGroupX實(shí)現(xiàn)多行多列布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Android項(xiàng)目實(shí)戰(zhàn)教程之高仿網(wǎng)易云音樂(lè)啟動(dòng)頁(yè)實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Android項(xiàng)目實(shí)戰(zhàn)教程之高仿網(wǎng)易云音樂(lè)啟動(dòng)頁(yè)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09