HarmonyOS基于LYEVK-3861開發童年游戲之貪吃蛇
介紹
在LYEVK-3861開發板套件中,有1個OLED屏幕擴展板,帶按鍵的照明板,本次我們用這2個擴展板實現一個簡易的貪吃蛇小游戲。由于現有的板子資源有限,綜合考慮,計劃用OLED屏幕顯示游戲運行界面,OLED擴展板和照明板上的按鍵復用為游戲選擇和游戲控制方向鍵。

OLED屏幕為128*64的點陣,使用I2C接口
OLED擴展板上的按鍵 用于游戲難度的選擇和游戲開始的方向控制(向左)
照明板主要是使用板子上的按鍵,按鍵用于整個游戲中的確認操作和游戲運行過程中的方向控制(向右)
效果演示
環境準備
1、開發環境、編譯環境搭建,參考官方文檔,此處不在贅述。參考鏈接如下:
2、OpenHarmony 2.0 Canary源碼 源碼獲取,參考:
3、LYEVK-3861 IoT物聯網開發板套件
OLED模塊與SSD1306
顯示原理

板子上的OLED屏幕約為0.96寸,顯存大小128*64,分8個頁,PAGE0~PAGE7,128列。
OLED與方塊
方塊點陣定義
貪吃蛇的蛇身采用■方塊表示,現有的板子的OLED的驅動庫里是沒有■的點陣定義的,使用PCtoLCD2002這個工具可以生成■的字符點陣定義,可以按照自己的需要生成指定大小的點陣,我們這里使用8*8的點陣,取模結果如下:

按照如圖所示的步驟,實現對方塊的取模。實際測試過程中,發現使用原始的取模結果,組成完整蛇的身體的過程中,每個方塊之間的間隙比較大,顯示效果不是很好。我們對取模結果做了修改,最后的方塊的8*8點陣表示如下:
- /*---8*8 點陣*/
- static const unsigned char F8X8[]=
- {
- //0x00,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x00,
- 0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x00, //■
- };
OLED顯示方塊
關于方塊的顯示和消除,我們使用自己定義的函數來顯示整個方塊,這函數需要指定方塊的起始位置,整個方塊的處理不影響屏幕其他區域的顯示
- /*打印1個方塊或者消除方塊*/
- void Bar(uint8 x0, uint8 y0, DisOnOff onOff)
貪吃蛇
有了以上的一些基礎,我們就可以根據我們LYEVK-3861的開發板來設計一個簡短貪吃蛇小游戲了。
貪吃蛇游戲基本定義
按鍵復用
1. OLED擴展板上的按鍵功能:
①游戲主界面,點擊按鈕,可選擇不同的難度;
② 游戲界面,功能為控制蛇頭左轉;
2. 照明板上的按鍵功能:
①游戲主界面、游戲結束界面、游戲通過界面,確認操作,界面跳轉
②游戲界面,功能為控制蛇頭右轉。
主界面
顯示游戲的名字、游戲的可選難度(1、2、3,數字越大難度越大),按鍵功能選擇
游戲界面
使用整個屏幕128x64作為游戲可運行的界面,蛇由方塊(8x8的點陣)組成,方塊充滿整個界面需要16*8個方塊。
游戲規則定義
- 每次移動1個長度單位(勻速,不同難度移動速度不同)
- 通過按鍵,方向可以改變為蛇前進方向的左邊或右邊
- 隨機生成食物
- 吃到食物長度+1
- 碰到墻壁或身體結束游戲(失敗)
- 長度達到最長長度結束游戲(成功)
貪吃蛇基本算法設計
蛇的定義
- typedef struct {
- int8 X[SNAKE_MAX_LONG];
- int8 Y[SNAKE_MAX_LONG];
- uint8 Long; //蛇的長度
- gameLevel Level; // 1-簡單 2- 正常 3- 困難
- snakeDirection Direction; //蛇的前進方向 默認向右
- } snakeType; //蛇結構體
蛇的移動
- 蛇的局部刷新
由于開發板的CPU Hi3861性能和0.96寸的處理性能都很有限,在貪吃蛇游戲的運行過程中,不能每次都刷新整個屏幕,更新蛇的身體。這里,我們采用局部刷新的方法,避免一次刷新整個屏幕,影響游戲的性能。具體處理方法如下: 蛇每移動一個長度單位(1個方塊),不管有沒有吃到食物,蛇頭方塊的位置都會被打印到屏幕上,蛇的尾部方塊在未吃到食物的情況下,會被消除,吃到食物,則本次不消除尾部方塊。這樣做的好處時,蛇每一次的位置變化,除了判斷是否吃到食物,只需要對頭尾部的方塊做打印處理,不需要重復打印蛇身的所有方塊。
- 蛇的移動規則
基于開發板的現有資源,想要實現貪吃蛇的4個方向直接控制是不現實的,為了合理利用開發板的配套資源,我們使用OLED擴展板和照明板上的2個按鍵來控制蛇的移動。設計方法簡要說明如下:
1、8x8的點陣分割整個屏幕后,每個方塊的坐標范圍在橫向(0-15),縱向(0-7),蛇每次移動一個方塊的位置,蛇頭的變化范圍都是在-1,0,1這個3個數字之間變化,按照蛇的4個行進方向和是否左右轉,定義以下的參數:
- typedef enum {
- DIREC_STRAIGHT = -1,
- DIREC_RIGHT, //右
- DIREC_TOP, //上
- DIREC_LEFT, //左
- DIREC_BOTTOM, //底
- DIREC_MAX
- } snakeDirection;
- /*1-2 直行 3-4 左轉 5-6 右轉*/
- static int8 snakeDirectonInfo[4][6] = {
- {1, 0, 0, -1, 0, 1}, //DIREC_RIGHT
- {0, -1, -1, 0, 1, 0}, //DIREC_TOP
- {-1, 0, 0, 1, 0, -1}, //DIREC_LEFT
- {0, 1, 1, 0, -1, 0} //DIREC_BOTTOM
- };
說明:每個方向有6個元素定義, 按照兩位一組,分別為直行、左轉、右轉,這樣在處理蛇的移動的時候,可以直接套用定義好的數組,來優化蛇身移動的邏輯處理。
2、沒有按鍵時,蛇按照一定的頻率(刷新頻率)向前移動,每次移動一個方塊;有按鍵時,根據不同的按鍵選擇不同的處理方式:
- if (direc == DIREC_LEFT)
- { //左轉
- newPos[0] = snakeDirectonInfo[Snake.Direction][2];
- newPos[1] = snakeDirectonInfo[Snake.Direction][3];
- Snake.Direction = (Snake.Direction + 1) > DIREC_BOTTOM ? (DIREC_RIGHT) : (Snake.Direction + 1);//新的方向
- }
- else if (direc == DIREC_RIGHT)
- { //右轉
- newPos[0] = snakeDirectonInfo[Snake.Direction][4];
- newPos[1] = snakeDirectonInfo[Snake.Direction][5];
- Snake.Direction = (Snake.Direction - 1) < DIREC_RIGHT ? (DIREC_BOTTOM) : (Snake.Direction - 1);//新的方向
- }
- else
- { //前進
- newPos[0] = snakeDirectonInfo[Snake.Direction][0];
- newPos[1] = snakeDirectonInfo[Snake.Direction][1];
- }
說明: 當前蛇的行進方向在有偏轉的情況下,需要更新蛇的行進方向,這樣設計的好處是,便于計算蛇下次的運行位置,讓蛇在我們設計的正確的路徑上行進。
- 蛇是否撞墻,是否吃到自己
撞墻和吃到自己的算法也簡單,撞墻就判斷蛇頭坐標是否和墻重合,吃自己函數就遍歷所有身體坐標,看是否與頭重合。是這一部分是否吃到自己的判斷可能會影響到一些游戲的性能
食物

