天天看點

【Android遊戲開發十一】手把手讓你愛上Android sdk自帶“9妹”

前幾天群成員讨論過關于9patch的工具【我比較喜歡喊它9妹子,西西(*^_^*)】、然後研究了一下,比較簡單但是很實用的一個Android sdk 自帶工具、這裡給大家做一個分享下經驗!

 1.什麼是“9妹”(9patch)?

    它是一個對png圖檔做處理的一個工具,能夠為我們生成一個"*.9.png"的圖檔;

2.何為"*.9.png"?

    所謂"*.9.png"這是Android os裡所支援的一種特殊的圖檔格式,用它可以實作部分拉伸;這種圖檔是經過”9妹“進行特殊處理過的,如果不處理的話,直接用PNG圖就會有失真,拉伸不正常的現象出現。

3.它的用途是?

    說到用途,這種特殊格式的png圖,我也看了網上的相關文章但都是用一個能自适應的button舉例子!(如下圖)清一色抄襲.. - -、

<a target="_blank" href="http://blog.51cto.com/attachment/201107/142955883.png"></a>

 (此執行個體咱們直接無視掉,在後面我會給大家灌輸遊戲中執行個體)

    這個例子是指當button上的字型大小改變,那麼文字底下的png圖也會自動适應文字。

    這似乎表明做Android 軟體應用 使用一些元件的的時候會時常用到;

4.那麼實際在遊戲中到底如何使用呢?什麼情況下去使用呢?

    當然啦,身為做遊戲我一定要”9妹“利用在咱們遊戲中才行,不然豈不是白研究了、經過思考突然想到了一些情況,并且發現“9妹”确實在遊戲開發中占有一定的分量!下面我們來先熟習“9妹”工具,然後再跟大家舉例,貼圖來說明其用途、畢竟有圖有真相 呵呵~

 啟動9妹:

    在你Android SDK 路徑下 X:/android sdk/tools ,你會找到一個 【draw9patch.bat】,沒錯這就是9妹啦、官方名 NinePatch ; 

<a target="_blank" href="http://blog.51cto.com/attachment/201107/143009179.png"></a>

 提示導入一張png圖檔,然後真正進入"9妹"的操作界面(如下圖): (圖1) 

<a target="_blank" href="http://blog.51cto.com/attachment/201107/143544138.png"></a>

      序列 ① :在拉伸區域周圍用紅色邊框顯示可能會對拉伸後的圖檔産生變形的區域,如果完全消除該内容則圖檔拉伸後是沒有變形的,也就是說,不管如何縮放圖檔顯示都是良 好的。 (實際試 發現NinePatch編輯器是根據圖檔的顔色值來區分是否為bad patch的,一邊來說隻要色差不是太大不用考慮這個設定。)

    序列 ② :區域是導入的圖檔,以及可操作區域。

    序列 ③ :這裡 zoom:的長條bar 是對導入的圖放大縮小操作,這裡的放大縮小隻是為了讓使用者更友善操作,畢竟是對像素點操作比較費眼,下面的 patch scale 是序列 ④區域中的三種形态的拉伸後的一個預覽操作,可以看到操作後的圖檔拉伸後的效果。

    序列 ④: 區域這裡從上到下,依次為:縱向拉伸的效果預覽、橫向拉伸的效果預覽,以及整體拉伸的效果預覽

    序列 ⑤: 這裡如果你勾選上,那麼當你滑鼠放在 ② 區域内的時候并且目前位置為不可操作區域就會出現lock的一張圖,就是顯示不可編輯區域 ;

    序列 ⑥: 這裡勾選上,那麼在④ 區域中你就會看到目前操作的像素點在拉伸預覽圖中的相對位置和效果。

    序列 ⑦: 在編輯區域顯示圖檔拉伸的區域;

如何操作:滑鼠左鍵選取需要拉伸的像素點; shift+滑鼠左鍵取消目前像素點。

操作區域: 

<a target="_blank" href="http://blog.51cto.com/attachment/201107/143036241.png"></a>

    大家看到導入的png圖檔預設周圍多了一像素點,也就是這一圈一像素點就是咱們的可操作區域。因為下方和右方可操作區域是指定内容的顯示區域,屬于可選區域,可不予理會;但是要注意内容區域的标記不能有間斷,也就是說标記要連續且僅有一處,否則.9.png圖檔在放入項目下會報錯。

主要大家注意Left 和 top 操作區域;

     Top操作區域的一排像素點,表示橫向拉伸的像素點;

    Left操作區的一排像素點,表示縱向拉伸的像素點;

下圖是我對圖檔的操作:(圖2)

<a target="_blank" href="http://blog.51cto.com/attachment/201107/143104245.png"></a>

    大家看到上方和左邊的黑色像素了麼?對,這些是我手動操作的地方,我這裡是想讓此png圖像拉伸操作的時候,隻是中間區域被拉伸。選擇上方中間區域是為了橫向拉伸的時候選取的拉伸像素點,左邊則是縱向拉伸的;

     那麼大家現在回頭看一眼(圖1)然後對比(圖2),看到差別了吧!很明顯,(圖1)我們沒有任何操作,預設整體拉伸,那麼拉伸的效果很明顯的失真了...而(圖2)我們指定了拉伸的像素點是以隻是中間的被拉伸,圖檔的花邊我們保留不拉伸這樣看起來就好太多啦 娃哈哈、

    然後通過“9妹”就可以儲存出來一張“*.9.png”圖檔,我們放在android 項目的res 下的 drawable 下就可以拉!

 現在我就可以跟大家講下使用“*.9.png”的好處:

     在我們手機遊戲開發的過程中,我們最關系的是生成的安裝檔案、比如j2me 的jar 包,塞班的sis、sisx 以及咱們andrid中的apk都希望打包後的包越小越好、雖然現在的手機趨向于智能了,但是畢竟手機的容量和記憶體還是有限、身為移動裝置開發者的我們對此都很看重,那麼通過"9妹"處理後的圖檔我們就可以省去不少的記憶體和容量。

