在之前的帖子中已经按照贪吃蛇需要的按键检测(Let'sDo第2期任务+过程1+贪吃蛇按键采集)及LCD 显示(Let'sDo第2期任务+《贪吃蛇》过程2+PIM580适配LVGL)了,在此基础上开始贪吃蛇游戏的进一步开发,将按键检测和LCD 显示相结合,通过按键控制贪吃蛇的运动。蛇身的移动通过双向链表来记录位置信息,移动过程中采用如下算法:
首先将最后一个节点设置未背景色
更新蛇头为身体颜色
更新蛇头位置信息并刷新显示
对应代码如下:
#include <rtthread.h> #include <stdio.h> #include <stdlib.h> #include "snake.h" #include <hardware/structs/systick.h> static rt_list_t *spriteSnake; // 链表头(蛇头) snake_game_t game_snake; static uint32_t my_rand(void) { return systick_hw->cvr; } /* * 函数名: static link_snake* lv_100ask_stm32_game_snake_initLink(void) * 输入参数: 无 * 返回值: 初始化后的链表 * 函数作用: 初始化链表(蛇) */ static void game_snake_initLink(void) { /* init snake body list */ static rt_list_t snake_body = RT_LIST_OBJECT_INIT(snake_body); spriteSnake = &snake_body; for (int i = 0; i < GAME_SNAKE_INIT_LINE; i++) { link_snake *body = (link_snake*)malloc(sizeof(link_snake)); body->x = i; body->y = i; rt_list_insert_before(spriteSnake,&body->node); } } /* * 函数名: static void lv_100ask_stm32_game_snake_init(void) * 输入参数: 无 * 返回值: 无 * 函数作用: 应用界面初始化 */ void game_snake_init(void) { game_snake.gesture = SNAKE_MOVE_UP; game_snake_initLink(); rt_list_t* head = NULL; rt_list_t* pos = NULL; link_snake * snake_body; head = spriteSnake; //将temp指针重新指向头结点 int i = 0; uint16_t init_x = (my_rand()%(GAME_LV_HOR_RES - (GAME_SNAKE_INIT_LINE * GAME_SNAKE_SIZE))); uint16_t init_y = (my_rand()%(GAME_LV_VER_RES - GAME_SNAKE_SIZE)); rt_list_for_each(pos,head) { snake_body = rt_container_of(pos,link_snake,node); if(i == 0) { /* draw head to lcd */ LCD_draw_block(init_x,init_y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GAME_SNAKE_HEAD_COLOR); } else { LCD_draw_block(init_x,init_y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GAME_BODY_COLOR); } snake_body->x = init_x; snake_body->y = init_y; init_x = init_x+GAME_SNAKE_SIZE; i++; } /* init food */ } void game_snake_move(void) { rt_list_t* head = NULL; rt_list_t* frist = NULL; rt_list_t* pos = NULL; rt_list_t* last = NULL; link_snake * snake_body_last; link_snake * snake_body_head; head = spriteSnake; /* update snake body */ frist = spriteSnake->next; last = spriteSnake->prev; /* clear last body cloor */ snake_body_last = rt_container_of(last,link_snake,node); LCD_draw_block(snake_body_last->x,snake_body_last->y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GLCD_COLOR_CYAN); snake_body_head = rt_container_of(frist,link_snake,node); /* move head postion to laster */ snake_body_last->x = snake_body_head->x; snake_body_last->y = snake_body_head->y; LCD_draw_block(snake_body_head->x,snake_body_head->y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GAME_BODY_COLOR); switch(game_snake.gesture) { case SNAKE_MOVE_UP: snake_body_head->y -= 15; break; case SNAKE_MOVE_LEFT: snake_body_head->x -= 15; break; case SNAKE_MOVE_DOWN: snake_body_head->y += 15; break; case SNAKE_MOVE_RIGHT: snake_body_head->x += 15; break; } LCD_draw_block(snake_body_head->x,snake_body_head->y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GAME_SNAKE_HEAD_COLOR); rt_list_remove(&snake_body_last->node); rt_list_insert_after(&snake_body_head->node,&snake_body_last->node); } void set_move_dir(uint8_t dir) { rt_kprintf("dir %d \n",dir); game_snake.gesture = dir; }
控制结果如下:
后续继续实物产生及吞噬食物后刷新显示的逻辑。