这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sDo第2期任务+《贪吃蛇》成果贴

共4条 1/1 1 跳转至

Let'sDo第2期任务+《贪吃蛇》成果贴

助工
2024-08-11 09:23:35     打赏

我们在上一篇已经可以通过按键控制蛇移动,我们在此基础上增加产生食物及撞墙及头身体相撞则触发gameover 的逻辑并显示gameove 画面。

之前过程贴连接如下:

Let'sDo第2期任务+《贪吃蛇》开箱帖

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 */

初版运行效果:

20240811-164837.gif

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

添加分数显示

image.png

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

image.png

添加flash 存储游戏记录显示

image.png

视频链接:

https://www.bilibili.com/video/BV1czWseoEdn/?vd_source=8c50c870cce93f7cea3a8fcc81260ac1



专家
2024-08-11 09:38:03     打赏
2楼

感谢分享


高工
2024-08-11 10:14:52     打赏
3楼

感谢分享


专家
2024-08-11 10:23:49     打赏
4楼

感谢分享


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]