|
用STM32做一個(gè)游戲機(jī)
游戲視頻地址:https://www.bilibili.com/video/BV1i84y1t7ro
制作出來的實(shí)物圖如下:
游戲運(yùn)行圖片如下:
51hei.jpg (293.73 KB, 下載次數(shù): 42)
下載附件
2022-12-14 16:26 上傳
單片機(jī)主函數(shù)如下:
- int main()
- {
-
- OLED_Init();
- Key_Init();
- InitAllVariable();
- OLED_ShowString(1,1,"Press any key to");
- OLED_ShowString(2,1,"start game");
- while(1)
- {
- Game();
- }
- }
復(fù)制代碼
主函數(shù)中的 “Game()”用于開始游戲、暫停游戲以及游戲重新開始,內(nèi)容如下:
- void Game(void)
- {
- i=KEY_ValueReturn();
- if(i)
- {
- i=0;
- OLED_Clear();
- while(1)
- {
- GameBody();
- i=KEY_ValueReturn();
- if(ReturnGameOverFlag()==1)//檢測(cè)到游戲結(jié)束標(biāo)志
- {
- OLED_Clear();
- while(1)
- {
- if(Counter_1_FullFlagReturn()){j=!j;}
- if(j)
- {
- OLED_Clear();
- }else
- {
- OLED_ShowString(1,1,"SCORE:");
- OLED_ShowNum(1,7,GameScore,6);
- OLED_ShowString(3,1,"Press key 3 to");
- OLED_ShowString(4,1,"restart");
- }
- i=KEY_ValueReturn();
- if(i==3){ OLED_Clear();Restart=1; break;}
- }
- }
- if(ReturnGameOverFlag()==0 && Restart==0)
- {
- if(i==3 )
- {
- OLED_Clear();
- while(1)
- {
- if(Counter_1_FullFlagReturn()){j=!j;}
- if(j){
- OLED_Clear();
- }else
- {
- OLED_ShowString(1,1," PAUSED ");
- }
- i=KEY_ValueReturn();
- if(i==3){OLED_Clear(); break;}
- }
- }
- }
- }
- }
- }
-
復(fù)制代碼
游戲主體Gamebody用于實(shí)現(xiàn)整個(gè)游戲的運(yùn)行,代碼如下:
- #include "stm32f10x.h" // Device header
- #include "KEY.h"
- #include "OLED.h"
-
-
- int8_t First_Enemy[9]={16,16,16,16,16,16,16,16,16};//每隊(duì)第一個(gè)敵人的坐標(biāo)
- int8_t Bullet_X[15],Bullet_Y[15];//儲(chǔ)存子彈坐標(biāo)
- uint32_t GameScore=0,LastScore;
- int8_t Restart=0;//重新開始標(biāo)志位
- typedef struct {
- uint8_t FireFlag;
- int8_t ShowBullet;
- uint8_t ShowEnemy;
- uint8_t GameOver;//
- uint8_t BulletSpeedUp;
- }FlagDef;
-
- typedef struct {
- int8_t X;
- int8_t Y;
- }PlayerDef;
-
- typedef struct {
- int8_t X;
- int8_t Y;
- }BulletDef;
-
- typedef struct {
- uint8_t X;
- uint8_t Y;
-
- }EnemyDef;
-
- PlayerDef My_loaction;
- FlagDef Flag;
- BulletDef Bullet_Location;
- BulletDef BulletNum;
- EnemyDef EnemyTarget;
- /****
- *@brief 初始化所有結(jié)構(gòu)體變量
- *@parameter 無
- *@ReturnValue 無
- */
- void InitAllVariable(void)
- {
- My_loaction.X=4;//初始化玩家X坐標(biāo)
- My_loaction.Y=1;//初始化玩家Y坐標(biāo)
- Flag.FireFlag=0;//初始化開火標(biāo)志位
- Flag.ShowBullet=0;//子彈顯示
- Flag.GameOver=0;//游戲結(jié)束標(biāo)志
- Flag.BulletSpeedUp=0;//子彈加速標(biāo)志位
- Bullet_Location.X=My_loaction.X;//初始化子彈位置
- Bullet_Location.Y=My_loaction.Y;//初始化子彈位置
- EnemyTarget.X=8;//首位敵軍的位置
- EnemyTarget.Y=16;//首位敵軍的位置
- }
-
- /****
- *@brief 按鍵返回值處理
- *@parameter 無
- *@ReturnValue 無
- */
- void KeyNumReturn(void)
- {
- int8_t i,temp=0;
- temp=KEY_ValueReturn();
- if(temp){i=temp;}
- if(i==1){ My_loaction.X--; i=0; if(My_loaction.X<=1)My_loaction.X=1;}//1號(hào)鍵按下,玩//家上移一格
- if(i==2){ My_loaction.X++; i=0; if(My_loaction.X>=8)My_loaction.X=8; }//2號(hào)鍵按下,玩//家下移一格
- if(i==3) { i=0; }
- if(i==4) { Flag.FireFlag=1; i=0; } //四號(hào)鍵按下,開火標(biāo)志位置一
- }
-
-
- /****
- *@brief 顯示玩家
- *@parameter
- *@ReturnValue
- */
- void ShowPlayer(void)
- {
- uint8_t i;
- OLED_ShowBlock(My_loaction.X,My_loaction.Y);//根據(jù)坐標(biāo)顯示玩家
- for(i=1;i<=8;i++)//清除玩家移動(dòng)后,上一次留下的影子(oled不會(huì)自動(dòng)清屏,玩家移動(dòng)后,上一次的方塊//依然會(huì)顯示)
- {
- if(i!=My_loaction.X)
- {
- OLED_DeleteBlock(i,My_loaction.Y);
- }
- }
-
- }
-
- /****
- *@brief 子彈處理
- *@parameter 無
- *@ReturnValue 無
- */
- void Bullet_process(void)
- {
- if(Flag.FireFlag==1)//開火標(biāo)志位
- {
- if(Flag.ShowBullet==0)
- {
- Bullet_Location.X=My_loaction.X;
- Bullet_Location.Y=My_loaction.Y+1;
- Flag.ShowBullet=1;//子彈顯示標(biāo)志位
- }else if(Flag.ShowBullet==1)
- {
- Flag.BulletSpeedUp=1;
- }
- }
- Flag.FireFlag=0;
-
- LastScore=GameScore;
- if(Flag.ShowBullet)
- {
- if(Bullet_Location.Y >=1 && Bullet_Location.Y <17)
- {
- if(Counter_0_FullFlagReturn() || Flag.BulletSpeedUp==1)
- {
- Bullet_Location.Y++;
-
- Flag.BulletSpeedUp=0;
- }
- if(Bullet_Location.Y>2)//手動(dòng)清除上一次子彈所在位置,OLED不會(huì)自動(dòng)清屏。
- {
- OLED_DeleteBlock(Bullet_Location.X,Bullet_Location.Y-1);
- }
- }
- EnemyTarget.Y=First_Enemy[Bullet_Location.X];//
- if(Bullet_Location.Y<EnemyTarget.Y+1)//子彈沒有碰到敵人或墻壁則根據(jù)坐標(biāo)顯示子彈
- {
- OLED_ShowBullet(Bullet_Location.X,Bullet_Location.Y);
- }else //子彈碰到敵人或墻壁則清除子彈
- {
- if(Bullet_Location.X<16){First_Enemy[Bullet_Location.X]++;}
- Flag.ShowBullet=0;
- GameScore++;//增加游戲分?jǐn)?shù)
- }
- if(Bullet_Location.Y>=17)Flag.ShowBullet=0;
- }
-
- }
- /****
- *@brief 返回游戲結(jié)束標(biāo)志位
- *@parameter 無
- *@ReturnValue 無
- */
- uint8_t ReturnGameOverFlag(void)
- {
- return Flag.GameOver;
- }
-
- /****
- *@brief 根據(jù)關(guān)卡顯示敵人
- *@parameter 無
- *@ReturnValue 無
- */
- void Enemy_Process(void)
- {
- uint8_t i,j;
- if(Counter_EnemyMovingFlag()==1 )//時(shí)間到,讓所有敵人往前走一步
- {
- for(i=1;i<=8;i++)
- {
- First_Enemy[i]--;
- }
- for(i=1;i<=8;i++)
- {
- for(j=First_Enemy[i];j<17;j++)
- {
- OLED_ShowAnemy(i,j);
- }
- }
- }else if(Counter_EnemyMovingFlag()==0)//時(shí)間沒到,所有敵人原地不動(dòng)
- {
- for(i=1;i<=8;i++)
- {
- for(j=First_Enemy[i];j<17;j++)
- {
- OLED_ShowAnemy(i,j);
- }
- }
- }
- for(i=1;i<=8;i++)//判斷是否有敵人走到了玩家面前
- {
- if(First_Enemy[i]<=2)
- {
- Flag.GameOver=1;//將游戲結(jié)束位置一;
- for(j=1;j<=8;j++)
- {
- First_Enemy[j]=16;
-
- }
- }
- }
- }
-
- /****
- *@brief 根據(jù)分?jǐn)?shù)控制蜂鳴器以及燈光
- *@parameter 無
- *@ReturnValue 無
- */
- void Score_Process(void)
- {
- if(GameScore>LastScore)
- {
- GPIO_ResetBits(GPIOC,GPIO_Pin_13);
- }else
- {
- GPIO_SetBits(GPIOC,GPIO_Pin_13);
- }
-
- if(Counter_0_FullFlagReturn())
- {
- GPIO_SetBits(GPIOC,GPIO_Pin_13);
- }
- }
-
- /****
- *@brief 游戲重新開始處理函數(shù)
- *@parameter 無
- *@ReturnValue 無
- */
- void GameRestart(void)
- {
- if(Restart==1 && Flag.GameOver==1)
- {
- OLED_Clear();
- GameScore=0;
- Flag.GameOver=0;
- Restart=0;
- }
-
- }
-
- /****
- *@brief //游戲主體,在主函數(shù)中循環(huán)調(diào)用該函數(shù),運(yùn)行當(dāng)前游戲。
- *@parameter 無
- *@ReturnValue 無
- */
- void GameBody(void)
- {
- KeyNumReturn();
- ShowPlayer();
- Enemy_Process();
- GameRestart();
- Bullet_process();
- Score_Process();
- }
-
復(fù)制代碼
按鍵處理Key.c用于處理按鍵,讓按鍵按下后產(chǎn)生對(duì)應(yīng)的動(dòng)作,本次的按鍵處理在《單片機(jī)定時(shí)器中斷掃描按鍵程序思路詳解》(http://www.zg4o1577.cn/bbs/dpj-225674-1.html)內(nèi)容上進(jìn)行修改,修改后Key.c內(nèi)容如下:
- #include "stm32f10x.h" // Device header
- #include "delay.h"
-
- uint8_t KEY_Num,KEY_Value;
- static uint8_t KEY_LastState,KEY_NowState;
- uint8_t Counter_0,Counter_0_FullFlag;
- uint8_t Counter_1,Counter_1_FullFlag;
- //uint8_t TEST_i;
- uint16_t Counter_2=0,Counter_EnemyMoving;
- /****
- *@brief 初始化按鍵
- *@parameter 無
- *@ReturnValue 無
- */
- void Key_Init(void)
- {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 開啟GPIOB時(shí)鐘
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);// 開啟GPIOB時(shí)鐘
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//開啟TIM2時(shí)鐘
-
- GPIO_InitTypeDef GPIO_InitStructure;//GPIO初始化
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOB,&GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOC,&GPIO_InitStructure);
- GPIO_SetBits(GPIOC,GPIO_Pin_13);
-
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//TIM2定時(shí)器初始化
- TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//不對(duì)內(nèi)部時(shí)鐘分頻
- TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上計(jì)數(shù)模式
- TIM_TimeBaseInitStructure.TIM_Period=20-1;
- TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//設(shè)置時(shí)鐘計(jì)數(shù)周期為72000000/7200=10000us=1
- TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//通用定時(shí)器沒有重復(fù)計(jì)數(shù)器,設(shè)置為0
- TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
-
- TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//打開TIM2的更新中斷
-
- TIM_InternalClockConfig(TIM2);//選擇內(nèi)部時(shí)鐘源
-
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中斷分組
-
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
- NVIC_Init(&NVIC_InitStructure);
-
- TIM_Cmd(TIM2,ENABLE);
- }
-
- //uint8_t Test_return(void)
- //{
- // return TEST_i;
- //}
- /****
- *@brief 判斷哪個(gè)按鍵被按下
- *@parameter 無
- *@ReturnValue 無
- */
- uint8_t KEY_Numble(void)
- {
- uint8_t i=0;
- if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==0) { i=1; }
- if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==0) { i=2; }
- if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==0) { i=3; }
- if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)==0) { i=4; }
- // TEST_i=i;
- return i;
- }
- /****
- *@brief 返回按鍵的值
- *@parameter 無
- *@ReturnValue 根據(jù)對(duì)應(yīng)的按鍵返回i(1~4)
- */
- uint8_t KEY_ValueReturn(void)
- {
- uint8_t i;
- i=KEY_Value;
- KEY_Value=0;
- return i;
- }
- /****
- *@brief 返回計(jì)數(shù)器Counter_0的狀態(tài)
- *@parameter 無
- *@ReturnValue i:Counter_0計(jì)數(shù)滿則返回1,否則返回0
- */
- uint8_t Counter_0_FullFlagReturn(void)
- {
- uint8_t i;
- i=Counter_0_FullFlag;
- Counter_0_FullFlag=0;
- return i;
- }
- /****
- *@brief 每間隔一定時(shí)間返回?cái)耻娗耙茦?biāo)志位,控制敵軍前移一格
- *@parameter無
- *@ReturnValue i:計(jì)數(shù)器滿則返回1,否則返回0;
- */
- uint8_t Counter_EnemyMovingFlag(void)
- {
- uint8_t i;
- i=Counter_EnemyMoving;
- Counter_EnemyMoving=0;
- return i;
- }
- /****
- *@brief 返回計(jì)數(shù)器Counter_1的狀態(tài)
- *@parameter 無
- *@ReturnValue i:Counter_1計(jì)滿則為1,否則為0
- */
- uint8_t Counter_1_FullFlagReturn(void)
- {
- uint8_t i;
- i=Counter_1_FullFlag;
- Counter_1_FullFlag=0;
- return i;
- }
-
- /****
- *@brief //TIM2定時(shí)器中斷函數(shù)
- *@parameter 無
- *@ReturnValue 無
- */
- void TIM2_IRQHandler(void)//TIM2定時(shí)器中斷函數(shù)
- {
- KEY_LastState=KEY_NowState;//保存好按鍵上一次狀態(tài)
- KEY_NowState=KEY_Numble();//刷新按鍵當(dāng)前狀態(tài)
-
- Counter_0++;
- Counter_2++;
- if(Counter_0==25){Counter_0=0;Counter_0_FullFlag=1;Counter_1++;}
- if(Counter_1==30){Counter_1=0;Counter_1_FullFlag=1;}
- if(Counter_2==2500){Counter_EnemyMoving=1;Counter_2=0;}
-
- if(KEY_LastState ==1 && KEY_NowState ==0)//根據(jù)前后兩次狀態(tài)來決定返回值
- {
- KEY_Value=1;
- }
- if(KEY_LastState ==2 && KEY_NowState ==0)
- {
- KEY_Value=2;
- }
- if(KEY_LastState ==3 && KEY_NowState ==0)
- {
- KEY_Value=3;
- }
- if(KEY_LastState ==4 && KEY_NowState ==0)
- {
- KEY_Value=4;
- }
- TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
- }
-
復(fù)制代碼
Keil代碼下載:
23-打磚塊游戲.7z
(180.88 KB, 下載次數(shù): 29)
2022-12-14 09:06 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|
評(píng)分
-
查看全部評(píng)分
|