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-05
Android開(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-02
Android?Activity生命周期調(diào)用的理解
大家好。本篇文章主要講的是Android?Activity生命周期調(diào)用的理解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
Android仿硅谷商城實(shí)現(xiàn)購(gòu)物車實(shí)例代碼
這篇文章主要介紹了Android購(gòu)物車編輯實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,一起跟隨小編過(guò)來(lái)看看吧2018-05-05
Android自定義RadioGroupX實(shí)現(xiàn)多行多列布局
這篇文章主要為大家詳細(xì)介紹了Android自定義RadioGroupX實(shí)現(xiàn)多行多列布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
Android項(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

