文章目录[隐藏]
基于单片机stm32f407的单机小游戏----贪吃蛇小游戏
1.介绍
这是我花一个星期完成的一个简单地单机贪吃蛇小游戏项目,芯片是stm32f407,项目是基于正点原子-探索者开发板完成的,有需要的伙伴可以看看,其他开发板也区别不大,主要看算法。
一、运行效果
- 运行效果图
开始游戏
二、软件设计
1.主程序main.c
main.c中,首先对系统的一些初始化,初始化完后开始游戏,游戏结束后按下按键up键,重新开始游戏。用到硬件有:led,lcd,按键,硬件随机数发生器,蜂鸣器(可选),串口,外部SRAM,flash(存放最高分)。
代码如下:
#include "snake.h"
int main(void)
{
START:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口
FSMC_SRAM_Init();//外部SRAM初始化
my_mem_init(SRAMIN);//初始化内部内存池
my_mem_init(SRAMEX);//初始化外部内存池
my_mem_init(SRAMCCM);//初始化CCM内存池
LED_Init(); //初始化LED端口
LCD_Init(); //初始化LCD
KEY_Init(); //初始化按键
RNG_Init(); //初始化随机数发生器
BEEP_Init(); //初始化蜂鸣器
SNAKE_Init();
Game_Start();
Game_End();
while(KEY_Scan(0)!= WKUP_PRES);//死亡后按下按键重新开始游戏
goto START;
}
2.包含头文件(snake.h)
此头文件主要是引入项目包含源文件的头文件,以及贪吃蛇行进方向定义,蛇体数据结构定义,函数声明。
代码如下:
#ifndef SNAKE__H
#define SNAKE__H
#include "sys.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "flash.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "math.h"
#include "rng.h"
#include "beep.h"
#include "bmp.h"
#include "malloc.h"
#include "sram.h"
enum POS{//行进方向
LEFT=1,
RIGHT,
UP,
DOWN
};
//蛇结构体
typedef struct SnakeNode{
int x;//节点坐标x
int y;//节点坐标y
u16 color;//节点颜色
struct SnakeNode *next,*prev;//结构采用双向链表,表头的前节点指向表尾
}SNAKE_t,*SNAKELIST;
void Game_Start(void);
void SNAKE_Init(void);
void Game_End(void);
#endif
3.SNAKE_Init()函数;
初始化,本函数主要是对游戏界面进行绘制,以及蛇的数据结构初始化。这里初始化蛇的初始长度为2。
代码如下:
void SNAKE_Init(void)
{
int i=0;
SNAKE_t *p;
POINT_COLOR = BLUE;
score=max_score=0;
//STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)&max_score,1);
STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)&max_score,1);//从flash中读出最大成绩
printf("max_score :%d\r\n",max_score);
//GUI 图形界面绘制
LCD_DrawBMP(20,0,logo1);//在LCD屏幕上画logo图标
LCD_DrawBMP(120,0,logo);
LCD_DrawRectangle(290-2,40-2,480-10,40+30);
LCD_ShowString(290,40,190,24,24,"Score: 0");
LCD_DrawRectangle(290-2,40+32-2,480-10,40+30+32);
LCD_ShowString(290,40+32,190,24,24,"Max_s: 0");//显示最大成绩
LCD_ShowNum(290+6*12,40+32,max_score,5,24);
LCD_DrawLine(2,up_y,480-2,up_y);
POINT_COLOR = RED;
LCD_DrawRectangle(2,up_y+2,480-2,800-2);
LCD_DrawRectangle(3,up_y+3,480-3,800-3);
POINT_COLOR=GREEN;
// Head=pvPortMalloc(sizeof(SNAKE_t));//freeRTOS提供的空间分配函数,这里不使用
Head=mymalloc(SRAMEX,sizeof(SNAKE_t));//分配空间
//头部初始化
Head->x=140;
Head->y=up_y+40;
Head->next=NULL;
Head->prev=Head;
Head->color=RED;
p=Head;
score++;
for(i=1;i<2;i++)
{
// SNAKE_t *node=pvPortMalloc(sizeof(SNAKE_t));
SNAKE_t *node=mymalloc(SRAMEX,sizeof(SNAKE_t));
node->x=140;
node->y=up_y+40;
node->prev=p;
node->next=NULL;
node->color=lcd_discolor[RNG_Get_RandomRange(0,12)];
p->next=node;
p=p->next;
Head->prev=p;
score++;
}
CreatFood();//创建一个实物
p=Head;
while(p!=NULL)
{
LCD_DrawNode(*p);
p=p->next;
}
LCD_ShowNum(290+6*12,40,score,5,24);//更新成绩
//while(1);
}
4.CreatFood()函数;
创建食物,在SNAKE_Init()函数里边调用了一个CreatFood()函数,这个函数很简单,就是利用随机数发生器产生三个随机数,分别是坐标x,坐标y和节点颜色,然后调用绘制节点函数LCD_DrawNode();绘制出节点。
代码如下:
void CreatFood(void)
{
u8 col=RNG_Get_RandomRange(0,11);
food.x=RNG_Get_RandomRange(13,469);
food.y=RNG_Get_RandomRange(up_y+5,789);
food.color=lcd_discolor[col];
printf("food : %d %d\r\n",food.x,food.y);
LCD_DrawNode(food);
}
5.LCD_DrawNode()函数;
在CreatFood()函数里边调用了一个CreatFood()函数,这个函数首先对其颜色进行判断,如果为红色,则表示此节点为蛇头,蛇头放大1.5倍,然后循环绘制出节点。声明:红色在随机颜色表里边不存在。
代码如下:
void LCD_DrawNode(SNAKE_t snake)
{
int i;
float j=1;
if(snake.color==RED)j=1.5;//如果是蛇头,节点放大1.5倍
POINT_COLOR=snake.color;
for(i=0;i<5*j;i++)
{
LCD_Draw_Circle(snake.x,snake.y,i);
}
}
6.Game_Start()函数;
项目难点核心部分,重点是对指针的处理。指针是C语言最难理解的一部分,若看不懂也没关系,画个指针操作草图理解一下。本项目用双向链表数据结构存储贪吃蛇信息,其中蛇头的前节点指向蛇尾。
代码如下:
void Game_Start(void){
u8 key=0;//按键捕获值
float dis;//蛇头中心点与食物中心点之间的距离,用于判断是否吃到食物
SNAKE_t *h=Head,*n=Head->prev,*newNode;
while(1)
{
key=KEY_Scan(0);
h=Head;
//绘制蛇身
while(h!=NULL){
LCD_ClearNode(*h);
h=h->next;
}
h=Head;
if(key!=0)
{
h=Head;//蛇头
n=Head->prev;//蛇尾
//蛇身向前移动
while(n!=h){
n->x=n->prev->x;
n->y=n->prev->y;
n=n->prev;
}
switch(key)
{
//左
case KEY2_PRES:
//不能向反方向180度转
if(SNAKE_POS!=RIGHT){
SNAKE_POS=LEFT;
h->x -=10;
}
break;
//右
case KEY0_PRES:
if(SNAKE_POS!=LEFT){
SNAKE_POS=RIGHT;
h->x += 10;
}
break;
//上
case WKUP_PRES:
if(SNAKE_POS!=DOWN){
SNAKE_POS=UP;
h->y -= 10;
}
break;
//下
case KEY1_PRES:
if(SNAKE_POS!=UP){
SNAKE_POS=DOWN;
h->y += 10;
}
break;
}
}
SNAKE_Move();
//计算蛇头中心点和食物中心点坐标之间的距离
dis=sqrt((h->x - food.x)*(h->x - food.x)+(h->y - food.y)*(h->y - food.y));
if(dis<2*5){//吃到食物,添加节点
//newNode=pvPortMalloc(sizeof(SNAKE_t));//freeRTOS操作系统自带的空间分配函数,本实验未用到freertos
newNode=mymalloc(SRAMEX,sizeof(SNAKE_t));//空间分配
n=Head->prev;
newNode->x=n->x;
newNode->y=n->y+10;
newNode->prev=n;
newNode->next=NULL;
newNode->color=food.color;
n->next=newNode;
n=n->next;
h->prev=n;
// BEEP=1;//这里可以打开,吃到食物蜂鸣器鸣一声
// delay_ms(10);
// BEEP=0;
//Head=h;
score++;
LCD_ClearNode(food);//清楚节点
CreatFood();//创建食物
}
// printf("food : %d %d\r\n",food.x,food.y);
//显示分数
LCD_ShowNum(290+6*12,40,score,5,24);//更新分数值
//判断是否到达边界,到边界游戏结束
if(h->x<6 || h->x>474 || h->y<up_y+12 || h->y>794){//判断蛇头是否到达边界,若出界则游戏结束
return;
}
delay_ms(80);
}
}
7.SNAKE_Move()函数;
蛇移动处理函数,SNAKE_POS变量记录蛇行进方向,周期时间内蛇身向行进方向移动一个单位。
代码如下:
void SNAKE_Move()
{
SNAKE_t *h=Head,*n=Head->prev;
h=Head;
n=Head->prev;
h=Head;
POINT_COLOR=RED;
//LCD_DrawRectangle(2,up_y+2,480-2,800-2);
LCD_DrawRectangle(3,up_y+3,480-3,800-3);
//蛇身向前移动
while(n!=h){
n->x=n->prev->x;
n->y=n->prev->y;
n=n->prev;
}
switch(SNAKE_POS)
{
case LEFT:
h->x -=10;
break;
case RIGHT:
h->x += 10;
break;
case UP:
h->y -= 10;
break;
case DOWN:
h->y += 10;
break;
}
h=Head;
//LCD_Fill(6,up_y+6,480-6,800-6,WHITE);
LCD_DrawNode(food);//画食物
while(h!=NULL){
LCD_DrawNode(*h);
h=h->next;
}
}
8.Game_End()函数;
游戏结束,绘制游戏结束界面。
代码如下:
void Game_End(void)
{
LCD_Fill(0,up_y,480-1,800-1,WHITE);
POINT_COLOR=BRRED;
LCD_DrawBMP(150,300,over);
POINT_COLOR=BLUE;
if(score>max_score){//更新最高分
STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)&score,1);//将最高分写入flash中
}
LCD_ShowString(220,700,200,48,24,"Press the up key to continue");
}
总结
本文简单介绍了基于stm32f407的贪吃蛇小游戏,对于其他型号的芯片可参考其中的算法自行移植,希望可以帮助到各位志同道合的朋友,嵌入式这个坑,要一脚踩到底。需要源码的朋友,请自行下载。
源码链接
项目名称:贪吃蛇小游戏
单片机:stm32f407 正点原子-探索者
版权声明:本文为CSDN博主「博创客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/DreamerPerple/article/details/122167623
基于单片机stm32f407的单机小游戏----贪吃蛇小游戏
1.介绍
这是我花一个星期完成的一个简单地单机贪吃蛇小游戏项目,芯片是stm32f407,项目是基于正点原子-探索者开发板完成的,有需要的伙伴可以看看,其他开发板也区别不大,主要看算法。
一、运行效果
- 运行效果图
开始游戏
二、软件设计
1.主程序main.c
main.c中,首先对系统的一些初始化,初始化完后开始游戏,游戏结束后按下按键up键,重新开始游戏。用到硬件有:led,lcd,按键,硬件随机数发生器,蜂鸣器(可选),串口,外部SRAM,flash(存放最高分)。
代码如下:
#include "snake.h"
int main(void)
{
START:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口
FSMC_SRAM_Init();//外部SRAM初始化
my_mem_init(SRAMIN);//初始化内部内存池
my_mem_init(SRAMEX);//初始化外部内存池
my_mem_init(SRAMCCM);//初始化CCM内存池
LED_Init(); //初始化LED端口
LCD_Init(); //初始化LCD
KEY_Init(); //初始化按键
RNG_Init(); //初始化随机数发生器
BEEP_Init(); //初始化蜂鸣器
SNAKE_Init();
Game_Start();
Game_End();
while(KEY_Scan(0)!= WKUP_PRES);//死亡后按下按键重新开始游戏
goto START;
}
2.包含头文件(snake.h)
此头文件主要是引入项目包含源文件的头文件,以及贪吃蛇行进方向定义,蛇体数据结构定义,函数声明。
代码如下:
#ifndef SNAKE__H
#define SNAKE__H
#include "sys.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "flash.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "math.h"
#include "rng.h"
#include "beep.h"
#include "bmp.h"
#include "malloc.h"
#include "sram.h"
enum POS{//行进方向
LEFT=1,
RIGHT,
UP,
DOWN
};
//蛇结构体
typedef struct SnakeNode{
int x;//节点坐标x
int y;//节点坐标y
u16 color;//节点颜色
struct SnakeNode *next,*prev;//结构采用双向链表,表头的前节点指向表尾
}SNAKE_t,*SNAKELIST;
void Game_Start(void);
void SNAKE_Init(void);
void Game_End(void);
#endif
3.SNAKE_Init()函数;
初始化,本函数主要是对游戏界面进行绘制,以及蛇的数据结构初始化。这里初始化蛇的初始长度为2。
代码如下:
void SNAKE_Init(void)
{
int i=0;
SNAKE_t *p;
POINT_COLOR = BLUE;
score=max_score=0;
//STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)&max_score,1);
STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)&max_score,1);//从flash中读出最大成绩
printf("max_score :%d\r\n",max_score);
//GUI 图形界面绘制
LCD_DrawBMP(20,0,logo1);//在LCD屏幕上画logo图标
LCD_DrawBMP(120,0,logo);
LCD_DrawRectangle(290-2,40-2,480-10,40+30);
LCD_ShowString(290,40,190,24,24,"Score: 0");
LCD_DrawRectangle(290-2,40+32-2,480-10,40+30+32);
LCD_ShowString(290,40+32,190,24,24,"Max_s: 0");//显示最大成绩
LCD_ShowNum(290+6*12,40+32,max_score,5,24);
LCD_DrawLine(2,up_y,480-2,up_y);
POINT_COLOR = RED;
LCD_DrawRectangle(2,up_y+2,480-2,800-2);
LCD_DrawRectangle(3,up_y+3,480-3,800-3);
POINT_COLOR=GREEN;
// Head=pvPortMalloc(sizeof(SNAKE_t));//freeRTOS提供的空间分配函数,这里不使用
Head=mymalloc(SRAMEX,sizeof(SNAKE_t));//分配空间
//头部初始化
Head->x=140;
Head->y=up_y+40;
Head->next=NULL;
Head->prev=Head;
Head->color=RED;
p=Head;
score++;
for(i=1;i<2;i++)
{
// SNAKE_t *node=pvPortMalloc(sizeof(SNAKE_t));
SNAKE_t *node=mymalloc(SRAMEX,sizeof(SNAKE_t));
node->x=140;
node->y=up_y+40;
node->prev=p;
node->next=NULL;
node->color=lcd_discolor[RNG_Get_RandomRange(0,12)];
p->next=node;
p=p->next;
Head->prev=p;
score++;
}
CreatFood();//创建一个实物
p=Head;
while(p!=NULL)
{
LCD_DrawNode(*p);
p=p->next;
}
LCD_ShowNum(290+6*12,40,score,5,24);//更新成绩
//while(1);
}
4.CreatFood()函数;
创建食物,在SNAKE_Init()函数里边调用了一个CreatFood()函数,这个函数很简单,就是利用随机数发生器产生三个随机数,分别是坐标x,坐标y和节点颜色,然后调用绘制节点函数LCD_DrawNode();绘制出节点。
代码如下:
void CreatFood(void)
{
u8 col=RNG_Get_RandomRange(0,11);
food.x=RNG_Get_RandomRange(13,469);
food.y=RNG_Get_RandomRange(up_y+5,789);
food.color=lcd_discolor[col];
printf("food : %d %d\r\n",food.x,food.y);
LCD_DrawNode(food);
}
5.LCD_DrawNode()函数;
在CreatFood()函数里边调用了一个CreatFood()函数,这个函数首先对其颜色进行判断,如果为红色,则表示此节点为蛇头,蛇头放大1.5倍,然后循环绘制出节点。声明:红色在随机颜色表里边不存在。
代码如下:
void LCD_DrawNode(SNAKE_t snake)
{
int i;
float j=1;
if(snake.color==RED)j=1.5;//如果是蛇头,节点放大1.5倍
POINT_COLOR=snake.color;
for(i=0;i<5*j;i++)
{
LCD_Draw_Circle(snake.x,snake.y,i);
}
}
6.Game_Start()函数;
项目难点核心部分,重点是对指针的处理。指针是C语言最难理解的一部分,若看不懂也没关系,画个指针操作草图理解一下。本项目用双向链表数据结构存储贪吃蛇信息,其中蛇头的前节点指向蛇尾。
代码如下:
void Game_Start(void){
u8 key=0;//按键捕获值
float dis;//蛇头中心点与食物中心点之间的距离,用于判断是否吃到食物
SNAKE_t *h=Head,*n=Head->prev,*newNode;
while(1)
{
key=KEY_Scan(0);
h=Head;
//绘制蛇身
while(h!=NULL){
LCD_ClearNode(*h);
h=h->next;
}
h=Head;
if(key!=0)
{
h=Head;//蛇头
n=Head->prev;//蛇尾
//蛇身向前移动
while(n!=h){
n->x=n->prev->x;
n->y=n->prev->y;
n=n->prev;
}
switch(key)
{
//左
case KEY2_PRES:
//不能向反方向180度转
if(SNAKE_POS!=RIGHT){
SNAKE_POS=LEFT;
h->x -=10;
}
break;
//右
case KEY0_PRES:
if(SNAKE_POS!=LEFT){
SNAKE_POS=RIGHT;
h->x += 10;
}
break;
//上
case WKUP_PRES:
if(SNAKE_POS!=DOWN){
SNAKE_POS=UP;
h->y -= 10;
}
break;
//下
case KEY1_PRES:
if(SNAKE_POS!=UP){
SNAKE_POS=DOWN;
h->y += 10;
}
break;
}
}
SNAKE_Move();
//计算蛇头中心点和食物中心点坐标之间的距离
dis=sqrt((h->x - food.x)*(h->x - food.x)+(h->y - food.y)*(h->y - food.y));
if(dis<2*5){//吃到食物,添加节点
//newNode=pvPortMalloc(sizeof(SNAKE_t));//freeRTOS操作系统自带的空间分配函数,本实验未用到freertos
newNode=mymalloc(SRAMEX,sizeof(SNAKE_t));//空间分配
n=Head->prev;
newNode->x=n->x;
newNode->y=n->y+10;
newNode->prev=n;
newNode->next=NULL;
newNode->color=food.color;
n->next=newNode;
n=n->next;
h->prev=n;
// BEEP=1;//这里可以打开,吃到食物蜂鸣器鸣一声
// delay_ms(10);
// BEEP=0;
//Head=h;
score++;
LCD_ClearNode(food);//清楚节点
CreatFood();//创建食物
}
// printf("food : %d %d\r\n",food.x,food.y);
//显示分数
LCD_ShowNum(290+6*12,40,score,5,24);//更新分数值
//判断是否到达边界,到边界游戏结束
if(h->x<6 || h->x>474 || h->y<up_y+12 || h->y>794){//判断蛇头是否到达边界,若出界则游戏结束
return;
}
delay_ms(80);
}
}
7.SNAKE_Move()函数;
蛇移动处理函数,SNAKE_POS变量记录蛇行进方向,周期时间内蛇身向行进方向移动一个单位。
代码如下:
void SNAKE_Move()
{
SNAKE_t *h=Head,*n=Head->prev;
h=Head;
n=Head->prev;
h=Head;
POINT_COLOR=RED;
//LCD_DrawRectangle(2,up_y+2,480-2,800-2);
LCD_DrawRectangle(3,up_y+3,480-3,800-3);
//蛇身向前移动
while(n!=h){
n->x=n->prev->x;
n->y=n->prev->y;
n=n->prev;
}
switch(SNAKE_POS)
{
case LEFT:
h->x -=10;
break;
case RIGHT:
h->x += 10;
break;
case UP:
h->y -= 10;
break;
case DOWN:
h->y += 10;
break;
}
h=Head;
//LCD_Fill(6,up_y+6,480-6,800-6,WHITE);
LCD_DrawNode(food);//画食物
while(h!=NULL){
LCD_DrawNode(*h);
h=h->next;
}
}
8.Game_End()函数;
游戏结束,绘制游戏结束界面。
代码如下:
void Game_End(void)
{
LCD_Fill(0,up_y,480-1,800-1,WHITE);
POINT_COLOR=BRRED;
LCD_DrawBMP(150,300,over);
POINT_COLOR=BLUE;
if(score>max_score){//更新最高分
STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)&score,1);//将最高分写入flash中
}
LCD_ShowString(220,700,200,48,24,"Press the up key to continue");
}
总结
本文简单介绍了基于stm32f407的贪吃蛇小游戏,对于其他型号的芯片可参考其中的算法自行移植,希望可以帮助到各位志同道合的朋友,嵌入式这个坑,要一脚踩到底。需要源码的朋友,请自行下载。
源码链接
项目名称:贪吃蛇小游戏
单片机:stm32f407 正点原子-探索者
版权声明:本文为CSDN博主「博创客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/DreamerPerple/article/details/122167623
暂无评论