- 食物生成/更新
游戲開始或者食物被吃,重新生成食物坐標,取系統的時鐘計數取模來生成一個隨機的坐標,若坐標和蛇身重合,則重新生成。
- 食物是否被吃
算法也很簡單,先判斷蛇頭坐標是否和食物坐標重合。如果重合則蛇變長一節,把之前儲存的蛇尾后面一節坐標賦給最新一節身體。然后重新生成一次食物。
按鍵檢測
本程序使用到2個按鍵,相關代碼如下:
- IoTGpioInit(IOT_IO_NAME_GPIO_8); //button 按鍵B
- IoTGpioSetDir(IOT_IO_NAME_GPIO_8, IOT_GPIO_DIR_IN);
- IoTGpioRegisterIsrFunc(IOT_IO_NAME_GPIO_8, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, OnButtonBPressed, NULL);
- IoTGpioInit(IOT_IO_NAME_GPIO_5); // oled button 按鍵A
- IoTGpioSetDir(IOT_IO_NAME_GPIO_5, IOT_GPIO_DIR_IN);
- IoTGpioRegisterIsrFunc(IOT_IO_NAME_GPIO_5, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, OnButtonAPressed, NULL);
按鍵響應函數獨立檢測按鍵:①游戲主界面,按鍵選擇難度和開始游戲,②游戲運行中,未按鍵時,蛇身在當前方向移動,直至蛇撞墻;有按鍵時,根據不同的按程序調整蛇的移動方向,并做其他的邏輯處理。
說明:只是簡單的對按鍵進行響應,并未做復雜的優先級和鎖的控制,這一部分有待后續完善。
總結
以上,完成一個基于LVEVK-3861開發板的貪吃蛇小游戲的開發, 限于篇幅,只列出了部分代碼。 由于本人業務水平不夠,整個開發的過程還是有不少的問題出現,解決了部分,也有很多沒有解決。部分功能也沒有做完善,留待后續再去補充吧,畢竟沒有十全十美。