找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6640|回復(fù): 6
打印 上一主題 下一主題
收起左側(cè)

STM32F103ZET6貪吃蛇游戲程序設(shè)計

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:462746 發(fā)表于 2019-1-5 21:47 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
基于STM32F103的貪吃蛇

單片機源程序如下:
  1. ///***************************************************
  2. //程序名:貪吃蛇
  3. //平臺:STM32F103ZET6精英版
  4. //
  5. //程序功能:貪吃蛇游戲,吃到食物后,速度增加,長度變長,咬到自己游戲結(jié)束,復(fù)位重新開始
  6. //
  7. //程序調(diào)用:自制手柄按鍵,AD產(chǎn)生隨機數(shù),正點原子4.3寸屏幕,FreeRTOS操作系統(tǒng)
  8. //
  9. //設(shè)計思路:創(chuàng)建若干任務(wù),按鍵任務(wù)控制蛇方向,顯示任務(wù)控制屏幕的顯示與坐標更新,事件任務(wù)為數(shù)據(jù)處理任務(wù),并控制著其他任務(wù)能否運行
  10. //
  11. //知識準備:AD采樣,GPIO設(shè)置,FreeRTOS創(chuàng)建任務(wù)與掛起
  12. //
  13. //注意:屏幕被裁剪成4.3寸版本,其它屏幕請修改為原程序
  14. //
  15. ///****************************************************

  16. //系統(tǒng)文件
  17. #include "sys.h"
  18. #include "delay.h"
  19. #include "usart.h"
  20. #include "stdio.h"
  21. #include "stdlib.h"
  22. #include "math.h"
  23. //內(nèi)部驅(qū)動
  24. #include "rand.h"
  25. //外圍電路
  26. #include "led.h"
  27. #include "key.h"
  28. #include "lcd_4_3.h"
  29. //用戶算法
  30. #include "my_task.h"

  31. #define GAME_WIDTH        480        //設(shè)置屏幕分辨率為800*480,為了維持正方形,分成80*48等分
  32. #define GAME_HEIGHT        800
  33. #define GAME_XPART  48
  34. #define GAME_YPART  80

  35. enum sta //枚舉狀態(tài)
  36. {
  37.         OFF,//0
  38.         ON        //1
  39. } station;

  40. enum dir //枚舉貪吃蛇方向
  41. {
  42.         UP,                //上
  43.         DOWN,        //下
  44.         LEFT,        //左
  45.         RIGHT        //右
  46. }direction;

  47. typedef struct  //貪吃蛇重要參數(shù)集
  48. {                                                                                    
  49.         u16 speed;                //速度
  50.         u16 length;     //長度
  51.         u16 energybuf;  //能量緩存
  52.         u16 width;      //蛇寬        //未使用
  53.         u16 life;       //生命數(shù)        //未使用
  54.         u16 firstx;     //蛇頭坐標x
  55.         u16 firsty;     //蛇頭坐標y
  56.         u16 lastx;      //蛇尾坐標x
  57.         u16 lasty;      //蛇尾坐標y
  58.         u16 color;      //蛇顏色        //未使用
  59. }snakes;
  60. snakes snake;

  61. void Snake_Init(snakes * snake)//貪吃蛇參數(shù)初始化
  62. {
  63.         snake->speed=5;
  64.         snake->length=10;
  65.         snake->energybuf=0;
  66.         snake->width=1;
  67.         snake->life=3;
  68.         snake->firstx=4;
  69.         snake->firsty=5;
  70.         snake->lastx=0;
  71.         snake->lasty=0;
  72.         snake->color=RED;
  73. }

  74. typedef struct  //食物重要參數(shù)集
  75. {                                                                                    
  76.         u16  energy ;//食物能量
  77.         u16  x ;        //食物坐標x
  78.         u16  y ;        //食物坐標y
  79. }apples;
  80. apples apple;

  81. void Apple_Init(apples * apple)//食物參數(shù)初始化
  82. {
  83.         apple->energy=1;
  84. //        apple->x=24;        //坐標由隨機數(shù)計算出來
  85. //        apple->y=40;
  86. }

  87. typedef struct  //事件重要參數(shù)集
  88. {                                                                                    
  89.         u16  Process ;//是否游戲暫停
  90.         u16  GameSta ;//是否游戲結(jié)束
  91.         u16  AppleSta;//食物狀態(tài)
  92.         u16  Direction;//蛇前進方向
  93. }events;
  94. events event;

  95. void Event_Init(events * event)//事件參數(shù)初始化
  96. {
  97.         event->Process=ON;
  98.         event->GameSta=ON;
  99.         event->AppleSta=ON;
  100.         event->Direction=DOWN;//初始方向向下
  101. }
  102. typedef struct  //貪吃蛇坐標參數(shù)
  103. {
  104.         u16 x;
  105.         u16 y;
  106. }axiss;
  107. axiss snake_axis[100];  //設(shè)蛇身最大長度可以達到100

  108. void Display(u16 x,u16 y,u16 color)//按照80*48的坐標映射到800*480的屏幕上
  109. {
  110.         LCD_Fill(GAME_WIDTH/GAME_XPART*x,GAME_HEIGHT/GAME_YPART*y,GAME_WIDTH/GAME_XPART*(x+1),GAME_HEIGHT/GAME_YPART*(y+1),color);
  111. }

  112. void DisplayInit(void) //蛇身初始化,默認在該位置,并蛇頭向下
  113. {
  114.         u16 i;
  115.         for(i=0;i<5;i++)//將初始坐標存入蛇身坐標內(nèi)
  116.         {
  117.                 snake_axis[i].x=i;
  118.                 snake_axis[i].y=0;
  119.         }
  120.                 for(i=5;i<10;i++)
  121.         {
  122.                 snake_axis[i].x=4;
  123.                 snake_axis[i].y=i-4;
  124.         }
  125.         LCD_Clear(WHITE);
  126.         for(i=0;i<10;i++)
  127.         {
  128.                 Display(snake_axis[i].x,snake_axis[i].y,RED);//按照初始坐標打印出蛇身
  129.         }
  130. }

  131. void GameOver(void)//游戲結(jié)束函數(shù),打印"GAME OVER",掛起核心數(shù)據(jù)處理函數(shù)
  132. {
  133.         LCD_ShowString(180,388,200,24,24,"GAME OVER !");
  134.         vTaskSuspend(EVENTTask_Handler);
  135. }

  136. //全局變量//////////////////////////////////////

  137. int main(void)
  138. {         
  139.         delay_init();                     //延時函數(shù)初始化         
  140.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         //設(shè)置NVIC中斷分組2:2位搶占優(yōu)先級,2位響應(yīng)優(yōu)先級
  141.         Rand_Adc_Init();        //隨機數(shù)初始化
  142.          LED_Init();                             //LED端口初始化
  143.         KEY_PLAY_Init();        //按鍵初始化,自制按鍵上/下/左/右/暫停,分別連接PF0/1/2/3/4,低電平接通
  144.         LCD_Init(0);//默認為豎屏模式
  145.         DisplayInit();//打印初始蛇身
  146.         Snake_Init(&snake);//貪吃蛇參數(shù)初始化
  147.         Apple_Init(&apple);//食物參數(shù)初始化
  148.         Event_Init(&event);//事件參數(shù)初始化
  149.         xTaskCreate((TaskFunction_t )start_task,            //任務(wù)函數(shù)
  150.                 (const char*    )"start_task",          //任務(wù)名稱
  151.                 (uint16_t       )START_STK_SIZE,        //任務(wù)堆棧大小
  152.                 (void*          )NULL,                  //傳遞給任務(wù)函數(shù)的參數(shù)
  153.                 (UBaseType_t    )START_TASK_PRIO,       //任務(wù)優(yōu)先級
  154.                 (TaskHandle_t*  )&StartTask_Handler);   //任務(wù)句柄              
  155.     vTaskStartScheduler();          //開啟任務(wù)調(diào)度
  156. }

  157. //開始任務(wù)任務(wù)函數(shù)
  158. void start_task(void *pvParameters)
  159. {
  160.     taskENTER_CRITICAL();           //進入臨界區(qū)
  161.     //創(chuàng)建貪吃蛇任務(wù)
  162.     xTaskCreate((TaskFunction_t )snake_task,            
  163.                 (const char*    )"snake_task",           
  164.                 (uint16_t       )SNAKE_STK_SIZE,
  165.                 (void*          )NULL,                                
  166.                 (UBaseType_t    )SNAKE_TASK_PRIO,        
  167.                 (TaskHandle_t*  )&SNAKETask_Handler);   
  168.     //創(chuàng)建食物任務(wù)
  169.     xTaskCreate((TaskFunction_t )apple_task,     
  170.                 (const char*    )"apple_task",   
  171.                 (uint16_t       )APPLE_STK_SIZE,
  172.                 (void*          )NULL,
  173.                 (UBaseType_t    )APPLE_TASK_PRIO,
  174.                 (TaskHandle_t*  )&APPLETask_Handler);        
  175.     //創(chuàng)建事件任務(wù)
  176.     xTaskCreate((TaskFunction_t )event_task,     
  177.                 (const char*    )"event_task",   
  178.                 (uint16_t       )EVENT_STK_SIZE,
  179.                 (void*          )NULL,
  180.                 (UBaseType_t    )EVENT_TASK_PRIO,
  181.                 (TaskHandle_t*  )&EVENTTask_Handler);  
  182.         //創(chuàng)建顯示任務(wù)
  183.     xTaskCreate((TaskFunction_t )display_task,     
  184.                 (const char*    )"display_task",   
  185.                 (uint16_t       )DISPLAY_STK_SIZE,
  186.                 (void*          )NULL,
  187.                 (UBaseType_t    )DISPLAY_TASK_PRIO,
  188.                 (TaskHandle_t*  )&DISPLAYTask_Handler);  
  189.         //創(chuàng)建閃爍任務(wù)
  190.     xTaskCreate((TaskFunction_t )led_task,     
  191.                 (const char*    )"led_task",   
  192.                 (uint16_t       )LED_STK_SIZE,
  193.                 (void*          )NULL,
  194.                 (UBaseType_t    )LED_TASK_PRIO,
  195.                 (TaskHandle_t*  )&LEDTask_Handler);  
  196.         //創(chuàng)建輸入任務(wù)
  197.     xTaskCreate((TaskFunction_t )key_task,     
  198.                 (const char*    )"key_task",   
  199.                 (uint16_t       )KEY_STK_SIZE,
  200.                 (void*          )NULL,
  201.                 (UBaseType_t    )KEY_TASK_PRIO,
  202.                 (TaskHandle_t*  )&KEYTask_Handler);  
  203.     vTaskDelete(StartTask_Handler); //刪除開始任務(wù)
  204.     taskEXIT_CRITICAL();            //退出臨界區(qū)
  205. }

  206. //事件任務(wù)函數(shù),核心數(shù)據(jù)處理函數(shù)
  207. void event_task(void *pvParameters)
  208. {
  209.         while(1)
  210.         {
  211.                 if(event.GameSta==ON)//如果游戲正常則繼續(xù)
  212.                 {
  213.                         if(event.Process==ON)//如果沒有暫停則繼續(xù)
  214.                         {
  215.                                 switch(event.Direction)//檢測按鍵情況,根據(jù)方向調(diào)整蛇頭坐標
  216.                                 {
  217.                                         case UP:
  218.                                         {
  219.                                                 snake.firsty-=1;
  220.                                                 if(snake.firsty>GAME_YPART-1)
  221.                                                 {
  222.                                                         snake.firsty=GAME_YPART-1;
  223.                                                 }
  224.                                         }break;
  225.                                         case DOWN:
  226.                                         {
  227.                                                 snake.firsty+=1;
  228.                                                 if(snake.firsty>GAME_YPART-1)
  229.                                                 {
  230.                                                         snake.firsty=0;
  231.                                                 }
  232.                                         }break;
  233.                                         case LEFT:
  234.                                         {
  235.                                                 snake.firstx-=1;
  236.                                                 if(snake.firstx>GAME_XPART-1)
  237.                                                 {
  238.                                                         snake.firstx=GAME_XPART-1;
  239.                                                 }
  240.                                         }break;
  241.                                         case RIGHT:
  242.                                         {
  243.                                                 snake.firstx+=1;
  244.                                                 if(snake.firstx>GAME_XPART-1)
  245.                                                 {
  246.                                                         snake.firstx=0;
  247.                                                 }
  248.                                         }break;
  249.                                 }
  250.                                 snake.lastx=snake_axis[0].x;//保存下蛇尾坐標
  251.                                 snake.lasty=snake_axis[0].y;
  252.                                 if(snake.firstx==apple.x&&snake.firsty==apple.y)//如果此時的坐標與食物坐標相同
  253.                                 {
  254.                                         event.AppleSta=OFF;        //食物被吃掉
  255.                                         snake.energybuf+=apple.energy;//蛇的能量加一
  256.                                         vTaskResume(APPLETask_Handler);        //使能生成食物函數(shù)               
  257.                                 }
  258.                                 vTaskResume(DISPLAYTask_Handler);        //使能顯示函數(shù)                        
  259.                         }
  260.                 }else GameOver();//如果游戲為結(jié)束狀態(tài)則游戲結(jié)束
  261.                 delay_ms(1000/snake.speed);        //按照蛇的速度調(diào)整此核心數(shù)據(jù)處理函數(shù)的時間間隔        
  262.         }
  263. }

  264. //輸入任務(wù)函數(shù),根據(jù)按鍵調(diào)整蛇的方向,數(shù)據(jù)處理函數(shù)之前最后一次按鍵視為有效
  265. void key_task(void *pvParameters)
  266. {
  267.         u8 key;
  268.     while(1)
  269.     {
  270.                 key=KEY_PLAY_Scan(0);//按鍵掃描函數(shù),此處是自制的手柄,上/下/左/右/暫停,分別連接PF0/1/2/3/4,低電平接通
  271.                 switch(key)
  272.                 {
  273.                         case KEY_UP_PRES:
  274.                         {
  275.                                 if(event.Direction!=DOWN)//如果當前方向與按鍵方向相反,則不響應(yīng)
  276.                                 event.Direction=UP;
  277.                         }break;
  278.                         case KEY_DOWN_PRES:
  279.                         {
  280.                                 if(event.Direction!=UP)
  281.                                 event.Direction=DOWN;
  282.                         }break;
  283.                         case KEY_LEFT_PRES:
  284.                         {
  285.                                 if(event.Direction!=RIGHT)
  286.                                 event.Direction=LEFT;
  287.                         }break;
  288.                         case KEY_RIGHT_PRES:
  289.                         {
  290.                                 if(event.Direction!=LEFT)
  291.                                 event.Direction=RIGHT;
  292.                         }break;
  293.                         case KEY_PASS_PRES://按下切換暫停/繼續(xù)狀態(tài)
  294.                         {
  295.                                 event.Process=!event.Process;
  296.                         }break;               
  297.                 }
  298.         delay_ms(20);//每20ms響應(yīng)一次
  299.     }
  300. }

  301. //食物任務(wù)函數(shù),食物被吃掉時觸發(fā)此函數(shù)
  302. void apple_task(void *pvParameters)
  303. {
  304.         u16 flag,i;
  305.     while(1)
  306.     {
  307.                 flag=1;
  308.                 while(flag)//生成新的食物坐標
  309.                 {
  310.                         flag=0;
  311.                         apple.x=Get_Rand()%(u16)(GAME_XPART);
  312.                         apple.y=Get_Rand()%(u16)(GAME_YPART);
  313.                         for(i=0;i<snake.length;i++) //食物坐標不能在蛇身上
  314.                         {
  315.                                 if(snake_axis[i].x==apple.x&&snake_axis[i].y==apple.y)
  316.                                 {
  317.                                         flag++;
  318.                                 }
  319.                         }
  320.                 }
  321.                 Display(apple.x,apple.y,RED);//按照坐標將食物顯示出來
  322.                 vTaskSuspend(APPLETask_Handler);//掛起任務(wù)        
  323.     }
  324. }

  325. //貪吃蛇任務(wù)函數(shù) ,此任務(wù)作廢
  326. void snake_task(void *pvParameters)
  327. {
  328.     while(1)
  329.     {
  330.         //LED0=!LED0;
  331.         delay_ms(500);
  332.     }
  333. }   

  334. //顯示任務(wù)函數(shù),顯示蛇頭,消去蛇尾,并更新蛇的坐標
  335. void display_task(void *pvParameters)
  336. {
  337.         u16 i;
  338.     while(1)
  339.     {
  340.                 Display(snake.firstx,snake.firsty,RED);//顯示蛇頭
  341.         if(snake.energybuf==0) //如果沒有吃到食物
  342.                 {
  343.                         Display(snake.lastx,snake.lasty,WHITE);//消去蛇尾
  344.                         for(i=0;i<snake.length-1;i++)
  345.                         {
  346.                                 snake_axis[i].x=snake_axis[i+1].x;//挨個更新坐標
  347.                                 snake_axis[i].y=snake_axis[i+1].y;
  348.                         }        
  349.                 }else //如果吃到了食物
  350.                 {
  351.                         snake.energybuf--;//能量緩沖區(qū)減一
  352.                         snake.length++; //蛇身加一
  353. //                        if(snake.length%2==0)snake.speed++;
  354.                         snake.speed++; //由于地圖很大,故設(shè)置蛇身加一則速度加一
  355.                 }        
  356.                 snake_axis[snake.length-1].x=snake.firstx;//最新的坐標更新為蛇頭的坐標
  357.                 snake_axis[snake.length-1].y=snake.firsty;
  358.                 for(i=0;i<snake.length-1;i++)//檢查有沒有咬到自己
  359.                 {
  360.                         if(snake_axis[i].x==snake.firstx&&snake_axis[i].y==snake.firsty)
  361.                         {
  362.                                 event.GameSta=OFF; //遍歷蛇身坐標是否與蛇頭坐標相同
  363.                         }
  364.                 }
  365.                 vTaskSuspend(DISPLAYTask_Handler);
  366.     }
  367. }

  368. //閃爍任務(wù)函數(shù),證明程序沒有死機
  369. void led_task(void *pvParameters)
  370. {
  371.     while(1)
  372.     {
  373.         LED0=!LED0;
  374.         delay_ms(500);
  375.     }
  376. }
