亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android游戲開發學習①彈跳小球實現方法

2020-04-11 11:23:27
字體:
來源:轉載
供稿:網友

本文實例講述了Android游戲開發學習①彈跳小球實現方法。分享給大家供大家參考。具體如下:

在學習了一點點Android之后,覺得有必要記錄下來,于是就開了這個新坑,慢慢來填吧。

1.運動體Movable類

本例主要模擬了一組大小不一的球以一定的水平初速度從高處落下的運動軌跡。其中的小球為一個可移動物體Movable對象,該類中除了包含小球圖片對象之外,還包括了如位置坐標、水平速度、垂直速度等一系列用于模擬小球運動的成員變量和一些方法。

Movable類:

package com.ball; import android.graphics.Bitmap; import android.graphics.Canvas; public class Movable {  int startX = 0;    // 初始X坐標  int startY = 0;    // 初始Y坐標  int x;    // 實時X坐標  int y;    // 實時Y坐標  float startVX = 0f;   // 初始水平方向的速度  float startVY = 0f;   // 初始豎直方向的速度  float v_x = 0f;    // 實時水平方向的速度  float v_y = 0f;   // 實時豎直方向的速度  int r;    // 可移動物體半徑  double timeX;   // X方向上的運動時間  double timeY;   // Y方向上的運動時間  Bitmap bitmap=null;   // 可移動物體圖片  BallThread bt=null;   // 負責小球移動  boolean bFall=false;  // 小球是否已經從木板上下落  float impactFactor=0.25f;  // 小球撞地后速度的損失系數  public Movable(int x,int y,int r,Bitmap bitmap) {   this.startX=x;   this.x=x;   this.startY=y;   this.y=y;   this.r=r;   this.bitmap=bitmap;   timeX=System.nanoTime(); // 獲取系統時間初始化timeX   this.v_x=BallView.V_MIN+(int)((BallView.V_MAX-BallView.V_MIN)*Math.random());   bt=new BallThread(this); // 創建并啟動BallThread   bt.start();  }  public void drawSelf(Canvas canvas) {   canvas.drawBitmap(bitmap,x,y,null);  } }

startX和startY變量記錄每一個運動階段(如從最高點下落到最低點)開始時小球的初始X、Y坐標,在隨后的物理計算中,小球的實時X、Y坐標將會是初始坐標加上這段時間內的位移。

startVX和startVY是小球每一個運動階段初始時刻在水平方向X和豎直方向Y方向上的速度,兩者將用于計算小球的實時速度v_x和v_y。

timeX和timeY分別代表小球在水平和豎直方向上運動的持續時間,當小球從一個階段運行到下一個階段時(如從下落階段彈起后轉入上拋階段),timeX和timeY將會被重置。

BallThread對象繼承自Thread線程類,起到了物理引擎的作用,負責根據物理公式對球的位置坐標等屬性進行修改,從而改變球的運動軌跡。

布爾變量bFall用于標識小球是否已經從木板上落下,在程序運行時屏幕的左上部分會有一個木板,所有的小球從木板開始向右進行平拋運動。bFall為false時代表小球仍然在木板上移動,還未落下。

float變量impactFactor作用是當小球撞到地面上后根據其值對小球水平和豎直方向的速度進行衰減。

構造函數中對部分成員變量進行初始化,并啟動物理引擎。

構造函數中BallView類的兩個常量V_MIN和V_MAX分別代表小球水平方向速度的最小值和最大值,此處用于生成小球的隨機水平速度。

2.小球物理引擎BallThread類

首先解釋一下此物理引擎的工作機制,了解其是如何改變小球的運動軌跡的。
運動階段,本例中將小球的運動按照豎直方向的速度分為若干個階段,每個階段中小球在豎直方向上的速度的大小或者是一直增大(下落),或者是一直減?。ㄉ仙?。即每當小球在豎直方向上的速度發生改變時(如撞地或達到空中最高點),小球就結束該階段的運動進入一個新的階段。

數值計算,在每個階段開始,都會記錄下開始的時間,同時還會記錄在這個階段小球的初始X、Y坐標,初始X、Y方向上的速度等物理量。之后在這個階段的運動中,小球的各項實時數據都根據這些記錄的物理量以及當前時間計算得出。

為零判斷,在小球上升的運動中和小球撞擊地面后,都需要判斷小球的速度是否為零。但是不同于真實的世界,在程序中小球的各項物理量都是離散的(即每隔固定的時間計算出這些物理量的值),小球實際的運動軌跡為一個個離散點。這種情況下如果還采用判斷是否為零的方式就有可能出現錯誤(如在前一次的計算中小球速度為正,下一次的計算為負,跳過了速度為零這個轉折點,小球將永遠不可能出現為零這個時刻)。所以在程序中使用了閾值的方式,小球的速度一旦小于某個閾值,就將其認定為零。

BallThread類:

package com.ball; public class BallThread extends Thread {  Movable father; // Movable對象引用  boolean flag = false; // 線程執行標識位  int sleepSpan = 40; // 休眠時間  float g = 200; // 球下落的加速度  double current; // 記錄當前時間  public BallThread(Movable father) {   this.father = father;   this.flag = true;  }  @Override  public void run() {   while (flag) {    current = System.nanoTime(); // 獲取當前時間,單位為納秒,處理水平方向上的運動    double timeSpanX = (double) ((current - father.timeX) / 1000 / 1000 / 1000); // 獲取水平方向走過的時間    father.x = (int) (father.startX + father.v_x * timeSpanX);    if (father.bFall) { // 處理豎直方向上的運動,判斷球是否已經移出擋板     double timeSpanY = (double) ((current - father.timeY) / 1000 / 1000 / 1000);     father.y = (int) (father.startY + father.startVY * timeSpanY + timeSpanY       * timeSpanY * g / 2);     father.v_y = (float) (father.startVY + g * timeSpanY);     //此處先省略檢測和處理特殊事件的代碼,隨后補全    } else if (father.x + father.r / 2 >= BallView.WOOD_EDGE) {// 通過X坐標判斷球是否移出了擋板     father.timeY = System.nanoTime();     father.bFall = true; // 確定下落    }    try {     Thread.sleep(sleepSpan);    } catch (Exception e) {     e.printStackTrace();    }   }  } }

代表重力加速度的變量g初始化為200,此值是經過測試得出的較為合理的值。

run方法處理小球在水平方向的運動時,先根據當前時間獲得本階段中從開始到現在小球在水平方向上運動的時間,然后用該階段中到目前為止小球的位移加上小球在該階段的初始位置,求出小球此時的X坐標。

run方法處理小球在豎直方向的運動時,先檢查小球的bFall是否為true,如果為true表明小球已經可以下落,進行物理計算;如果為false則使用X坐標進行判斷是否需要將其設置為true。

使用到的BallView類的常量WOOD_EDGE記錄著木板圖片的最右邊的X坐標值,如果小球的水平位置超過該值就需要下落了。

剛才省略的檢測代碼如下:

// 判斷小球是否到達最高點 if (father.startVY < 0 && Math.abs(father.v_y) <= BallView.UP_ZERO) {  father.timeY = System.nanoTime();  father.v_y = 0;  father.startVY = 0;  father.startY = father.y; } // 判斷小球是否撞地 if (father.y + father.r * 2 >= BallView.GROUND_LING && father.v_y > 0) {  father.v_x = father.v_x * (1 - father.impactFactor); // 衰減水平方向的速度  father.v_y = 0 - father.v_y * (1 - father.impactFactor); // 衰減豎直方向的速度并改變方向  if (Math.abs(father.v_y) < BallView.DOWN_ZERO) { // 判斷撞地衰減后的速度,太小就停止運動   this.flag = false;  } else {   // 撞地后的速度還可以彈起繼續下一階段的運動   father.startX = father.x;   father.timeX = System.nanoTime();   father.startY = father.y;   father.timeY = System.nanoTime();   father.startVY = father.v_y;  } }

3.視圖類BallView

BallView是負責畫面渲染的視圖類,其中聲明了一些物理計算時要使用的靜態常量,同時還聲明了程序中要繪制的圖片資源以及要繪制的小球對象列表。BallView類繼承自android.view包下SurfaceView類。SurfaceView不同于普通的View,其具有不同的繪制機理,適合用于開發游戲程序。使用SurfaceView需要實現SurfaceHolder.Callback接口,該接口可以對SurfaceView進行編輯等操作,還可以監控SurfaceView的變化。

BallView類:

package com.ball; import java.util.ArrayList; import java.util.Random; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import com.bp.R; public class BallView extends SurfaceView implements Callback {  public static final int V_MAX=35;  public static final int V_MIN=15;  public static final int WOOD_EDGE=60;  public static final int GROUND_LING=450; //代表地面的Y坐標,小球下落到此會彈起  public static final int UP_ZERO=30; //小球在上升過程中,速度小于該值就算0  public static final int DOWN_ZERO=60; //小球在撞擊地面后,速度小于該值就算0  Bitmap[] bitmapArray =new Bitmap[6];  Bitmap bmpBack; //背景圖片  Bitmap bmpWood; // 擋板圖片  String fps="FPS:N/A"; //用于顯示幀速率的字符串  int ballNumber =8; //小球數目  ArrayList<Movable> alMovable=new ArrayList<Movable>(); //小球對象數組  DrawThread dt; //后臺屏幕繪制線程  public BallView(Context activity) {   super(activity);   getHolder().addCallback(this);   initBitmaps(getResources()); //初始化圖片   initMovables(); //初始化小球   dt=new DrawThread(this,getHolder()); //初始化重繪線程  }  public void initBitmaps(Resources r) {   bitmapArray[0]=BitmapFactory.decodeResource(r, R.drawable.ball_red_small);   bitmapArray[1]=BitmapFactory.decodeResource(r, R.drawable.ball_purple_small);   bitmapArray[2]=BitmapFactory.decodeResource(r, R.drawable.ball_green_small);   bitmapArray[3]=BitmapFactory.decodeResource(r, R.drawable.ball_red);   bitmapArray[4]=BitmapFactory.decodeResource(r, R.drawable.ball_purple);   bitmapArray[5]=BitmapFactory.decodeResource(r, R.drawable.ball_green);   bmpBack=BitmapFactory.decodeResource(r, R.drawable.back);   bmpWood=BitmapFactory.decodeResource(r, R.drawable.wood);  }  public void initMovables() {   Random r=new Random();   for(int i=0;i<ballNumber;i++) {    int index=r.nextInt(32);    Bitmap tempBitmap=null;    if(i<ballNumber/2) { //如果是初始化前一半球,就從大球中隨機找一個     tempBitmap=bitmapArray[3+index%3];    } else { //如果是初始化前一半球,就從小球中隨機找一個     tempBitmap=bitmapArray[index%3];    }    //創建Movable對象    Movable m=new Movable(0, 70-tempBitmap.getHeight(), tempBitmap.getWidth()/2, tempBitmap);    alMovable.add(m); //加入列表中   }  }  public void doDraw(Canvas canvas) { //繪制程序中需要的圖片等信息   canvas.drawBitmap(bmpBack, 0, 0,null);   canvas.drawBitmap(bmpWood, 0, 60,null);   for (Movable m : alMovable) { //遍歷繪制每個Movable對象    m.drawSelf(canvas);   }   Paint p=new Paint();   p.setColor(Color.BLUE);   p.setTextSize(18);   p.setAntiAlias(true); //設置抗鋸齒   canvas.drawText(fps, 30, 30, p); //畫出幀速率字符串  }  @Override  public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {  }  @Override  public void surfaceCreated(SurfaceHolder arg0) {   if(!dt.isAlive()) {    dt.start();   }  }  @Override  public void surfaceDestroyed(SurfaceHolder arg0) {   dt.flag=false;   dt=null;  } }

因為bitmapArray數組中的圖片分為大尺寸和小尺寸,為了繪制圖片時,小尺寸圖片不會被擋住,所以先使用大尺寸圖片。

doDraw方法會在DrawThread中調用,用于繪制圖片和幀速率。

4.繪制線程DrawThread類

DrawThread類:

package com.ball; import android.graphics.Canvas; import android.view.SurfaceHolder; public class DrawThread extends Thread {  BallView bv;  SurfaceHolder surfaceHolder;  boolean flag=false;  int sleepSpan=30;  long start =System.nanoTime(); //記錄起始時間,該變量用于計算幀速率  int count=0 ; //記錄幀數  public DrawThread(BallView bv,SurfaceHolder surfaceHolder) {   this.bv=bv;   this.surfaceHolder=surfaceHolder;   this.flag=true;  }  public void run() {   Canvas canvas=null;   while(flag) {    try {     canvas=surfaceHolder.lockCanvas(null); //獲取BallView的畫布     synchronized (surfaceHolder) {      bv.doDraw(canvas);     }    } catch (Exception e) {     e.printStackTrace();    } finally {     if(canvas!=null) {      surfaceHolder.unlockCanvasAndPost(canvas); // surfaceHolder解鎖,并將畫布傳回     }    }    this.count++;    if(count==20) { //計滿20幀時計算一次幀速率     count=0;     long tempStamp=System.nanoTime();     long span=tempStamp-start;     start=tempStamp;     double fps=Math.round(100000000000.0/span*20)/100.0;     bv.fps="FPS:"+fps;    }    try {     Thread.sleep(sleepSpan);    } catch (InterruptedException e) {     e.printStackTrace();    }   }  } }

代碼中調用了BallView的屏幕重繪函數doDraw,其實現機制是現將BalView的畫布加鎖,然后調用BallView的doDraw方法對BallView的畫布進行重新繪制。最后解鎖BallView的畫布并將其傳回。

計算幀速率的方法是,首先求出程序繪制20幀所消耗的時間span,然后計算100s內能夠包含幾個span。100s內包含的span個數乘以20就能得出100s內能夠繪制幾幀,再除以100就可求得1s內繪制的幀數。

5.MainActivity類

MainActivity類:

package com.ball; import android.app.Activity; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity {  BallView bv;  @Override  public void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   requestWindowFeature(Window.FEATURE_NO_TITLE); //設置不顯示標題  getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //設置全屏  bv=new BallView(this);   setContentView(bv); }}

運行效果圖:

使用到的資源文件:

希望本文所述對大家的Android程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产亚洲美女精品久久久| 国产97在线|日韩| 欧美日韩国产精品一区二区不卡中文| 91国偷自产一区二区三区的观看方式| 中文字幕在线观看亚洲| 不卡av日日日| 亚洲图片欧美午夜| 国产一区二区三区在线| 91色在线观看| 成人激情av在线| 日韩精品高清在线| 亚洲区bt下载| 亚洲国产福利在线| 亚洲精品久久久久中文字幕欢迎你| 国产一区二区精品丝袜| 国产日韩中文字幕| 91系列在线观看| 欧美高清视频在线播放| 欧美国产日韩一区二区三区| 久久久中精品2020中文| 国产视频在线观看一区二区| 中文字幕日韩专区| 国产精品91在线观看| 欧美成人精品一区二区| 日韩经典中文字幕在线观看| 久久久久久久国产精品视频| 亚洲精品国产电影| 亚洲激情在线观看视频免费| 亚洲成人黄色网址| 日韩av影院在线观看| 国产激情视频一区| 97在线免费视频| 国模吧一区二区三区| 亚洲成人精品av| 久久久免费精品| 免费av一区二区| 国产一区二区动漫| 国产婷婷色综合av蜜臀av| 亚洲成人中文字幕| 一区二区欧美久久| 久久午夜a级毛片| 91高潮在线观看| 亚洲国产欧美一区二区丝袜黑人| 国产成人在线播放| 91在线视频精品| 日韩在线观看免费网站| 亚洲国产日韩精品在线| 国产成人精品在线视频| 韩国一区二区电影| 日韩精品久久久久久福利| 欧美乱人伦中文字幕在线| 日韩黄色在线免费观看| 一本色道久久88综合亚洲精品ⅰ| 亚洲日韩第一页| 亚洲自拍偷拍色图| 亚洲高清在线观看| 国产成人av网址| 国产精品日本精品| 国内精品400部情侣激情| 欧美野外猛男的大粗鳮| 亚洲国产欧美一区二区三区同亚洲| 欧美黑人xxx| 欧美壮男野外gaytube| 日韩欧亚中文在线| 国产亚洲精品激情久久| 欧美激情亚洲自拍| 国产精品自拍小视频| 国产一区二区三区三区在线观看| 国产日韩av高清| 久久国产精品免费视频| 国产精品中文在线| 色哟哟入口国产精品| 久久不射热爱视频精品| 精品女同一区二区三区在线播放| 91av视频在线| 国产精品v片在线观看不卡| 国产亚洲精品久久久优势| 欧美性猛交xxxx| 亚洲情综合五月天| 亚洲国产另类久久精品| 国产精品久久久| 欧美日韩人人澡狠狠躁视频| 亚洲无亚洲人成网站77777| 91亚洲午夜在线| 中文字幕亚洲综合久久筱田步美| 青青草99啪国产免费| 国产亚洲精品一区二区| 欧美精品手机在线| 日韩精品福利网站| 久久亚洲精品成人| 一区二区三区视频在线| 亚洲综合中文字幕68页| 国产美女主播一区| 成人国产精品免费视频| 色一情一乱一区二区| 丝袜亚洲另类欧美重口| 欧美成人中文字幕| 国产一区二区三区18| 国产成人精品网站| 成人国产在线激情| 亚洲国产高清自拍| 日韩美女免费观看| 国产网站欧美日韩免费精品在线观看| 夜色77av精品影院| 一个人www欧美| 亚洲欧美日韩精品久久奇米色影视| 亚洲高清久久久久久| 亚洲女人初尝黑人巨大| 欧美国产日韩一区二区在线观看| 欧美午夜激情视频| 亚洲91av视频| 久久久久久国产精品美女| 欧美一级电影免费在线观看| 日韩视频亚洲视频| 久久精品成人动漫| 91在线精品视频| 永久免费精品影视网站| 中文亚洲视频在线| 国产精品久久久久久久电影| 成人久久18免费网站图片| 国产午夜精品麻豆| 欧美怡红院视频一区二区三区| 成人网在线免费看| 日韩福利伦理影院免费| 欧美性感美女h网站在线观看免费| 91在线高清视频| 九九热精品在线| 欧美做爰性生交视频| 亚洲天堂色网站| 91亚洲精品在线| 国内精品视频久久| 97在线视频观看| 国产一区二区三区高清在线观看| 国产精品久久久久久一区二区| 国产精品久久一| 色爱精品视频一区| www.欧美视频| 久久99热这里只有精品国产| 成人观看高清在线观看免费| 国产精品一区二区三区毛片淫片| 蜜臀久久99精品久久久无需会员| 欧美日韩国产在线播放| 国产精品久久久久av免费| 成人自拍性视频| 国产精品久久久久久中文字| 亚洲人成自拍网站| 97福利一区二区| 国产乱人伦真实精品视频| 久久av红桃一区二区小说| 亚洲iv一区二区三区| 日韩在线观看免费高清| 青青青国产精品一区二区| 国产美女精品视频免费观看| 成人网在线观看| 日韩av免费在线| 国产精品精品视频一区二区三区| 日韩中文字幕在线精品| 久久久精品久久久久| 欧洲亚洲在线视频| 亚洲精品一区久久久久久| 欧美高清一级大片| 国产区精品视频| 亚洲第一av网| 国产69精品久久久久99|