Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
LittlevGL_LVGL
RT-Thread Studio
俄罗斯方块
RT-Thread Studio使用记录(十一) 贪吃蛇+俄罗斯方块
发布于 2021-02-05 14:02:32 浏览:1856
订阅该版
[RT-Thread Studio使用记录(一)点亮led](https://club.rt-thread.org/ask/article/2519.html) [RT-Thread Studio使用记录(二)pwm呼吸灯](https://club.rt-thread.org/ask/article/2520.html) [RT-Thread Studio使用记录(三)flash挂载文件系统](https://club.rt-thread.org/ask/article/2521.html) [RT-Thread Studio使用记录(四)SD-Card 挂载文件系统](https://club.rt-thread.org/ask/article/2526.html) [RT-Thread Studio使用记录(五)USB 虚拟串口](https://club.rt-thread.org/ask/article/2524.html) [RT-Thread Studio使用记录(六)ESP8266网络设备](https://club.rt-thread.org/ask/article/2527.html) [RT-Thread Studio使用记录(七)STemWin](https://club.rt-thread.org/ask/article/2529.html) [RT-Thread Studio使用记录(八)LittlevGL2RTT](https://club.rt-thread.org/ask/article/2530.html) [RT-Thread Studio使用记录(九)LittlevGL2RTT触摸屏](https://club.rt-thread.org/ask/article/2531.html) [RT-Thread Studio使用记录(十)LittlevGL2RTT 贪吃蛇](https://club.rt-thread.org/ask/article/2534.html) [RT-Thread Studio使用记录(十一)LittlevGL2RTT 贪吃蛇+俄罗斯方块](https://club.rt-thread.org/ask/article/2544.html) 本章继续使用 RT-Thread 的 LittlevGL2RTT 软件包,再上一章 “贪吃蛇小游戏” 的基础上,再设计完成一个 “俄罗斯方块” 游戏,并且让这两个游戏公用画面,停止后可以切换。 完成效果:[RT-Thread 使用 LittlevGL 制作贪吃蛇+俄罗斯方块小游戏](https://www.bilibili.com/video/BV1hy4y1Y7UG) 参考:1、[【C语言】俄罗斯方块的源代码](https://blog.csdn.net/wenqiang1208/article/details/71245082) 2、[lvgl官方](https://docs.lvgl.io/v7/en/html/widgets/index.html) 3、[正点原子 lvgl 教程](http://www.openedv.com/forum.php?mod=viewthread&tid=311917&extra=page%3D1%26filter%3Ddigest%26digest%3D1) 本章没有设置项,纯代码操作。 1、 在 applications 文件夹新建 tetris.h 和 tetris.c 两个文件,内容如下: ``` /* * Copyright (c) 2006-2020, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-02-01 mgcheng the first version */ #ifndef APPLICATIONS_TETRIS_H_ #define APPLICATIONS_TETRIS_H_ /** * INCLUDES */ #include "../lvgl/lvgl.h" #include "../lv_conf.h" #include
#include
typedef struct tetris_struct { uint8_t x; //横坐标,以块为单位 uint8_t y; //纵坐标,以块为单位 uint8_t type; //方块种类 uint8_t state; //方块旋转状态 uint16_t value; //当前状态标记值 }tetrist_struct_t; void tetris(void); void tetris_btn_event_cb(lv_obj_t *obj, lv_event_t event); void tetris_roller_event_cb(lv_obj_t *obj, lv_event_t event); #ifdef __cplusplus }/* extern "C" */ #endif // __cplusplus #endif /* APPLICATIONS_TETRIS_H_ */ ``` ``` /* * Copyright (c) 2006-2020, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-02-01 mgcheng the first version */ #include "tetris.h" #include "stdlib.h" #include "time.h" #include
#include
#include "beep.h" #include "lvgl_app.h" #define TETRIS_UP 1 //按键旋转 #define TETRIS_DOWN 2 //按键下降 #define TETRIS_LEFT 3 //按键左移 #define TETRIS_RIGHT 4 //按键右移 #define TETRIS_AUTO_DOWN 5 //自动下落 #define TETRIS_SPEED_MAX 10 #define TETRIS_BLOCK_SIZE_SMALL 5 #define TETRIS_BLOCK_SIZE_MEDIUM 10 #define TETRIS_BLOCK_SIZE_LARGE 20 static uint8_t tetris_speed = 1; //下落速度 static uint8_t tetris_block_size = TETRIS_BLOCK_SIZE_MEDIUM; //块大小 static uint8_t tetris_row_number; //行数 static uint8_t tetris_column_number; //列数 static uint32_t state_map[30] = {0}; //地图块状态,每行用一个 32 位数标记块状态 static uint32_t row_mask; //判断行满掩膜 /** * 不同方块不同状态的块标记,用一个16位数标记4行4列的状态 * 1.横杠 * @@@@ * 2.竖杠 * @*** * @*** * @*** * @*** * 3.田字 * @@ * @@ * 4.左镰刀1 * @@* * *@* * *@* * 5.左镰刀2 * @@@ * @** * 6.左镰刀3 * @* * @* * @@ * 7.左镰刀4 * **@* * @@@* * 8.右镰刀1 * @@ * @* * @* * 9.右镰刀2 * @** * @@@ * 10.右镰刀3 * *@* * *@* * @@* * 11.右镰刀4 * @@@* * **@* * 12.左拐1 * *@* * @@* * @** * 13.左拐2 * @@ * @@ * 14.右拐1 * @** * @@* * *@* * 15.右拐2 * @@ * @@ * 16.山1 * *@* * @@@ * 17.山2 * *@* * @@* * *@* * 18.山3 * @@@ * *@* * 19.山4 * @* * @@ * @* * */ static uint16_t block_value[] = //各种不同方块不同状态的块标记,用一个16位数标记4行4列状态 { // type state 0xf000, //0, 横杠 0 - 0 0x8888, //1, 竖杠 0 - 1 0xcc00, //2, 田字 1 - 0 0xc440, //3, 左镰刀1 2 - 0 0xe800, //4, 左镰刀2 2 - 1 0x88c0, //5, 左镰刀3 2 - 2 0x2e00, //6, 左镰刀4 2 - 3 0xc880, //7, 右镰刀1 3 - 0 0x8e00, //8, 右镰刀2 3 - 1 0x44c0, //9, 右镰刀3 3 - 2 0xe200, //10, 右镰刀4 3 - 3 0x4c80, //11, 左拐1 4 - 0 0xc600, //12, 左拐2 4 - 1 0x8c40, //13, 右拐1 5 - 0 0x6c00, //14, 右拐2 5 - 1 0x4e00, //15, 山1 6 - 0 0x4c40, //16, 山2 6 - 1 0xe400, //17, 山3 6 - 2 0x8c80, //18, 山4 6 - 3 }; static tetrist_struct_t* tetris_now; lv_draw_rect_dsc_t tetris_rect_dsc; int tetris_score = 0, tetris_add = 10; //总分数, 单个食物分数 int status; //方向 static uint16_t tetris_get_state(tetrist_struct_t *tetris) { uint16_t temp = 0; switch(tetris->type) { case 0: //横杠,竖杠 switch(tetris->state) { case 0: //横杠 temp = block_value[0]; break; case 1: //竖杠 temp = block_value[1]; break; default: break; } break; case 1: //田字 temp = block_value[2]; break; case 2: //左镰刀 switch(tetris->state) { case 0: //左镰刀1 temp = block_value[3]; break; case 1: //左镰刀2 temp = block_value[4]; break; case 2: //左镰刀3 temp = block_value[5]; break; case 3: //左镰刀4 temp = block_value[6]; break; default: break; } break; case 3: //右镰刀 switch(tetris->state) { case 0: //右镰刀1 temp = block_value[7]; break; case 1: //右镰刀2 temp = block_value[8]; break; case 2: //右镰刀3 temp = block_value[9]; break; case 3: //右镰刀4 temp = block_value[10]; break; default: break; } break; case 4: //左拐 switch(tetris->state) { case 0: //左拐1 temp = block_value[11]; break; case 1: //左拐2 temp = block_value[12]; break; default: break; } break; case 5: //右拐 switch(tetris->state) { case 0: //右拐1 temp = block_value[13]; break; case 1: //右拐2 temp = block_value[14]; break; default: break; } break; case 6: //山 switch(tetris->state) { case 0: //山1 temp = block_value[15]; break; case 1: //山2 temp = block_value[16]; break; case 2: //山3 temp = block_value[17]; break; case 3: //山4 temp = block_value[18]; break; default: break; } break; default: break; } return temp; } static void tetris_change_state(tetrist_struct_t *tetris) { switch(tetris->type) { case 0: //横杠,竖杠 switch(tetris->state) { case 0: //横杠 -> 竖杠 tetris->state = 1; tetris->value = block_value[1]; break; case 1: //竖杠 -> 横杠 tetris->state = 0; tetris->value = block_value[0]; break; default: break; } break; case 1: //田字 tetris->state = 0; tetris->value = block_value[2]; break; case 2: //左镰刀 switch(tetris->state) { case 0: //左镰刀1 -> 左镰刀2 tetris->state = 1; tetris->value = block_value[4]; break; case 1: //左镰刀2 -> 左镰刀3 tetris->state = 2; tetris->value = block_value[5]; break; case 2: //左镰刀3 -> 左镰刀4 tetris->state = 3; tetris->value = block_value[6]; break; case 3: //左镰刀4 -> 左镰刀1 tetris->state = 0; tetris->value = block_value[3]; break; default: break; } break; case 3: //右镰刀 switch(tetris->state) { case 0: //右镰刀1 -> 右镰刀2 tetris->state = 1; tetris->value = block_value[8]; break; case 1: //右镰刀2 -> 右镰刀3 tetris->state = 2; tetris->value = block_value[9]; break; case 2: //右镰刀3 -> 右镰刀4 tetris->state = 3; tetris->value = block_value[10]; break; case 3: //右镰刀4 -> 右镰刀1 tetris->state = 0; tetris->value = block_value[7]; break; default: break; } break; case 4: //左拐 switch(tetris->state) { case 0: //左拐1 -> 左拐2 tetris->state = 1; tetris->value = block_value[12]; break; case 1: //左拐2 -> 左拐1 tetris->state = 0; tetris->value = block_value[11]; break; default: break; } break; case 5: //右拐 switch(tetris->state) { case 0: //右拐1 -> 右拐2 tetris->state = 1; tetris->value = block_value[14]; break; case 1: //右拐2 -> 右拐1 tetris->state = 0; tetris->value = block_value[13]; break; default: break; } break; case 6: //山 switch(tetris->state) { case 0: //山1 -> 山2 tetris->state = 1; tetris->value = block_value[16]; break; case 1: //山2 -> 山3 tetris->state = 2; tetris->value = block_value[17]; break; case 2: //山3 -> 山4 tetris->state = 3; tetris->value = block_value[18]; break; case 3: //山4 -> 山1 tetris->state = 0; tetris->value = block_value[15]; break; default: break; } break; default: break; } } void tetris_btn_event_cb(lv_obj_t *obj, lv_event_t event) { if(event == LV_EVENT_PRESSED) { if((obj == up_button)) //上 旋转方块 { status = TETRIS_UP; } if((obj == down_button) && (tetris_now->x < tetris_row_number-1)) //下 { status = TETRIS_DOWN; } if((obj == left_button) && (tetris_now->x >= 1)) //左 { status = TETRIS_LEFT; } if((obj == right_button) && (tetris_now->x < tetris_column_number-1)) //右 { status = TETRIS_RIGHT; } if((obj == start_button) && (game_status != GAME_STATUS_RUNNING)) //开始 { game_status = GAME_STATUS_RUNNING; } if((obj == stop_button) && (game_status != GAME_STATUS_STOP)) //停止 { endGamestatus = 3; } if(obj == beep_button) { lv_btn_state_t state = lv_btn_get_state(beep_button); if(state == LV_BTN_STATE_PRESSED) { lv_label_set_text(beep_button_label, LV_SYMBOL_VOLUME_MAX); beep_enable = true; beep(1, 100, 50, 0); // rt_kprintf("beep_enabel = %d\r\n", beep_enable); } else { lv_label_set_text(beep_button_label, LV_SYMBOL_MUTE); beep_enable = false; // rt_kprintf("beep_enabel = %d\r\n", beep_enable); } } } } void tetris_roller_event_cb(lv_obj_t *obj, lv_event_t event) { uint16_t selected_number; if(event == LV_EVENT_VALUE_CHANGED) { selected_number = lv_roller_get_selected(obj); if (obj == speed_roller) //速度 { tetris_speed = selected_number + 1; if(tetris_speed > TETRIS_SPEED_MAX) { tetris_speed = TETRIS_SPEED_MAX; } } else if(obj == size_roller && game_status == GAME_STATUS_STOP) //大小 { switch(selected_number) { case 0: case 1: tetris_block_size = TETRIS_BLOCK_SIZE_MEDIUM; break; case 2: tetris_block_size = TETRIS_BLOCK_SIZE_LARGE; break; default: break; } } } } static void init_tetris(void) //初始小蛇 { int i; lv_color_t color0; uint16_t selected_number; lv_label_set_text(info_label, ""); //清空提示信息 status = TETRIS_AUTO_DOWN; //默认自动下落 rt_memset(state_map, 0, sizeof(state_map)); selected_number = lv_roller_get_selected(speed_roller); //速度初始化 tetris_speed = selected_number + 1; if(tetris_speed > TETRIS_SPEED_MAX) { tetris_speed = TETRIS_SPEED_MAX; } selected_number = lv_roller_get_selected(size_roller); //尺寸初始化 switch(selected_number) { case 0: case 1: tetris_block_size = TETRIS_BLOCK_SIZE_MEDIUM; break; case 2: tetris_block_size = TETRIS_BLOCK_SIZE_LARGE; break; default: break; } tetris_row_number = LVGL_APP_CANVAS_HEIGHT / tetris_block_size; //计算行数 tetris_column_number = LVGL_APP_CANVAS_WIDTH / tetris_block_size; //计算列数 row_mask = 0; for(i=0; i<(sizeof(state_map[0])*8); i++) { if(i
y == 0)) { return 1; } return 0; } static void tetris_draw_block(lv_color_t color) { uint8_t i, j; uint16_t temp; temp = tetris_now->value; tetris_rect_dsc.bg_color = color; for(i=0;i<4;i++) { for(j=0;j<4;j++) { if(temp & 0x8000) { lv_canvas_draw_rect(lvgl_app_canvas, (tetris_now->x+j) * tetris_block_size, (tetris_now->y+i) *tetris_block_size, tetris_block_size, tetris_block_size, &tetris_rect_dsc); } temp <<= 1; } } } static void tetris_creat_block(void) //创造新块 { tetrist_struct_t *food_1; srand((unsigned)time(NULL)); //以时间做随机种子,不会导致每次随机数都一样 food_1 = (tetrist_struct_t *)rt_malloc(sizeof(tetrist_struct_t)); food_1->type = rand() % 7; switch(food_1->type) { case 0: //横杠 case 4: //左拐 case 5: //右拐 food_1->state = rand() % 2; break; case 1: //田字 food_1->state = rand() % 1; break; case 2: //左镰刀 case 3: //右镰刀 case 6: //山 food_1->state = rand() % 4; break; default: break; } food_1->x = tetris_column_number / 2; food_1->y = 0; food_1->value = tetris_get_state(food_1); tetris_now = food_1; lv_color_t color0; color0.full = COLOR_DRAW_WHITE;//指向调色板中的第一种颜色 tetris_draw_block(color0); // rt_kprintf("now->x:%d, now->y:%d, now->type:%d, now->state:%d, now->value:%d\r\n", // tetris_now->x, tetris_now->y, tetris_now->type, tetris_now->state, tetris_now->value); } // 判断 index 行是否满行,满行返回1,否则返回0 static int tetris_full_row(uint8_t index) { if((state_map[index] & row_mask) == row_mask) { return 1; } return 0; } //判断是否还能移动,1,不能;0,能 static int tetris_moveable(void) { uint8_t i, j; uint16_t next_value; uint32_t state_map_value; tetrist_struct_t *tetris_next; tetris_next = rt_malloc(sizeof(tetrist_struct_t)); rt_memcpy(tetris_next, tetris_now, sizeof(tetrist_struct_t)); switch(status) { case TETRIS_UP: tetris_change_state(tetris_next); break; case TETRIS_DOWN: case TETRIS_AUTO_DOWN: tetris_next->y += 1; break; case TETRIS_LEFT: tetris_next->x -= 1; break; case TETRIS_RIGHT: tetris_next->x += 1; break; default : break; } next_value = tetris_next->value; for(i=0;i<4;i++) { state_map_value = state_map[tetris_next->y + i]; state_map_value <<= tetris_next->x; for(j=0;j<4;j++) { if(next_value & 0x8000) //被标记 { if((state_map_value & 0x80000000)//重叠 || ((tetris_next->x + j) >= tetris_column_number) || ((tetris_next->y+i) >= tetris_row_number))//超限 { rt_free(tetris_next); return 1; } } next_value <<= 1; state_map_value <<= 1; } } rt_free(tetris_next); return 0; } static void tetris_down_finish_handle(void) { uint8_t i, j; uint8_t index; //满行行号 lv_color_t color0; uint16_t now_value; uint32_t state_map_value; index = 5; now_value = tetris_now->value; for(i=0; i<4; i++) { state_map_value = state_map[tetris_now->y + i]; //取画布当前行标记 for(j=0;j<4;j++) { if(now_value & 0x8000) //被标记 { state_map_value |= (0x80000000>>(tetris_now->x + j)); } now_value <<= 1; } state_map[tetris_now->y + i] = state_map_value; //保存画布当前行新标记 } for(i=0; i<4; i++) { if(tetris_full_row(tetris_now->y + i)) //满行 { index = i; tetris_score = tetris_score + tetris_add; if(beep_enable == true) { beep(1, 100, 50, 0); //吃到食物提示音,一声 } //清除本行 color0.full = COLOR_DRAW_BLACK;//指向调色板中的第一种颜色 tetris_rect_dsc.bg_color = color0; lv_canvas_draw_rect(lvgl_app_canvas, 0, (tetris_now->y+i)*tetris_block_size, LVGL_APP_CANVAS_WIDTH, tetris_block_size, &tetris_rect_dsc); for(j=tetris_now->y+i; j>0; j--) //调整画布状态值 { state_map[j] = state_map[j - 1]; if(state_map[j] == 0) //遇到空行中止 { break; } } } } if(index != 5) //有满行消除,后续补位 { color0.full = COLOR_DRAW_BLACK;//指向调色板中的第一种颜色 tetris_rect_dsc.bg_color = color0; j=0; for(i=tetris_now->y+index; i>0; i--) //先消除下降行 { state_map_value = state_map[i-1]; if((state_map_value & 0xffffffff) != 0) //不是空行 { lv_canvas_draw_rect(lvgl_app_canvas, 0, (i-1)*tetris_block_size, LVGL_APP_CANVAS_WIDTH, tetris_block_size, &tetris_rect_dsc); } else { if(j < index+1)//多消除几行 { lv_canvas_draw_rect(lvgl_app_canvas, 0, (i-1)*tetris_block_size, LVGL_APP_CANVAS_WIDTH, tetris_block_size, &tetris_rect_dsc); j++; } else { break; } } } color0.full = COLOR_DRAW_WHITE;//指向调色板中的第一种颜色 tetris_rect_dsc.bg_color = color0; for(i=tetris_now->y+index; i>0; i--) { state_map_value = state_map[i]; if((state_map_value & 0xffffffff) != 0) //不是空行 { for(j=0; j
y += 1; break; case TETRIS_LEFT: tetris_now->x -= 1; break; case TETRIS_RIGHT: tetris_now->x += 1; break; default : break; } //重绘新方块 color0.full = COLOR_DRAW_WHITE;//指向调色板中的第一种颜色 tetris_draw_block(color0); // rt_kprintf("now->x:%d, now->y:%d, now->type:%d, now->state:%d, now->value:%d\r\n", // tetris_now->x, tetris_now->y, tetris_now->type, tetris_now->state, tetris_now->value); } else //不能移动 { switch(status) { case TETRIS_DOWN: case TETRIS_AUTO_DOWN: tetris_down_finish_handle(); break; default : break; } // rt_kprintf("now->x:%d, now->y:%d, now->type:%d, now->state:%d, now->value:%d\r\n", // tetris_now->x, tetris_now->y, tetris_now->type, tetris_now->state, tetris_now->value); } status = TETRIS_AUTO_DOWN; //切换回自动下落状态 } static void tetris_run_game(void) // { char str[100]; rt_tick_t tick; tick = rt_tick_get(); while(1) { rt_thread_delay(20);// * (TETRIS_SPEED_MAX - tetris_speed)); //移动速度 if((status == TETRIS_AUTO_DOWN && (rt_tick_get() - tick >= (RT_TICK_PER_SECOND / tetris_speed))) //自由下落,按照设定速度执行 || status == TETRIS_DOWN || status == TETRIS_LEFT || status == TETRIS_RIGHT || status == TETRIS_UP) //按键操作,立即执行 { tetris_move(); if(status == TETRIS_AUTO_DOWN && (rt_tick_get() - tick >= (RT_TICK_PER_SECOND / tetris_speed))) { tick = rt_tick_get(); } sprintf(str, "score: %d ", tetris_score); lv_label_set_text(score_label, str); //显示分数 } if(endGamestatus != 0) { break; } } } static void tetris_init_game(void) { endGamestatus = 0; tetris_score = 0; } static void tetris_end_game(void) { switch(endGamestatus) { case 1: lv_label_set_text(info_label, "sorry, can't cross the wall.\n game over."); break; case 2: lv_label_set_text(info_label, "sorry, can't bit your self.\n game over"); break; case 3: lv_label_set_text(info_label, " game over"); break; default: break; } rt_free(tetris_now); //释放上一个内存 game_status = GAME_STATUS_STOP; if(beep_enable == true) { beep(3, 100, 50, 0); //停止提示音,三声 } } static void tetris_game_start(void) // { tetris_init_game(); init_tetris(); tetris_creat_block(); } void tetris(void) { tetris_game_start(); tetris_run_game(); if(endGamestatus != 0) { tetris_end_game(); } } ``` 2、 参照 tetris.c 和 tetris.h 修改上一章的 snake.c 和 snake.h 两个文件。 3、 在 applications 文件夹新建 lvgl_app.h , 并修改 lvgl_app.c ,内容如下: ``` /* * Copyright (c) 2006-2020, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-02-01 Administrator the first version */ #ifndef APPLICATIONS_LVGL_APP_H_ #define APPLICATIONS_LVGL_APP_H_ #include "../lvgl/lvgl.h" #include "../lv_conf.h" #define GAME_STATUS_RUNNING 1 #define GAME_STATUS_STOP 0 #define BORDER_X_START 10 #define BORDER_X_END 210 #define BORDER_Y_START 1 #define BORDER_Y_END 271 #define BORDER_LINE_WIDTH 2 #define BORDER_LINE_COLOR LV_COLOR_RED #define LVGL_APP_CANVAS_WIDTH (BORDER_X_END-BORDER_X_START) //202//180 //画布 2 的宽度 #define LVGL_APP_CANVAS_HEIGHT (BORDER_Y_END-BORDER_Y_START) //272//240 //画布 2 的高度 #define COLOR_DRAW_WHITE 0 #define COLOR_DRAW_BLACK 5627 extern lv_obj_t *up_button, *down_button, *left_button, *right_button, *start_button, *stop_button; extern lv_obj_t *beep_button; extern lv_obj_t *speed_roller, *size_roller; //速度,大小选项、 extern uint8_t beep_enable; extern lv_obj_t * lvgl_app_canvas; //画布 extern lv_obj_t *beep_button_label; extern lv_obj_t *info_label; //提示 extern lv_obj_t *score_label; //分数 extern int endGamestatus; //游戏停止原因 extern lv_obj_t* lvgl_app_scr; extern int game_status; //游戏状态, 1,运行;0,停止 void creat_map(void); #endif /* APPLICATIONS_LVGL_APP_H_ */ ``` ``` /* * Copyright (c) 2006-2020, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-01-06 mgcheng the first version */ #include "littlevgl2rtt.h" #include "lvgl.h" #include "lvgl_app.h" #include "tetris.h" #include "snake.h" #include "beep.h" #include
#define SNAKE_GAME_INDEX 0 #define TETRIS_GAME_INDEX 1 static uint8_t choose_game = SNAKE_GAME_INDEX; //0,贪吃蛇; 1,俄罗斯方块 const lv_point_t border_line_points[] = {{BORDER_X_START, BORDER_Y_START}, //边界点 {BORDER_X_START, BORDER_Y_END}, {BORDER_X_END, BORDER_Y_END}, {BORDER_X_END, BORDER_Y_START}, {BORDER_X_START, BORDER_Y_START}}; const char speed_roller_options[] = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; const char size_roller_options[] = "small\nmedium\nlarge"; const char choose_game_roller_options[] = "snake\ntetris"; lv_color_t lvgl_app_canvas_cbuf[LV_CANVAS_BUF_SIZE_ALPHA_1BIT(LVGL_APP_CANVAS_WIDTH, LVGL_APP_CANVAS_HEIGHT)]; lv_obj_t* lvgl_app_scr; lv_obj_t * lvgl_app_canvas; //画布 lv_obj_t *up_button, *down_button, *left_button, *right_button, *start_button, *stop_button; lv_obj_t *beep_button; lv_obj_t *speed_roller, *size_roller; //速度,大小选项、 lv_obj_t *choose_game_roller; //游戏选择 lv_obj_t *beep_button_label; lv_obj_t *info_label; //提示 lv_obj_t *score_label; //分数 uint8_t beep_enable = false; int endGamestatus = 0; //游戏停止原因 int game_status = GAME_STATUS_STOP; //游戏状态, 1,运行;0,停止 static void change_button_cb(void) { switch(choose_game) { case SNAKE_GAME_INDEX: //贪吃蛇 lv_obj_set_event_cb(up_button, snake_btn_event_cb); lv_obj_set_event_cb(down_button, snake_btn_event_cb); lv_obj_set_event_cb(left_button, snake_btn_event_cb); lv_obj_set_event_cb(right_button, snake_btn_event_cb); lv_obj_set_event_cb(start_button, snake_btn_event_cb); lv_obj_set_event_cb(stop_button, snake_btn_event_cb); lv_obj_set_event_cb(beep_button, snake_btn_event_cb); lv_obj_set_event_cb(speed_roller, snake_roller_event_cb); lv_obj_set_event_cb(size_roller, snake_roller_event_cb); break; case TETRIS_GAME_INDEX: //俄罗斯方块 lv_obj_set_event_cb(up_button, tetris_btn_event_cb); lv_obj_set_event_cb(down_button, tetris_btn_event_cb); lv_obj_set_event_cb(left_button, tetris_btn_event_cb); lv_obj_set_event_cb(right_button, tetris_btn_event_cb); lv_obj_set_event_cb(start_button, tetris_btn_event_cb); lv_obj_set_event_cb(stop_button, tetris_btn_event_cb); lv_obj_set_event_cb(beep_button, tetris_btn_event_cb); lv_obj_set_event_cb(speed_roller, tetris_roller_event_cb); lv_obj_set_event_cb(size_roller, tetris_roller_event_cb); break; default: break; } } static void roller_event_cb(lv_obj_t *obj, lv_event_t event) { uint16_t selected_number; if(event == LV_EVENT_VALUE_CHANGED) { selected_number = lv_roller_get_selected(obj); if(obj == choose_game_roller && game_status == GAME_STATUS_STOP) //大小 { switch(selected_number) { case 0: choose_game = SNAKE_GAME_INDEX; //0,贪吃蛇; 1,俄罗斯方块 change_button_cb(); //切换按键功能 break; case 1: choose_game = TETRIS_GAME_INDEX; //0,贪吃蛇; 1,俄罗斯方块 change_button_cb(); //切换按键功能 break; default: break; } } } } void creat_map(void) //画初始面板 { lv_color_t color0; lv_obj_t *border_line; static lv_style_t style_border_line; lv_style_init(&style_border_line); //外框线style lv_style_set_line_width(&style_border_line, LV_STATE_DEFAULT, BORDER_LINE_WIDTH); lv_style_set_line_color(&style_border_line, LV_STATE_DEFAULT, BORDER_LINE_COLOR); lv_style_set_line_rounded(&style_border_line, LV_STATE_DEFAULT, true); lvgl_app_scr = lv_disp_get_scr_act(NULL); border_line = lv_line_create(lvgl_app_scr, NULL); //外框线 lv_line_set_points(border_line, border_line_points, sizeof(border_line_points)/sizeof(border_line_points[0])); lv_obj_add_style(border_line, LV_LINE_PART_MAIN, &style_border_line); info_label = lv_label_create(lvgl_app_scr, NULL); // 提示 lv_obj_set_pos(info_label, 295, 10); lv_obj_set_width(info_label, 100); lv_label_set_text(info_label, ""); score_label = lv_label_create(lvgl_app_scr, NULL); //分数 lv_obj_set_pos(score_label, 355, 60); lv_label_set_text(score_label, ""); lvgl_app_canvas = lv_canvas_create(lvgl_app_scr, NULL); //画布 lv_canvas_set_buffer(lvgl_app_canvas, lvgl_app_canvas_cbuf, LVGL_APP_CANVAS_WIDTH, LVGL_APP_CANVAS_HEIGHT, LV_IMG_CF_ALPHA_1BIT); color0.full = COLOR_DRAW_BLACK;//指向调色板中的第一种颜色 lv_obj_align(lvgl_app_canvas, NULL, LV_ALIGN_IN_LEFT_MID, 10, 0); lv_canvas_fill_bg(lvgl_app_canvas, color0, LV_OPA_COVER); up_button = lv_btn_create(lvgl_app_scr, NULL); // lv_obj_set_event_cb(up_button, btn_event_cb); lv_obj_set_size(up_button, 50, 50); lv_obj_set_pos(up_button, 380, 100); down_button = lv_btn_create(lvgl_app_scr, NULL); // lv_obj_set_event_cb(down_button, btn_event_cb); lv_obj_set_size(down_button, 50, 50); lv_obj_align(down_button, up_button, LV_ALIGN_OUT_BOTTOM_MID, 0, 50); left_button = lv_btn_create(lvgl_app_scr, NULL); // lv_obj_set_event_cb(left_button, btn_event_cb); lv_obj_set_size(left_button, 50, 50); lv_obj_align(left_button, up_button, LV_ALIGN_OUT_BOTTOM_LEFT, -50, 0); right_button = lv_btn_create(lvgl_app_scr, NULL); // lv_obj_set_event_cb(right_button, btn_event_cb); lv_obj_set_size(right_button, 50, 50); lv_obj_align(right_button, up_button, LV_ALIGN_OUT_BOTTOM_RIGHT, 50, 0); start_button = lv_btn_create(lvgl_app_scr, NULL); // lv_obj_set_event_cb(start_button, btn_event_cb); lv_obj_set_size(start_button, 50, 50); lv_obj_align(start_button, left_button, LV_ALIGN_OUT_BOTTOM_LEFT, -100, 0); stop_button = lv_btn_create(lvgl_app_scr, NULL); // lv_obj_set_event_cb(stop_button, btn_event_cb); lv_obj_set_size(stop_button, 50, 50); lv_obj_align(stop_button, left_button, LV_ALIGN_OUT_TOP_LEFT, -100, 30); beep_button = lv_btn_create(lvgl_app_scr, NULL); // lv_obj_set_event_cb(beep_button, btn_event_cb); lv_obj_set_size(beep_button, 30, 30); lv_obj_align(beep_button, left_button, LV_ALIGN_OUT_BOTTOM_LEFT, -35, -10); lv_btn_set_checkable(beep_button, true); lv_obj_t* up_button_label = lv_label_create(up_button, NULL); lv_obj_t* down_button_label = lv_label_create(down_button, NULL); lv_obj_t* left_button_label = lv_label_create(left_button, NULL); lv_obj_t* right_button_label = lv_label_create(right_button, NULL); lv_obj_t* start_button_label = lv_label_create(start_button, NULL); lv_obj_t* stop_button_label = lv_label_create(stop_button, NULL); beep_button_label = lv_label_create(beep_button, NULL); lv_label_set_text(up_button_label, "U"); lv_label_set_text(down_button_label, "D"); lv_label_set_text(left_button_label, "L"); lv_label_set_text(right_button_label, "R"); lv_label_set_text(start_button_label, "start"); lv_label_set_text(stop_button_label, "stop"); lv_label_set_text(beep_button_label, LV_SYMBOL_MUTE); speed_roller = lv_roller_create(lvgl_app_scr, NULL); //速度选项 lv_roller_set_options(speed_roller, speed_roller_options, LV_ROLLER_MODE_INIFINITE); lv_roller_set_fix_width(speed_roller, 80); lv_roller_set_visible_row_count(speed_roller, 1); lv_roller_set_selected(speed_roller, 0, LV_ANIM_OFF); lv_obj_align(speed_roller, stop_button, LV_ALIGN_OUT_TOP_MID, 0, -30); // lv_obj_set_event_cb(speed_roller, roller_event_cb); size_roller = lv_roller_create(lvgl_app_scr, NULL); //尺寸选项 lv_roller_set_options(size_roller, size_roller_options, LV_ROLLER_MODE_INIFINITE); lv_roller_set_fix_width(size_roller, 80); lv_roller_set_visible_row_count(size_roller, 1); lv_roller_set_selected(size_roller, 1, LV_ANIM_OFF); lv_obj_align(size_roller, speed_roller, LV_ALIGN_OUT_TOP_MID, 0, -10); // lv_obj_set_event_cb(size_roller, roller_event_cb); choose_game_roller = lv_roller_create(lvgl_app_scr, NULL); //尺寸选项 lv_roller_set_options(choose_game_roller, choose_game_roller_options, LV_ROLLER_MODE_INIFINITE); lv_roller_set_fix_width(choose_game_roller, 80); lv_roller_set_visible_row_count(choose_game_roller, 1); lv_roller_set_selected(choose_game_roller, 0, LV_ANIM_OFF); lv_obj_align(choose_game_roller, left_button, LV_ALIGN_OUT_BOTTOM_LEFT, -42, 30); lv_obj_set_event_cb(choose_game_roller, roller_event_cb); } static void lvgl_app_entry(void *parameter) { creat_map(); //初始画面 change_button_cb(); //初始按键功能 for(;;) { if(game_status == GAME_STATUS_RUNNING)//开始 { lv_obj_set_hidden(choose_game_roller, true); //隐藏游戏选择按键 switch(choose_game) { case SNAKE_GAME_INDEX: //贪吃蛇 snake(); break; case TETRIS_GAME_INDEX: //俄罗斯方块 tetris(); break; default: break; } } else { lv_obj_set_hidden(choose_game_roller, false); //显示游戏选择按键 } rt_thread_delay(RT_TICK_PER_SECOND / 10); } } int rt_lvgl_app_init(void) { rt_err_t ret = RT_EOK; rt_thread_t thread = RT_NULL; /* init littlevGL */ ret = littlevgl2rtt_init("lcd"); if(ret != RT_EOK) { return ret; } /* littleGL demo gui thread */ thread = rt_thread_create("lvgl_app", lvgl_app_entry, RT_NULL, 10*1024, 7, 10); if(thread == RT_NULL) { return RT_ERROR; } rt_thread_startup(thread); return RT_EOK; } //INIT_APP_EXPORT(rt_lvgl_app_init); ``` 4、编译,下载。 ![before_snake.jpg](https://oss-club.rt-thread.org/uploads/20210205/a3a6bcfe3523268e0f557ece171e9d2b.jpg) ![snake.jpg](https://oss-club.rt-thread.org/uploads/20210205/577098c773c14e63b6333214114936ae.jpg) ![before_tetris.jpg](https://oss-club.rt-thread.org/uploads/20210205/da40077e41c95ed4df5a6d952515b09b.jpg) ![tetris.jpg](https://oss-club.rt-thread.org/uploads/20210205/1842214e03913d769ae1b6a89b848f65.jpg)
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
mgcheng
这家伙很懒,什么也没写!
文章
12
回答
2
被采纳
0
关注TA
发私信
相关文章
1
rt_thread studio 啥时候能用呢
2
RT_Thread使用反馈帖子
3
RTT studio 下的 AT指令问题。
4
什么时候RTT Sdudio支持Ubuntu,Deepin和UOS操作系统
5
rt thread Studio 关于J-LINK下载问题
6
RT-Thread studio 调试设置问题
7
RTT-Studio 如何设置调试配置参数?
8
rt_thread studio 软件包配置
9
RT-Studio目前只能开发STM32的项目吗?
10
rtt studio 生成hex名字修改
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部