復(fù)制代碼

所有資料51hei提供下載:
貪吃蛇游戲F1.7z (356.21 KB, 下載次數(shù): 147)



評分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏6 分享淘帖 頂2 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:461502 發(fā)表于 2019-1-15 22:46 來自手機 | 只看該作者
小白求助,我就改主函數(shù)里分辨率的定義   我用stm32戰(zhàn)艦v3
回復(fù)

使用道具 舉報

板凳
ID:461502 發(fā)表于 2019-1-15 22:49 來自手機 | 只看該作者
小白求助,我就改了主函數(shù)分辨率的定義  用stm32戰(zhàn)艦v3不能實現(xiàn)效果   蛇的初始位置什么的,是不是也要自己定義,看不懂代碼
回復(fù)

使用道具 舉報

地板
ID:777709 發(fā)表于 2020-6-14 22:55 | 只看該作者
小白求助,這個需要用到proteus嗎
回復(fù)

使用道具 舉報

5#
ID:1087401 發(fā)表于 2023-7-5 19:14 | 只看該作者
xiaokeai5023 發(fā)表于 2020-6-14 22:55
小白求助,這個需要用到proteus嗎

好像用不到
回復(fù)

使用道具 舉報

6#
ID:1106310 發(fā)表于 2023-12-28 17:41 | 只看該作者
感謝樓主的代碼,但是燒錄之后屏幕沒有反應(yīng),用的是正點原子F103ZET6精英板
回復(fù)

使用道具 舉報

7#
ID:1010295 發(fā)表于 2024-1-4 23:00 | 只看該作者
小白求助,這個需要自己設(shè)計電路嗎
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表