1. 省精力和時間!

    如果我們有一張50*50的類似上面那種帶花邊的png圖檔,那麼我們在android或者大分辨率的機器上使用的畫,肯定需要對其處理,那麼要不就是讓美工的mm們給咱們重新做一張,那麼通過"9妹"處理得到的“*.9.png”就會省去美工的負擔了。

2.省記憶體!

    如果不想用代碼來對其小圖進行縮放來再次使用(因為考慮會失真),那麼可能會多加了圖檔,這樣一來遊戲包的大小就會增加了,幾K—幾十K不等,而利用"9妹"處理的就省去了這些麻煩。

3.減少代碼量!

    有些童鞋該說啦,我用代碼一樣能實作(圖2)的效果不失真,OK,我也知道。當初我在J2ME平台做RPG的時候也是利用設定可視區域等代碼來實作的,但是如果你用“.9.png”的方式就更簡單!!!

     不多吹 “9妹”的好處,下面我們來看看代碼如何實作此格式的方式和效果吧! 

package com.himi;  

import android.content.Context;  

import android.graphics.Bitmap;  

import android.graphics.BitmapFactory;  

import android.graphics.Canvas;  

import android.graphics.Color;  

import android.graphics.NinePatch;  

import android.graphics.Paint;  

import android.graphics.RectF;  

import android.util.Log;  

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 Canvas canvas;  

    private Paint paint;  

    private Bitmap bmp_old;  

    private Bitmap bmp_9path;  

    private NinePatch np;  

    public MySurfaceView(Context context) {  

        super(context);  

        this.setKeepScreenOn(true);  

        bmp_old = BitmapFactory.decodeResource(getResources(), R.drawable.himi_old);  

        bmp_9path = BitmapFactory.decodeResource(getResources(), R.drawable.himi_9path);  

        np = new NinePatch(bmp_9path, bmp_9path.getNinePatchChunk(), null);  

        //建立一個ninePatch的對象執行個體,第一個參數是bitmap、第二個參數是byte[],這裡其實要求我們傳入  

        //如何處理拉伸方式,當然我們不需要自己傳入,因為“.9.png”圖檔自身有這些資訊資料,  

        //也就是我們用“9妹”工具操作的資訊! 我們直接用“.9.png”圖檔自身的資料調用getNinePatchChunk()即可  

        //第三個參數是圖檔源的名稱,這個參數為可選參數,直接null~就OK~  

        sfh = this.getHolder();  

        sfh.addCallback(this);  

        paint = new Paint();  

        paint.setAntiAlias(true);  

        setFocusable(true);  

    }  

    public void surfaceCreated(SurfaceHolder holder) {  

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

        th.start();  

    /**  

     * @author Himi  

     */  

    public void draw() {  

        canvas = sfh.lockCanvas();  

        canvas.drawColor(Color.BLACK);  

        RectF rectf_old_two = new RectF(0, 50, bmp_old.getWidth() * 2, 120 + bmp_old.getHeight() * 2);//備注1  

        RectF rectf_old_third = new RectF(0, 120 + bmp_old.getHeight() * 2, bmp_old.getWidth() * 3,  

                140 + bmp_old.getHeight() * 2 + bmp_old.getHeight() * 3);  

        // --------下面是對正常png繪畫方法-----------  

        canvas.drawBitmap(bmp_old, 0, 0, paint);  

        canvas.drawBitmap(bmp_old, null, rectf_old_two, paint);  

        canvas.drawBitmap(bmp_old, null, rectf_old_third, paint);  

        RectF rectf_9path_two = new RectF(250, 50, 250 + bmp_9path.getWidth() * 2, 90 + bmp_9path.getHeight() * 2);  

        RectF rectf_9path_third = new RectF(250, 120 + bmp_9path.getHeight() * 2, 250 + bmp_9path.getWidth() * 3,  

                    140 + bmp_9path.getHeight() * 2  

                + bmp_9path.getHeight() * 3);  

        canvas.drawBitmap(bmp_9path, 250, 0, paint);  

        // --------下面是".9.png"圖像的繪畫方法-----------  

        np.draw(canvas, rectf_9path_two);  

        np.draw(canvas, rectf_9path_third);  

        sfh.unlockCanvasAndPost(canvas);  

    public void run() {  

        // TODO Auto-generated method stub  

        while (true) {  

            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) {  

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

下圖是模拟器中的效果圖、

    左邊是正常png的縮放不同大小的情況,右邊是咱們的9妹處理過的“*.9.png”、娃哈哈,怎麼樣 效果明顯不一樣吧!

  好啦,到這裡就結篇吧,挺累的 寫了三個多小時了....... 希望大家以後多多的利用 “9妹”哦、

本文轉自 xiaominghimi 51CTO部落格,原文連結:http://blog.51cto.com/xiaominghimi/606382,如需轉載請自行聯系原作者