ESP32 開發筆記(十五)使用 LittlevGL 實現 2048 小遊戲

使用 LittlevGL 實現 2048 小遊戲

2048 這款益智小遊戲,遊戲的規則十分簡單,簡單易上手的數字小遊戲,但又十分虐心。曾經也是風靡一時。

現在我們在 ESP32 上自己動手實現 2048 這款小遊戲吧。

1 使用 LittlevGL

esp32-lvgl-gui 倉庫已經適配了 LittlevGL V5.3,並適配了幾款屏幕(ILI9341、ST7789、SSD1306、NT35510) 和 觸摸驅動(FT5X06、XPT2046)。

使用時,在 menuconfig 中選擇你所使用的 屏幕 和 觸摸驅動。

編譯代碼:

  1. 添加頭文件:
/* lvgl includes */
#include "iot_lvgl.h"

/* game include */
#include "game.h"
  1. 初始化 LittlevGL:
extern "C" void app_main()
{
    /* Initialize LittlevGL */
    lv_init();

    /* Tick interface, Initialize a Timer for 1 ms period and in its interrupt call*/
    // esp_register_freertos_tick_hook(lv_tick_task_callback);
    lvgl_tick_timer = xTimerCreate(
        "lv_tickinc_task",
        1 / portTICK_PERIOD_MS,            //period time
        pdTRUE,                            //auto load
        (void *)NULL,                      //timer parameter
        lv_tick_task_callback);            //timer callback
    xTimerStart(lvgl_tick_timer, 0);

    /* Display interface */
    lvgl_lcd_display_init();	           /*Initialize your display*/

    /* Input device interface */
    input_device = lvgl_indev_init();                     /*Initialize your indev*/

    lvgl_timer = xTimerCreate(
        "lv_task",
        10 / portTICK_PERIOD_MS,           //period time
        pdTRUE,                            //auto load
        (void *)NULL,                      //timer parameter
        lvgl_task_time_callback);          //timer callback
    xTimerStart(lvgl_timer, 0);

	// 2048 game init
    game_init(480);

	// game logic handle task
    xTaskCreate(
        user_task,   //Task Function
        "user_task", //Task Name
        1024*4,      //Stack Depth
        NULL,        //Parameters
        1,           //Priority
        NULL);       //Task Handler
}

2 2048 遊戲邏輯

2.1 界面初始化

將遊戲相關界面初始化分爲以下幾步:

  1. Step 1: 畫遊戲背景
  2. Step 2: 畫遊戲分數顯示框
  3. Step 3: 畫遊戲網格
  4. Step 4: 畫遊戲網格中每個單元格的內容

2.2 滑動處理

2.2.1 判斷滑動方向

通過調用 LittlevGL 的 API 讀取觸摸狀態(擡起/按下、座標點),計算水平/豎直方向滑動的差值,判斷爲哪個方向上的滑動(上/下/左/右),執行相應的操作。

static lv_indev_drv_t input_device;

static void user_task(void *pvParameter)
{
    bool pressing = false;
    uint8_t value = 0;
    lv_indev_data_t touchpad_data;
    lv_point_t last_data;
    int16_t x_diff, y_diff;
    while (1)
    {
        vTaskDelay(50 / portTICK_PERIOD_MS);
        input_device.read(&touchpad_data); // 讀取觸摸驅動的值
        if (touchpad_data.state == LV_INDEV_STATE_REL) { // 當前爲 `擡起` 狀態
            pressing = false; // 計算座標偏移量
            x_diff = touchpad_data.point.x - last_data.x;
            y_diff = touchpad_data.point.y - last_data.y;
            if(fabs(x_diff) > SENSITIVE || fabs(y_diff) > SENSITIVE) { // 判斷滑動距離是否超過判斷閾值
                if (fabs(x_diff) > fabs(y_diff)) { // 判斷是否爲水平滑動
                    if (x_diff > 0) { // 判單是否爲向右滑動
                        move_right();
                    } else { // 向左滑動
                        move_left();
                    }
                } else { // 豎直方向滑動
                    if (y_diff > 0) { // 判單是否爲向下滑動
                        move_down();
                    } else { // 向上滑動
                        move_up();
                    }
                }
            }
            last_data.x = touchpad_data.point.x;
            last_data.y = touchpad_data.point.y;
        } else if (touchpad_data.state == LV_INDEV_STATE_PR) { // 當前爲 `按下` 狀態
            if (!pressing) { // 按下狀態,記錄初次按下的座標點
                last_data.x = touchpad_data.point.x;
                last_data.y = touchpad_data.point.y;
                pressing = true;
            }
        }
    }
}

2.2.2 滑動邏輯處理

  1. 判斷同一行/列滑動方向上是否存在相等的數值
  2. 相同的單元格,數值相加爲相鄰單元格中的後一個(滑動方向上)的數值
  3. 畫出總的得分
  4. 判斷遊戲是否結束
  5. 刷新界面上的單元格
static uint16_t num_matrix[5][5] = {0}; // 保存所有的單元格中的數值
static uint32_t score_num = 0; // 總得分

void move_up()
{
    int i, j, k, t, nx = -1, ny = 0, nn = 0;
    for (i = 1; i <= 4; ++i)
        tmp[i] = 0;
    for (j = 1; j <= 4; ++j)
    {
        k = 0;
        for (i = 1; i <= 4; ++i)
        {
            if (num_matrix[i][j])
            {
                tmp[++k] = num_matrix[i][j];
                num_matrix[i][j] = 0;
            }
        }
        t = 1;
        while (t <= k - 1)
        {
            if (tmp[t] == tmp[t + 1])
            {
                tmp[t] *= 2;
                tmp[t + 1] = 0;
                score_num += tmp[t];
                if (nx == -1)
                {
                    nx = t;
                    ny = j;
                    nn = tmp[t];
                }
                t += 2;
            }
            else
                t++;
        }
        t = 1;
        for (i = 1; i <= k; ++i)
            if (tmp[i])
                num_matrix[t++][j] = tmp[i];
    }
    // 畫總分
    draw_score_num(score_num);
    // 刷新網格中單元格的內容
    gen_num();
}

參考鏈接

GitHub 源碼:esp32-lvgl-gui
Twitter 視頻:Twitter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章