【Android遊戲開發之四】Android 遊戲框架(一個遊戲角色在屏幕行走的demo)


 李華明Himi 原創,轉載務必在明顯處註明:
轉載自 【黑米GameDev街區】 原文連接:  http://www.himigame.com/android-game/298.html


不少童鞋說個人代碼運行後,點擊home或者back後會程序異常,若是你也這樣遇到過,那麼你確定沒有仔細讀完Himi的博文,第十九篇Himi專門寫了關於這些錯誤的緣由和解決方法,這裏我在博客都補充說明下,省的童鞋們總疑惑這一塊;請點擊下面聯繫進入閱讀:css

【Android遊戲開發十九】(必看篇)SurfaceView運行機制詳解—剖析Back與Home按鍵及切入後臺等異常處理!html


              各位童鞋請大家注意:surfaceview中確實有 onDraw這個方法,可是surfaceview不會本身去調用!!!java

  而我代碼中的ondraw 也好 draw 也好,都是我本身定義的一個方法。。。放在線程中不斷調用的,必定要注意!!android

 

        其實上一篇分析surfaceview的文章就是一個簡單的遊戲框架了,固然這裏再強調一下,簡單的遊戲框架,因此不要高手們不要亂噴~canvas

 

 這個Demo是給羣裏一童鞋寫的一個對圖片操做以及按鍵處理,遊戲簡單框架的一個demo,這裏放出給你們分享~框架

 

 

 

 

package com.himi;  
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.util.Log;  
import android.view.KeyEvent;  
import android.view.SurfaceHolder;  
import android.view.SurfaceView;  
import android.view.SurfaceHolder.Callback;  
public class MySurfaceView extends SurfaceView implements Callback, Runnable {  
    private Thread th = new Thread(this);  
    private SurfaceHolder sfh;  
    private int SH, SW;  
    private Canvas canvas;  
    private Paint p;  
    private Paint p2;  
    private Resources res;  
    private Bitmap bmp;  
    private int bmp_x = 100, bmp_y = 100;  
    private boolean UP, DOWN, LEFT, RIGHT;  
    private int animation_up[] = { 3, 4, 5 };  
    private int animation_down[] = { 0, 1, 2 };  
    private int animation_left[] = { 6, 7, 8 };  
    private int animation_right[] = { 9, 10, 11 };  
    private int animation_init[] = animation_down;  
    private int frame_count;  
    public MySurfaceView(Context context) {  
        super(context);  
        this.setKeepScreenOn(true);  
        res = this.getResources();  
        bmp = BitmapFactory.decodeResource(res, R.drawable.enemy1);  
        sfh = this.getHolder();  
        sfh.addCallback(this);  
        p = new Paint();  
        p.setColor(Color.YELLOW);  
        p2 = new Paint();  
        p2.setColor(Color.RED);  
        p.setAntiAlias(true);  
        setFocusable(true);  //備註1
    }  
    public void surfaceCreated(SurfaceHolder holder) {  
        SH = this.getHeight();  
        SW = this.getWidth();  
        th.start();  
    }  
    public void draw() {  
        canvas = sfh.lockCanvas();  
        canvas.drawRect(0, 0, SW, SH, p);   //備註2
        canvas.save();   //備註3
        canvas.drawText("Himi", bmp_x-2, bmp_y-10, p2);  
        canvas.clipRect(bmp_x, bmp_y, bmp_x + bmp.getWidth() / 13, bmp_y+bmp.getHeight());  
        if (animation_init == animation_up) {  
            canvas.drawBitmap(bmp, bmp_x - animation_up[frame_count] * (bmp.getWidth() / 13), bmp_y, p);  
        } else if (animation_init == animation_down) {  
            canvas.drawBitmap(bmp, bmp_x - animation_down[frame_count] * (bmp.getWidth() / 13), bmp_y, p);  
        } else if (animation_init == animation_left) {  
            canvas.drawBitmap(bmp, bmp_x - animation_left[frame_count] * (bmp.getWidth() / 13), bmp_y, p);  
        } else if (animation_init == animation_right) {  
            canvas.drawBitmap(bmp, bmp_x - animation_right[frame_count] * (bmp.getWidth() / 13), bmp_y, p);  
        }  
        canvas.restore();  //備註3
        sfh.unlockCanvasAndPost(canvas);  
    }  
    public void cycle() {  
        if (DOWN) {  
            bmp_y += 5;  
        } else if (UP) {  
            bmp_y -= 5;  
        } else if (LEFT) {  
            bmp_x -= 5;  
        } else if (RIGHT) {  
            bmp_x += 5;  
        }  
        if (DOWN || UP || LEFT || RIGHT) {  
            if (frame_count < 2) {  
                frame_count++;  
            } else {  
                frame_count = 0;  
            }  
        }  
        if (DOWN == false && UP == false && LEFT == false && RIGHT == false) {  
            frame_count = 0;  
        }  
    }  
    @Override  
    public boolean onKeyDown(int key, KeyEvent event) {  
        if (key == KeyEvent.KEYCODE_DPAD_UP) {  
            if (UP == false) {  
                animation_init = animation_up;  
            }  
            UP = true;  
        } else if (key == KeyEvent.KEYCODE_DPAD_DOWN) {  
            if (DOWN == false) {  
                animation_init = animation_down;  
            }  
            DOWN = true;  
        } else if (key == KeyEvent.KEYCODE_DPAD_LEFT) {  
            if (LEFT == false) {  
                animation_init = animation_left;  
            }  
            LEFT = true;  
        } else if (key == KeyEvent.KEYCODE_DPAD_RIGHT) {  
            if (RIGHT == false) {  
                animation_init = animation_right;  
            }  
            RIGHT = true;  
        }  
        return super.onKeyDown(key, event);  
    }  
    /* (non-Javadoc) 
     * @see android.view.View#onKeyUp(int, android.view.KeyEvent) 
     */  
    @Override  
    public boolean onKeyUp(int keyCode, KeyEvent event) {  
        if (DOWN) {  
            DOWN = false;  
        } else if (UP) {  
            UP = false;  
        } else if (LEFT) {  
            LEFT = false;  
        } else if (RIGHT) {  
            RIGHT = false;  
        }  
        return super.onKeyUp(keyCode, event);  
    }  
    @Override  
    public void run() {  
        // TODO Auto-generated method stub  
        while (true) {  
            draw();  
            cycle();  
            try {  
                Thread.sleep(100);  
            } catch (Exception ex) {  
            }  
        }  
    }  
    @Override  
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
        // TODO Auto-generated method stub  
    }  
    @Override  
    public void surfaceDestroyed(SurfaceHolder holder) {  
        // TODO Auto-generated method stub  
    }  
}

 

 備註1ide

   此方法是用來響應按鍵!若是是本身定義一個繼承自View的類,從新實現onKeyDown方法後,只有當該View得到焦點時纔會調用onKeyDown方法,Actvity中的onKeyDown方法是當全部控件均沒有處理該按鍵事件時,纔會調用.post

 

 備註2this

   這裏也是對屏幕進行刷屏操做,其實這也只是一種,以前文章裏我也用到drawRGB的方法一樣實現,固然也能夠用fillRect等來刷屏。spa

    那麼這裏我想說下,在繼承view中,由於onDraw方法是系統自動調用的,不像在surfaceview這裏這樣去在run裏面本身去不斷調用,在view中咱們能夠抵用 invalidate()/postInvalidate() 這兩種方法實現讓系統調用onDraw方法,這裏也是和surfaceview中的不一樣之一!

 

 備註3

   這裏canvas.save();和canvas.restore();是兩個相互匹配出現的,做用是用來保存畫布的狀態和取出保存的狀態的。這裏稍微解釋一下,

   當咱們對畫布進行旋轉,縮放,平移等操做的時候其實咱們是想對特定的元素進行操做,好比圖片,一個矩形等,可是當你用canvas的方法來進行這些操做的時候,實際上是對整個畫布進行了操做,那麼以後在畫布上的元素都會受到影響,因此咱們在操做以前調用canvas.save()來保存畫布當前的狀態,當操做以後取出以前保存過的狀態,這樣就不會對其餘的元素進行影響

 

