学习嵌入式已经有两年多了,现在准备工作了,也已经从51单片机过度到ARM的STM32单片机,就想结合自己所学的东西做一个东西出来,于是就做了这个贪吃蛇游戏。
本贪吃蛇游戏是的硬件CPU是STM32F103C8T6、显示液晶用的是诺基亚Nokia5510的屏幕、按键、电源稳压模块。
为什么选择STM32,因为STM32的主频时钟高达72M,说白了就是速度快,内部资源丰富和大容量的flash和动态内存。液晶不选用LCD12864,本人自己认为那个蓝光屏幕看久了会眼花而且还有点笨重(纯属个人意见)。
怎么在程序上实现贪吃蛇游戏设计呢,在这里感谢网上的个位大佬,核心程序基本上是借鉴的过来了。核心程序解决了,怎么显示在液晶上了,第一首先写一个画点函数,就是输入坐标就可以在对应的坐标点亮。nokia5510是84*48的像素点屏幕。其他的按键驱动函数就不在描述了。主要是本作者的表达能力不是很好,不在啰嗦了,直接上程序吧!
制作出来的贪吃蛇实物图如下:
运行结果(为了防腐蚀涂上了绿油)
焊接好STM32最小系统
实物
下面链接是演示视频:
https://v.youku.com/v_show/id_XNDEzNTI4ODk0NA==.html
Altium Designer画的PCB图如下:(51hei附件中可下载工程文件)
STM32单片机源程序如下:
- #include "lcd_5510.h"
- #include "Snake_Game.h"
- #define ElemType int
-
- typedef struct node
- {
- ElemType x,y;
- struct node *prior;
- struct node *next;
- } Node;
- Food food; //全局变量//
- int add=10; //总得分与每次吃食物得分//蛇长度计数;。
- u8 sleeptime=200; //每次运行的时间间隔
- Snake snake;
- Node *Head; //Node*food;//蛇头指针,食物指针
- u8 endgamestatus=0; //游戏结束的情况,1:撞到墙;2:咬到自己;3:主动退出游戏。
- //按键判断
- Fuct KEY_Test(void)
- {
- Fuct sta=Null;
- if(UP_ON) sta = Up;
- if(Down_ON) sta = Down;
- if(Left_ON) sta = Left;
- if(Right_ON) sta = Right;
- if(MODE_ON) sta = Puase;
- if(RTN_ON) sta = Rtn;
- return sta;
- }
- // 新建节点。成功,返回节点指针;否则,返回NULL。
- static Node* CreateNode()
- {
- Node *newNode = NULL;
- newNode = (Node*)malloc(sizeof(Node));
- if (newNode == NULL)
- return NULL;
- // 初始化新建节点前置节点和后置节点都是自己
- newNode->prior = newNode->next = newNode;
- return newNode;
- }
- // 创建表头 成功,返回0;否则,返回-1。
- int Link_Create()
- {
- Head = CreateNode();
- if (Head == NULL)
- return -1;
- return 0;
- }
- // 表头插入数据
- Node * Link_InsertFirst(Node*head)
- {
- Node *newNode = CreateNode();
- if (newNode == NULL)
- return NULL;
- newNode->next = head->next;
- newNode->prior = head;
- head->next->prior = newNode;
- head->next = newNode;
- return newNode;
- }
- //删除表尾数据
- Node* Link_DeleteLast(Node*head)
- {
- Node *current = head->prior;
- current->next->prior = current->prior;
- current->prior->next = current->next;
- return current;
- }
- //销毁双向循环链表L:
- void DestroyList(Node* head)
- {
- Node* q,*p=head->next; /* p指向第一个结点 */
- while(p!=head) /* p没到表头 */
- {
- q=p->next;
- free(p);
- p=q;
- }
- free(head);
- head=NULL;
- }
- /*=========显示蛇身===========*/
- void LCD_DrawPoint_Snake(Node *head)
- {
- Node *current=head->next;
- while(current!=head)//从头到为,输出蛇身
- {
- LCD_DrawPoint(current->x,current->y,ON);
- current=current->next;
- }
- }
- /*=========判断是否撞墙=============*/
- void cantcrosswall(Node*head)//不能穿墙
- {
- Node *current = head->next;
- if(current->x<=min_width ||current->x>=frame_width-1 ||current->y>=frame_height-1 || current->y<=min_height)
- {
- endgamestatus=1;//游戏结束的情况。3种情况
- }
- }
- /*=========判断是否咬到了自己=============*/
- void biteself(Node*head)//
- {
- Node *current=head->next;
- Node *self=current->next;
- while(self!=head)
- {
- if(self->x==current->x && self->y==current->y)
- {
- endgamestatus=2;
- }
- self=self->next;
- }
- }
- u8 is_alive(Node*head)//判断是否存活
- {
- biteself(head);//判断是否咬到自己
- cantcrosswall(head);//判断是否到边界
- return endgamestatus;
- }
- /*=========判断是否吃到食物=============*/
- FlagStatus judgeCoordInFoods(Food *foods, Node *spot)
- {
- Node * nextHead=spot->next;
- if(nextHead->x>=foods->X[0])//如果蛇头在食物坐标范围内
- if(nextHead->x<=foods->X[3])
- if(nextHead->y>=foods->Y[0])
- if(nextHead->y<=foods->Y[3])
- return SET;//返回吃的食物
- return RESET;//没吃的到
- }
- void DrawFood(Food *foods,u8 state)//画出食物
- {
- for(int i=0; i<Food_Size; i++)
- {
- LCD_DrawPoint(foods->X[i], foods->Y[i],state);//显示食物
- }
- }
- /*========产生随机食物=====*/
- void Gave_Food(Food *foods)
- {
- do
- {
- foods->X[0]=(rand() % (77))+ 5; //产生食物的范围
- foods->Y[0]=(rand() % (41))+ 5;//(x-y)Y最大值 +z 最小值
- }
- while(!((foods->X[0]>5)&&(foods->X[0]<80)&&(foods->Y[0]<40)&&(foods->Y[0]>9))); //判断是否在范围内
- foods->X[1] = foods->X[0] + 1;
- foods->X[2] = foods->X[0];
- foods->X[3] = foods->X[0] + 1;
- foods->Y[1] = foods->Y[0] ;
- foods->Y[2] = foods->Y[0] + 1;
- foods->Y[3] = foods->Y[0] + 1;
- DrawFood(foods,ON);
- }
- /*=======吃到食物处理=======*/
- void update_food() //吃到食物处理
- {
- static u16 time=0;
- Node * nextHead=Head->next;
- time++;
- if(judgeCoordInFoods(&food,Head))//吃到食物
- {
- time=0;//食物更新时间清0
- snake.len++;//蛇身长度+1
- DrawFood(&food,OFF);//清除当前食物
- Gave_Food(&food);//获取新食物
- snake.scroe+=((snake.len+10)/10);//分数
-
- LCD_ShowNum(10,0,snake.len,3); //显示长度
- LCD_ShowNum(3,0,snake.scroe/100,3); //显示
- LCD_ShowNum(3,0,snake.scroe%100,3); //显示
- LCD_DrawPoint(nextHead->x,nextHead->y,ON); //显示蛇头
- }
- else
- {
- nextHead=Link_DeleteLast(Head); //删除蛇最后一个元素
- LCD_DrawPoint(nextHead->x,nextHead->y,OFF);//关掉蛇尾最后一个像素点
- free(nextHead);//释放最后一个链表
- }
- if(time>100)//如果跟新时间到达之前没有吃到食物
- {
- time=0;//更新食物
- DrawFood(&food,OFF);//关掉食物
- Gave_Food(&food);//获取新食物
- }
- }
- /*=========游戏暂停==========*/
- void pause()
- {
- // Disp_CZhuitu(6,8,2,10,Pause_char);
- while(1)
- {
- // delay_ms(300);
- if(MODE_ON)
- break;
- }
- // Disp_CZhuitu(6,8,2,10,jie_char);
- }
- /*=========控制游戏==========*/
- void gamecircle()//控制游戏
- {
- Fuct Sta=KEY_Test();
- if(Sta==Up&& snake.dir!=Down)//如果上按键按下 且蛇运动方向不为下
- {
- snake.dir=Up;//蛇方向为上
- }
- else if(Sta==Down&& snake.dir!=Up)
- {
- snake.dir=Down;
- }
- else if(Sta==Left&& snake.dir!=Right)
- {
- snake.dir=Left;
- }
- else if( Sta==Right&& snake.dir!=Left)
- {
- snake.dir=Right;
- }
- else if(Sta==Puase)//如果暂停键按下
- {
- pause();
- }
- else if(Sta==Rtn)
- {
- endgamestatus=3;
- }
- }
- /*=========蛇移动==========*/
- void move_snake()//蛇前进,上U,下D,左L,右R
- {
- Node*nextHead;
- Node * currot=Head->next;
- nextHead=Link_InsertFirst(Head);//在蛇头添加一个元素
- switch(snake.dir)
- {
- case Up:
- nextHead->x=currot->x;
- nextHead->y=currot->y-1;
- break;
- case Down:
- nextHead->x=currot->x;
- nextHead->y=currot->y+1;
- break;
- case Left:
- nextHead->x=currot->x-1;
- nextHead->y=currot->y;
- break;
- case Right:
- nextHead->x=currot->x+1;
- nextHead->y=currot->y;
- break;
- }
- LCD_DrawPoint(nextHead->x,nextHead->y,ON);//显示添加的元素
- }
- //显示游戏界面
- void game_ucos()
- {
- LCD_prints_68(0, 0, "SC:");
- LCD_prints_68(7, 0,"Ln:");
- LCD_DrawLine(0,8,83,8);
- LCD_DrawLine(0,8,0,47);
- LCD_DrawLine(0,47,83,47);
- LCD_DrawLine(83,47,83,8);
- }
- /*=========初始化游戏===========*/
- void init_snake(u8 grade)
- {
- int i;
- Node *list=NULL;
- if(grade==2)
- snake.speed=120;
- else if(grade==3)
- snake.speed=70;
- else if(grade==4)
- snake.speed=40;
- //=============蛇初始化==============//
- snake.dir=Right;
- endgamestatus=0;
- snake.len=10;
- Link_Create();
- for(i=0; i<snake.len; i++)
- {
- list=Link_InsertFirst(Head);
- list->x=frame_width/2+i;
- list->y=frame_height/2;
- }
- LCD_DrawPoint_Snake(Head);
- //=============界面初始化==============//
- snake.scroe=0;
-
- LCD_ShowNum(10,0,snake.len,3); //显示长度
- LCD_ShowNum(3,0,snake.scroe%1000,3); //显示分数
- LCD_ShowNum(3,0,snake.scroe/100,3); //显示分数
- LCD_ShowNum(3,0,snake.scroe%100,3); //显示分数
- Gave_Food(&food);
- }
- void remove_snake(Node *head)
- {
- Node *current=head->next;
- while(current!=head)//从头到为,输出蛇身
- {
- LCD_DrawPoint(current->x,current->y,OFF);
- current=current->next;
- }
- }
- int Play(u8 grade)
- {
- init_snake(grade);
- game_ucos();
- while(1)
- {
- gamecircle(); //游戏控制
- move_snake(); //移动蛇身
- update_food(); //是否产生食物
- delay_ms(snake.speed); //移动速度snake.speed
- if(is_alive(Head)) //蛇的死活(撞墙或自食)
- {
- DestroyList(Head);
- DrawFood(&food,OFF);//清除当前食物
- LCD_Clear_Cache();
- while(KEY_Test()==0);
- RLCD_vertical_vrintch(game_icon);
- LCD_clr_scr();
- interface();
- return 0;
- }
- }
- }
- //进入难度选择
- void Start_game()
- {
- int key,num=2;
- interface();
- while(1)
- {
- LCD_prints_68(3, 0,"Difficult");
- LCD_ShowNum(5,2,1,1); //显示分数
- LCD_ShowNum(5,3,2,1); //显示分数
- LCD_ShowNum(5,4,3,1); //显示分数
- LCD_printc_68(3, num, '>');
-
- key=KEY_Test();
- switch (key)
- {
- case Up:
- LCD_printc_68(3, num, ' ');
- num ++;
- if(num >=5) num =2;
- LCD_printc_68(3, num, '>');
- delay_ms(100) ;break ;
- case Down:
- LCD_printc_68(3, num, ' ');
- num --;
- if(num <=1) num =4;
- LCD_printc_68(3, num, '>');
- delay_ms(100);break ;
- case Puase:
- LCD_clr_scr();
- Play(num);break ;
-
- default : break;
- }
- }
- }
复制代码
附件有源程序和PCB文件
全部资料51hei下载地址:
nokia5510.zip
(1.5 MB, 下载次数: 73)
|