【Android遊戲開發二十】物理遊戲之重力系統開發,讓你的遊戲變得有質有量!

來源:互聯網
上載者:User

 

今天群裡一哥哥說急需關於物理遊戲方面的資料,so~下午就隨手寫了一個簡單的圓形自由落體Demo,正好一起分享給大家學習下吧;

    先大概說一下,之前的文章中,給大家介紹過重力感應器,那麼和今天要說的重力系統,其實是一樣的!

    在重力感應器中,雖然我也實現了一個圓形會根據手機反轉的角度而擁有不同的速度,但是其內建加速度演算法都是Android os封裝好的,而今天我們要講的重力系統就是去類比這個加速度,從而讓一個自由落體的圓形,感覺跟現實中的皮球一樣有質有量!下落的時候速度加快,反彈起來以後速度慢慢減下來~

 

OK,先上兩張,然後簡單介紹之後進行講解:

 


                                                     

 

Demo:簡介:(咳咳、玩的有點H,狂點按鈕搞的滿屏都是- -)

      當你點擊模擬器任意按鍵的時候會隨機在螢幕上產生一個隨機大小、隨即顏色、隨即位置、不停閃爍的一個圓形,並且圓形都擁有重力,在做自由落體,當圓形觸到螢幕底部的時候會反彈,並且反彈的高度一次比一次低!

      這個執行個體中,為了好看,我沒有讓圓形最終慢到停下來,會一直在一個高度進行的反彈,下落;

 

還有一點:對於圓形當從一個高度自由落體的時候可能它在X座標繫上沒有發生改變,當然這是在我們代碼中,屬於理想狀態,因為現實生活中,一般X/Y座標系都會有變動,在此Demo中,我主要把垂直下落並且反彈的功能做出來了,關於水平的加速度我沒做,第一是因為和垂直的處理思路基本一致,第二點我沒時間- -...

 

好了 不廢話!先介紹一下我自訂的圓形類:

MyArc.java

 

 

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

package com.himi; 

import java.util.Random; 

import android.graphics.Canvas; 

import android.graphics.Color; 

import android.graphics.Paint; 

import android.graphics.RectF; 

/**

 * @author Himi

 * @自訂圓形類

 */ 

public class MyArc { 

    private int arc_x, arc_y, arc_r;//圓形的X,Y座標和半徑 

    private float speed_x = 1.2f, speed_y = 1.2f;//小球的x、y的速度 

    private float vertical_speed;//加速度 

    private float horizontal_speed;//水平加速度,大家自己試著添加吧 

    private final float ACC = 0.135f;//為了類比加速度的位移值 

    private final float RECESSION = 0.2f;//每次彈起的衰退係數  

    private boolean isDown = true;//是否處於下落  狀態 

    private Random ran;//隨即數庫 

    /**

     * @定義圓形的建構函式

     * @param x 圓形X座標

     * @param y 圓形Y座標

     * @param r 圓形半徑

     */ 

    public MyArc(int x, int y, int r) { 

        ran = new Random(); 

        this.arc_x = x; 

        this.arc_y = y; 

        this.arc_r = r; 

    } 

    public void drawMyArc(Canvas canvas, Paint paint) {//每個圓形都應該擁有一套繪畫方法 

        paint.setColor(getRandomColor());//不斷的擷取隨即顏色,對圓形進行填充(實現圓形閃爍效果) 

        canvas.drawArc(new RectF(arc_x + speed_x, arc_y + speed_y, arc_x + 2 * 

                arc_r + speed_x, arc_y + 2 * arc_r + speed_y), 0, 360, true, paint); 

    } 

    /**

     * @return

     * @返回一個隨即顏色

     */ 

    public int getRandomColor() { 

        int ran_color = ran.nextInt(8); 

        int temp_color = 0; 

        switch (ran_color) { 

        case 0: 

            temp_color = Color.WHITE; 

            break; 

        case 1: 

            temp_color = Color.BLUE; 

            break; 

        case 2: 

            temp_color = Color.CYAN; 

            break; 

        case 3: 

            temp_color = Color.DKGRAY; 

            break; 

        case 4: 

            temp_color = Color.RED; 

            break; 

        case 6: 

            temp_color = Color.GREEN; 

        case 7: 

            temp_color = Color.GRAY; 

        case 8: 

            temp_color = Color.YELLOW; 

            break; 

        } 

        return temp_color; 

    } 

    /**

     * 圓形的邏輯

     */ 

    public void logic() {//每個圓形都應該擁有一套邏輯 

        if (isDown) {//圓形下落邏輯 

/*--備忘1-*/speed_y += vertical_speed;//圓形的Y軸速度加上加速度 

            int count = (int) vertical_speed++; 

            //這裡拿另外一個變數記下當前速度位移量 

            //如果下面的for (int i = 0; i < vertical_speed++; i++) {}這樣就就死迴圈了- - 

            for (int i = 0; i < count; i++) {//備忘1 

/*--備忘2-*/  vertical_speed += ACC; 

            } 

        } else {//圓形反彈邏輯 

            speed_y -= vertical_speed; 

            int count = (int) vertical_speed--; 

            for (int i = 0; i < count; i++) { 

                vertical_speed -= ACC; 

            } 

        } 

        if (isCollision()) { 

            isDown = !isDown;//當發生碰撞說明圓形的方向要改變一下了! 

            vertical_speed -= vertical_speed * RECESSION;//每次碰撞都會衰減反彈的加速度 

        } 

    } 

