學習嵌入式已經有兩年多了,現在準備工作了,也已經從51單片機過度到ARM的STM32單片機,就想結合自己所學的東西做一個東西出來,于是就做了這個貪吃蛇游戲。
本貪吃蛇游戲是的硬件CPU是STM32F103C8T6、顯示液晶用的是諾基亞Nokia5510的屏幕、按鍵、電源穩壓模塊。
為什么選擇STM32,因為STM32的主頻時鐘高達72M,說白了就是速度快,內部資源豐富和大容量的flash和動態內存。液晶不選用LCD12864,本人自己認為那個藍光屏幕看久了會眼花而且還有點笨重(純屬個人意見)。
怎么在程序上實現貪吃蛇游戲設計呢,在這里感謝網上的個位大佬,核心程序基本上是借鑒的過來了。核心程序解決了,怎么顯示在液晶上了,第一首先寫一個畫點函數,就是輸入坐標就可以在對應的坐標點亮。nokia5510是84*48的像素點屏幕。 其他的按鍵驅動函數就不在描述了。主要是本作者的表達能力不是很好,不在啰嗦了,直接上程序吧!
制作出來的貪吃蛇實物圖如下:
IMG_20190408_144515.jpg (3.53 MB, 下載次數: 89)
下載附件
運行結果(為了防腐蝕涂上了綠油)
2019-4-12 21:53 上傳
IMG_20190327_120851.jpg (3.16 MB, 下載次數: 80)
下載附件
焊接好STM32最小系統
2019-4-12 21:53 上傳
IMG_20190327_131624.jpg (3.19 MB, 下載次數: 94)
下載附件
實物
2019-4-12 21:53 上傳
下面鏈接是演示視頻:
https://v.youku.com/v_show/id_XNDEzNTI4ODk0NA==.html
Altium Designer畫的PCB圖如下:(51hei附件中可下載工程文件)
0.png (39.23 KB, 下載次數: 81)
下載附件
2019-4-12 23:49 上傳
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;
- }
- }
- }
復制代碼
0.png (2.47 KB, 下載次數: 96)
下載附件
2019-4-12 23:49 上傳
附件有源程序和PCB文件
全部資料51hei下載地址:
nokia5510.zip
(1.5 MB, 下載次數: 73)
2019-4-12 22:12 上傳
點擊文件名下載附件
硬件文件 下載積分: 黑幣 -5
基于nolkia5510的貪吃蛇游戲設計.7z
(198.81 KB, 下載次數: 65)
2019-4-12 23:51 上傳
點擊文件名下載附件
基于STM32的程序 下載積分: 黑幣 -5
|