1. 程式人生 > >一種在嵌入式環境下的2D遊戲柵格地圖繪製方法

一種在嵌入式環境下的2D遊戲柵格地圖繪製方法

在嵌入式系統開發中,如果你想要在LCD螢幕上繪製一幅二維柵格地圖(就像坦克大戰那樣的磚塊地圖),該如何實現呢?應該會用到一個二維陣列來儲存地圖資訊,但如何構建這幅地圖呢?肯定不是手工在數組裡賦值吧,那樣很麻煩,也不直觀,我在我的課程實驗中是這樣做的,使用畫圖軟體先“畫一幅地圖”,然後通過資料轉換實現地圖的直觀、快捷設計,適用於小的實驗程式,分享給大家。

實驗開發環境:嵌入式晶片為STM32F429,開發板配一塊7寸LCD顯示屏。該晶片系列內部自帶LTDC液晶顯示控制模組,若使用其他系列晶片,請自行配置液晶驅動。

實現思路:

假設你的液晶屏為800*480大小,因為是要做柵格化的地圖,就假定柵格大小為20個畫素,那麼螢幕就被分成了40*24的小格子,每個格子20*20畫素,繪製地圖時,你得先定義好一個基本地圖單元,比如一個20*20的磚塊圖案,在指定的格子裡繪製這樣的單位磚塊,就構成了地圖。

那麼此時你需要一個40*24的二維陣列,來決定每個格子畫還是不畫,數組裡就兩種數,1:表示畫,0:表示不畫。繪製地圖就是遍歷這樣一個二維陣列。

如果你手工給陣列賦值,會很累,而且最後的圖案需要你反覆除錯,很浪費時間,於是這裡使用Photoshop來幫個忙。

用Photoshop來建立一副小影象,畫布大小隻有40*24畫素,夠小吧,請把圖案放大到最大來觀看,於是你可以看到畫布上的每一個畫素,這幅圖的大小是和地圖柵格大小相一致的,這裡的每一個點就意味著將來LCD屏上對應座標位置會出現一個柵格基本單元(磚塊圖案)。

繪製好的圖片就是這個樣子滴,寬40畫素,高24畫素,之所以現在看起來那麼大,那是因為我截圖後貼過來的,為了突出柵格感。

請將圖片儲存為bmp格式,色彩深度請選擇16位,後面資料還要在轉換一次,16位意味著顏色模式是RGB565模式,2個位元組表示一個畫素。

下面需要用一下一個小軟體:Image2LCD,應該聽過吧,它可以將圖片資料轉換為1維陣列,注意,是1維,還沒有到最終的2維陣列。

注意這裡的設定,開啟我們做好的圖片後,要選擇輸出型別為C語言陣列,單色,大小就是圖片大小,水平掃描,如果你想給自己找麻煩,可以選擇其他掃描方式。

點選儲存後,會生成一個一維陣列,長相如下:

不要頭昏,它只是一維的,這裡是軟體生成的陣列,我將資料型別改為了u8,因為嵌入式系統設計中不常使用int,char這類的資料型別,u8是無符號整形,一個數據1位元組。

來分析一下這個陣列結構,否則後續讀不出正確結果。我們之前選擇的是“單色”,還記得吧,就是說1個數據位表示一個畫素,0代表白,1代表黑。

比如0xff,代表一橫排8個黑色畫素點,0x00,代表8個白色點。

這裡的陣列一共有120個數據,每個資料1位元組,共960個位(一位元組8位啊),剛好等於40*24,大小是和我們做的圖片相吻合的,一位一位讀就可以轉換為我們需要的二維陣列。但有人可能會遇到這樣的問題(很關鍵):比如圖片大小30*20,但生成的陣列是80位元組共640位,是和30*20=600對不上的,如果還是一位一位的讀,肯定會資料錯位,為什麼會對不上呢?

因為該軟體轉換資料時,一行畫素資料儲存在整數個位元組中,如果一行只有30畫素,對應到陣列中就是用30位來表示,但30位是3個位元組多6位,最後6位不滿1位元組,軟體自動補0,湊出整數字節,這就是陣列大小和我們設計的圖片大小不吻合的原因,很多人資料讀不對就是沒有跳過這軟體自動添的那幾個0!

接下來就簡單了,設計一個小函式,一位一位的讀陣列,若果你的陣列和圖片大小對不上,請設計一個小環節自動跳過那幾個0。為了說明這個對不齊的問題,下面的函式使用的是一個28*24的二維陣列,我的函式是這樣躲過那幾個0的:

void Map_convert(uint8_t * line_map,uint8_t num,uint8_t (*map2D)[28])   //引數1:,我們軟體生成的一位陣列,引數2、一位陣列長度,引數3:已經定義好的空二維陣列
{
     u8 i,j;   //用來遍歷二維陣列
     u8 bit_temp;
     u8 k=0;     //用來遍歷1位陣列
     u8 temp;//一個臨時存數的變數

     u8 bit_mask;    //用來取一個位元組的某一位
 
    bit_mask=0x80;  //  1000 0000 可以用它取出一個位元組的最高一位

    //我定義的二維陣列為28*24,所以這裡ij直接寫出來了,你也可以作為引數傳進來。
    for(i=0;i<24;i++)           //我設計的圖片為28*24,存在資料不對齊的問題
    {
        for(j=0;j<32;j++)       //為此,我將行遍歷的值改為整數字節,此處為32,而不是28,
        {
            bit_temp=line_map[k];
          
            if(((u8)bit_temp & (u8)bit_mask)==bit_mask)     //取位運算,若果取到的位為1,那麼temp=1,否則為0
            {
                temp=1;
            }
            else
            {
                temp=0;
            }
        if(j<28)                                                           //這裡很關鍵,就是隻有前28位才執行給二維陣列的賦值操作,29-32位是軟體自動補的0,要跳過去
         map2D[i][j]=temp;                 //這個二維資料就是最後要用的陣列,
            
            bit_mask=bit_mask>>1;  //0x1000 0000    迴圈移位,
            if(bit_mask==0)
            {
                bit_mask=0x80;
                k++;
            }    
        }    
    }

到這裡,就完成了一位陣列向二維陣列賦值的操作。

最後一步,就是遍歷這個二維陣列,此時這個二維數組裡面應該都是0和1了,1代表要繪製一個柵格,0代表什麼也不繪製。

假設我們有個繪製柵格的函式,叫Map_Draw(uint8_t  (*map)[28]); 引數就是上述二維陣列,這個函式你可以做的很簡單,比如單純的畫個20*20的彩色方塊,也可以稍微複雜一些,比如顯示一個20*20的圖片(圖片資料存在內部儲存器讀取要快一些),那麼剩下的事情就是遍歷這個二維陣列,只有當陣列元素為1的時候,才執行Map_Draw()函式,這樣就可以繪製一幅任意你定義好的地圖。

看起來有些麻煩,一旦寫好,地圖的更改、設計將會很簡單,因為你一開始操作的是一副看得見的圖片,這總比改數組裡的0101方便得多吧。