    /**

     * 圓形與螢幕底部的碰撞

     * @return

     * @返回true 發生碰撞

     */ 

    public boolean isCollision() { 

        return arc_y + 2 * arc_r + speed_y >= MySurfaceViee.screenH; 

    } 

 

   

 

代碼比較簡單主要講解下幾個備忘:

備忘1:

       估計有些同學看到這裡有點小暈,我解釋下,大家都知道自由落體的時候,速度是越來越快的,這是受到加速度的影響,所以這裡我們對原有的圓形y速度基礎上再加上加速度!

備忘2:

       雖然加速度影響了圓形原有的速度,但是我們的加速度也不是恒定的,為了類比真實球體的自由下落,這裡我們不僅對加速度增加了位移量ACC,而且我們還要對其變化的規律進行類比,讓下次的加速度位移量成倍增加!所以為什麼要for迴圈的時候把加速度的值當成for迴圈的一個判定條件!

 

好了,下面來看我們SurfaceView!

 

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

package com.himi; 

import java.util.Random; 

import java.util.Vector; 

import android.content.Context; 

import android.graphics.Canvas; 

import android.graphics.Color; 

import android.graphics.Paint; 

import android.util.Log; 

import android.view.KeyEvent; 

import android.view.SurfaceHolder; 

import android.view.SurfaceView; 

import android.view.SurfaceHolder.Callback; 

public class MySurfaceViee extends SurfaceView implements Callback, Runnable { 

    private Thread th; 

    private SurfaceHolder sfh; 

    private Canvas canvas; 

    private Paint paint; 

    private boolean flag; 

    public static int screenW, screenH; 

    private Vector<MyArc> vc;//這裡定義裝我們自訂圓形的容器 

    private Random ran;//隨即庫 

    public MySurfaceViee(Context context) { 

        super(context); 

        this.setKeepScreenOn(true); 

        vc = new Vector<MyArc>(); 

        ran = new Random();//備忘1 

        sfh = this.getHolder(); 

        sfh.addCallback(this); 

        paint = new Paint(); 

        paint.setAntiAlias(true); 

        setFocusable(true); 

    } 

    public void surfaceCreated(SurfaceHolder holder) { 

        flag = true;//這裡都是上一篇剛講過的。。。 

        th = new Thread(this); 

        screenW = this.getWidth(); 

        screenH = this.getHeight(); 

        th.start(); 

    } 

    public void draw() { 

        try { 

            canvas = sfh.lockCanvas(); 

            canvas.drawColor(Color.BLACK); 

            if (vc != null) {//當容器不為空白,遍曆容器中所有圓形畫方法 

                for (int i = 0; i < vc.size(); i++) { 

                    vc.elementAt(i).drawMyArc(canvas, paint); 

                } 

            } 

        } catch (Exception e) { 

            // TODO: handle exception 

        } finally { 

            try { 

                if (canvas != null) 

                    sfh.unlockCanvasAndPost(canvas); 

            } catch (Exception e2) { 

            } 

        } 

    } 

    private void logic() {//主邏輯 

        if (vc != null) {//當容器不為空白,遍曆容器中所有圓形邏輯 

            for (int i = 0; i < vc.size(); i++) { 

                vc.elementAt(i).logic(); 

            } 

        } 

    } 

    @Override 

    public boolean onKeyDown(int keyCode, KeyEvent event) { 

        //當按鍵事件響應,我們往容器中仍個我們的圓形執行個體 

        vc.addElement(new MyArc(ran.nextInt(this.getWidth()), ran.nextInt(100), ran.nextInt(50))); 

        return true; 

    } 

    public void run() { 

        // TODO Auto-generated method stub 

        while (flag) { 

            logic(); 

            draw(); 

            try { 

                Thread.sleep(100); 

            } catch (Exception ex) { 

            } 

        } 

    } 

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 

        Log.v("Himi", "surfaceChanged"); 

    } 

    public void surfaceDestroyed(SurfaceHolder holder) { 

        flag = false; 

    } 

 

 

 

 

OK,代碼都很簡單,也很清晰! 稍微說一句:像MyArc裡面也有類似MysurfaceView中一樣的方法logic() 以及draw()這樣是更好的管理我們的代碼結構,清晰思路,讓該幹什麼的就去幹什麼,這樣省的亂~ 

 

源碼: http://www.bkjia.com/uploadfile/2011/1115/20111115052234134.rar

 

                           補充下://備忘1 這裡!有的童鞋說for迴圈可以簡寫:這我就要提示各位童鞋了~

for (int i = 0; i < count; i++) {

         vertical_speed += ACC;

}

以上代碼確實可以用一句來表示:

               vertical_speed +=ACC*count;     或者    vertical_speed  =vertical_speed + ACC*count;

但是要注意:因為我這裡變數都是浮點數,大家都知道對於浮點數有位元的限制,那麼我這裡用for來寫可以避免乘積,如果簡寫的形式會有造成得到的結果有差異!!!!所以要注意;

               還有千萬不要簡寫成vertical_speed =(vertical_speed +ACC)*count; 這是錯誤的!

  Himi  原創, 歡迎轉載,轉載請在明顯處註明! 謝謝。

原文地址:http://blog.csdn.net/xiaominghimi/archive/2011/01/19/6153396.aspx

     

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.