對於 canvas.save();和canvas.restore();  還有很多童鞋不懂,OK、我再補充點:

 

代碼段1:

public void draw() { 
    Canvas canvas = sfh.lockCanvas();  
    canvas.drawColor(Color.BLACK);
    canvas.drawBitmap(bmp1, 0,0,paint);
    canvas.save(); 
    canvas.scale(1.5f, 1.5f);
    canvas.restore(); 
    canvas.drawBitmap(bmp2, 0,0,paint);
    sfh.unlockCanvasAndPost(canvas);  
  }
 

代碼段2:

public void draw() { 
    Canvas canvas = sfh.lockCanvas();  
    canvas.drawColor(Color.BLACK);
    canvas.drawBitmap(bmp1, 0,0,paint);
    canvas.scale(1.5f, 1.5f);
    canvas.drawBitmap(bmp2, 0,0,paint);
    sfh.unlockCanvasAndPost(canvas);  
  }
 

上面這兩個代碼片斷中咱們都假設有兩張圖片 bmp1和bmp2,而且都畫在畫布上!

那麼代碼段1和代碼段2的不一樣:

代碼段1中咱們進行畫布縮放的以前保存了畫布狀態,作了縮放操做以後又取出以前保存的狀態,這樣作是爲了保證bmp2正常畫出來不受到縮放的影響!

代碼段2裏,畫了bmp1後就執行了縮放操做,而且沒有保存狀態!緊接着畫了bmp2,那麼bmp2也會同樣受到縮放的影響!!

因此咱們若是單獨處理一張圖片的時候,並且不想影響其餘部分的繪製,那麼應該以下來作:

public void draw() { 
    Canvas canvas = sfh.lockCanvas();  
    canvas.drawColor(Color.BLACK);
    canvas.drawBitmap(bmp1, 0,0,paint);
    canvas.save(); 
    canvas.scale(1.5f, 1.5f);
    canvas.drawBitmap(bmp2, 0,0,paint);
    canvas.restore(); 
    sfh.unlockCanvasAndPost(canvas);  
  }
 

 

(推薦你們訂閱本博客,由於咱的更新速度但是很快的~娃哈哈)

源碼下載地址:   http://www.himigame.com/android-game/298.html

 

 

 

 

 


原文連接: http://blog.csdn.net/xiaominghimi/article/details/6090631
相關文章
相關標籤/搜索