我们在上一篇已经可以通过按键控制蛇移动,我们在此基础上增加产生食物及撞墙及头身体相撞则触发gameover 的逻辑并显示gameove 画面。
之前过程贴连接如下:
Let'sDo第2期任务+《贪吃蛇》过程1+贪吃蛇按键采集、
Let'sDo第2期任务+《贪吃蛇》过程2+PIM580适配LVGL
Let'sDo第2期任务+《贪吃蛇》过程3+按键控制贪吃蛇移动
在此基础上添加控制算法:
#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 gen_food(void)
{
rt_list_t* head = NULL;
rt_list_t* pos = NULL;
link_snake * snake_body;
head = spriteSnake;
rt_list_t* frist = NULL;
uint16_t i = 0,len = 0;
len = rt_list_len(head);
while((i != len))
{
i = 0;
game_snake.food_x = (my_rand()%(GAME_LV_HOR_RES));
game_snake.food_y = (my_rand()%(GAME_LV_VER_RES));
game_snake.food_x -= game_snake.food_x%GAME_SNAKE_SIZE;
game_snake.food_y -= game_snake.food_y%GAME_SNAKE_SIZE;
rt_list_for_each(pos,head)
{
i++;
snake_body = rt_container_of(pos,link_snake,node);
if((abs(game_snake.food_x - snake_body->x) <= GAME_SNAKE_SIZE)&&\
(abs(game_snake.food_y - snake_body->y) <= GAME_SNAKE_SIZE))
{
break;
}
}
}
LCD_draw_block(game_snake.food_x,game_snake.food_y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GAME_FOOD_COLOR);
}
/*
* 函数名: static void lv_100ask_stm32_game_snake_init(void)
* 输入参数: 无
* 返回值: 无
* 函数作用: 应用界面初始化
*/
void game_snake_init(void)
{
/* init game status */
game_snake.gesture = SNAKE_MOVE_UP;
game_snake.status = GAME_STATUS_START;
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));
init_x -= init_x%GAME_SNAKE_SIZE;
init_y -= init_y%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 */
gen_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 -= GAME_SNAKE_SIZE;
break;
case SNAKE_MOVE_LEFT:
snake_body_head->x -= GAME_SNAKE_SIZE;
break;
case SNAKE_MOVE_DOWN:
snake_body_head->y += GAME_SNAKE_SIZE;
break;
case SNAKE_MOVE_RIGHT:
snake_body_head->x += GAME_SNAKE_SIZE;
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);
}
uint8_t game_snake_eat_food(void)
{
/* get head pos */
rt_list_t* head = NULL;
link_snake *body;
head = spriteSnake;
link_snake * snake_body_head = rt_container_of( head->next,link_snake,node);
//rt_kprintf("food %d %d head %d %d\n",game_snake.food_x,game_snake.food_y,snake_body_head->x,snake_body_head->y);
/* check head pos and food pos */
/* left */
if((game_snake.gesture == SNAKE_MOVE_LEFT) &&
(snake_body_head->y == game_snake.food_y) &&
(snake_body_head->x == game_snake.food_x + GAME_SNAKE_SIZE))
{
goto eat_food;
}
/* right */
if((game_snake.gesture == SNAKE_MOVE_RIGHT) &&
(snake_body_head->y == game_snake.food_y) &&
(snake_body_head->x == game_snake.food_x - GAME_SNAKE_SIZE))
{
goto eat_food;
}
/* up */
if((game_snake.gesture == SNAKE_MOVE_UP) &&
(snake_body_head->x== game_snake.food_x) &&
(snake_body_head->y == game_snake.food_y + GAME_SNAKE_SIZE))
{
goto eat_food;
}
/* down */
if((game_snake.gesture == SNAKE_MOVE_DOWN) &&
(snake_body_head->x== game_snake.food_x) &&
(snake_body_head->y == game_snake.food_y - GAME_SNAKE_SIZE))
{
goto eat_food;
}
return 0;
eat_food:
rt_kprintf("eate food \n");
/* create snake body list */
body = (link_snake*)malloc(sizeof(link_snake));
body->x = snake_body_head->x;
body->y = snake_body_head->y;
rt_list_insert_after(&snake_body_head->node,&body->node);
/* update head pos */
snake_body_head->x = game_snake.food_x;
snake_body_head->y = game_snake.food_y;
/* draw snake */
LCD_draw_block(body->x,body->y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GAME_BODY_COLOR);
LCD_draw_block(snake_body_head->x,snake_body_head->y,GAME_SNAKE_SIZE,GAME_SNAKE_SIZE,GAME_SNAKE_HEAD_COLOR);
/* gen new food */
gen_food();
return 1;
}
void snake_gameover_check(void)
{
/* get head pos */
rt_list_t* head = NULL;
rt_list_t* pos = NULL;
link_snake *snake_body;
head = spriteSnake;
uint16_t x,y;
uint16_t i = 0;
link_snake * snake_body_head = rt_container_of( head->next,link_snake,node);
if(game_snake.status != GAME_STATUS_START)
return;
/* touch wall check */
if((game_snake.gesture == SNAKE_MOVE_UP) && (snake_body_head->y == 0))
game_snake.status = GAME_STATUS_SHOW_OVER;
if((game_snake.gesture == SNAKE_MOVE_DOWN) && (snake_body_head->y == GAME_LV_VER_RES - GAME_SNAKE_SIZE))
game_snake.status = GAME_STATUS_SHOW_OVER;
if((game_snake.gesture == SNAKE_MOVE_LEFT) && (snake_body_head->x == 0))
game_snake.status = GAME_STATUS_SHOW_OVER;
if((game_snake.gesture == SNAKE_MOVE_RIGHT) && (snake_body_head->x == GAME_LV_HOR_RES - GAME_SNAKE_SIZE))
game_snake.status = GAME_STATUS_SHOW_OVER;
/* touch body check */
if(game_snake.gesture == SNAKE_MOVE_UP)
{
x = snake_body_head->x;
y = snake_body_head->y - GAME_SNAKE_SIZE;
}
if(game_snake.gesture == SNAKE_MOVE_DOWN)
{
x = snake_body_head->x;
y = snake_body_head->y + GAME_SNAKE_SIZE;
}
if(game_snake.gesture == SNAKE_MOVE_LEFT)
{
x = snake_body_head->x - GAME_SNAKE_SIZE;
y = snake_body_head->y;
}
if(game_snake.gesture == SNAKE_MOVE_RIGHT)
{
x = snake_body_head->x + GAME_SNAKE_SIZE;
y = snake_body_head->y;
}
rt_list_for_each(pos,head)
{
snake_body = rt_container_of(pos,link_snake,node);
if((i > 0) && (x == snake_body->x) && (y == snake_body->y))
{
game_snake.status = GAME_STATUS_SHOW_OVER;
}
i++;
}
}
void game_snake_start(void)
{
if( 0 == game_snake_eat_food())
{
game_snake_move();
}
}
extern const char gameover_320_240[153600];
void game_snake_showover(void)
{
rt_kprintf("snake game over \n");
LCD_DrawBitmap(0,0,320,240,gameover_320_240);
game_snake.status = GAME_STATUS_IDLE;
}
void snake_game(void)
{
snake_gameover_check();
switch(game_snake.status)
{
case GAME_STATUS_START:
game_snake_start();
break;
case GAME_STATUS_SHOW_OVER:
game_snake_showover();
break;
case GAME_STATUS_IDLE:
break;
default:
break;
}
}
void set_move_dir(uint8_t dir)
{
if((game_snake.gesture == SNAKE_MOVE_UP) && (dir == SNAKE_MOVE_DOWN))
{
return;
}
if((game_snake.gesture == SNAKE_MOVE_DOWN) && (dir == SNAKE_MOVE_UP))
{
return;
}
if((game_snake.gesture == SNAKE_MOVE_RIGHT) && (dir == SNAKE_MOVE_LEFT))
{
return;
}
if((game_snake.gesture == SNAKE_MOVE_LEFT) && (dir == SNAKE_MOVE_RIGHT))
{
return;
}
game_snake.gesture = dir;
}
#ifdef RT_USING_FINSH
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <finsh.h>
#include <msh_parse.h>
static void __snake(int argc, char *argv[])
{
rt_list_t* head = NULL;
rt_list_t* pos = NULL;
link_snake * snake_body;
head = spriteSnake; //将temp指针重新指向头结点
rt_kprintf("food %d %d \n", game_snake.food_x, game_snake.food_y);
rt_list_for_each(pos,head)
{
snake_body = rt_container_of(pos,link_snake,node);
rt_kprintf("body %d %d \n", snake_body->x, snake_body->y);
}
}
MSH_CMD_EXPORT_ALIAS(__snake, snake, snake [option]);
#endif /* end of RT_USING_FINSH */初版运行效果:

在基本功能的基础上更新显示素材,添加游戏开始结束画面,及产生多个和食物及添加障碍物的逻辑。



添加分数显示

添加暂停控制,并在底部显示游戏运行状态

添加flash 存储游戏记录显示

视频链接:
https://www.bilibili.com/video/BV1czWseoEdn/?vd_source=8c50c870cce93f7cea3a8fcc81260ac1
我要赚赏金
