欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
STM32單片機打磚塊游戲機制作 附源程序
[打印本頁]
作者:
小白EE
時間:
2022-12-14 10:44
標題:
STM32單片機打磚塊游戲機制作 附源程序
用STM32做一個游戲機
游戲視頻地址:
https://www.bilibili.com/video/BV1i84y1t7ro
制作出來的實物圖如下:
游戲運行圖片如下:
51hei.jpg
(293.73 KB, 下載次數: 42)
下載附件
2022-12-14 16:26 上傳
單片機主函數如下:
int main()
{
OLED_Init();
Key_Init();
InitAllVariable();
OLED_ShowString(1,1,"Press any key to");
OLED_ShowString(2,1,"start game");
while(1)
{
Game();
}
}
復制代碼
主函數中的 “Game()”用于開始游戲、暫停游戲以及游戲重新開始,內容如下:
void Game(void)
{
i=KEY_ValueReturn();
if(i)
{
i=0;
OLED_Clear();
while(1)
{
GameBody();
i=KEY_ValueReturn();
if(ReturnGameOverFlag()==1)//檢測到游戲結束標志
{
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;}
}
}
}
}
}
}
復制代碼
游戲主體Gamebody用于實現整個游戲的運行,代碼如下:
#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};//每隊第一個敵人的坐標
int8_t Bullet_X[15],Bullet_Y[15];//儲存子彈坐標
uint32_t GameScore=0,LastScore;
int8_t Restart=0;//重新開始標志位
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 初始化所有結構體變量
*@parameter 無
*@ReturnValue 無
*/
void InitAllVariable(void)
{
My_loaction.X=4;//初始化玩家X坐標
My_loaction.Y=1;//初始化玩家Y坐標
Flag.FireFlag=0;//初始化開火標志位
Flag.ShowBullet=0;//子彈顯示
Flag.GameOver=0;//游戲結束標志
Flag.BulletSpeedUp=0;//子彈加速標志位
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號鍵按下,玩//家上移一格
if(i==2){ My_loaction.X++; i=0; if(My_loaction.X>=8)My_loaction.X=8; }//2號鍵按下,玩//家下移一格
if(i==3) { i=0; }
if(i==4) { Flag.FireFlag=1; i=0; } //四號鍵按下,開火標志位置一
}
/****
*@brief 顯示玩家
*@parameter
*@ReturnValue
*/
void ShowPlayer(void)
{
uint8_t i;
OLED_ShowBlock(My_loaction.X,My_loaction.Y);//根據坐標顯示玩家
for(i=1;i<=8;i++)//清除玩家移動后,上一次留下的影子(oled不會自動清屏,玩家移動后,上一次的方塊//依然會顯示)
{
if(i!=My_loaction.X)
{
OLED_DeleteBlock(i,My_loaction.Y);
}
}
}
/****
*@brief 子彈處理
*@parameter 無
*@ReturnValue 無
*/
void Bullet_process(void)
{
if(Flag.FireFlag==1)//開火標志位
{
if(Flag.ShowBullet==0)
{
Bullet_Location.X=My_loaction.X;
Bullet_Location.Y=My_loaction.Y+1;
Flag.ShowBullet=1;//子彈顯示標志位
}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)//手動清除上一次子彈所在位置,OLED不會自動清屏。
{
OLED_DeleteBlock(Bullet_Location.X,Bullet_Location.Y-1);
}
}
EnemyTarget.Y=First_Enemy[Bullet_Location.X];//
if(Bullet_Location.Y<EnemyTarget.Y+1)//子彈沒有碰到敵人或墻壁則根據坐標顯示子彈
{
OLED_ShowBullet(Bullet_Location.X,Bullet_Location.Y);
}else //子彈碰到敵人或墻壁則清除子彈
{
if(Bullet_Location.X<16){First_Enemy[Bullet_Location.X]++;}
Flag.ShowBullet=0;
GameScore++;//增加游戲分數
}
if(Bullet_Location.Y>=17)Flag.ShowBullet=0;
}
}
/****
*@brief 返回游戲結束標志位
*@parameter 無
*@ReturnValue 無
*/
uint8_t ReturnGameOverFlag(void)
{
return Flag.GameOver;
}
/****
*@brief 根據關卡顯示敵人
*@parameter 無
*@ReturnValue 無
*/
void Enemy_Process(void)
{
uint8_t i,j;
if(Counter_EnemyMovingFlag()==1 )//時間到,讓所有敵人往前走一步
{
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)//時間沒到,所有敵人原地不動
{
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;//將游戲結束位置一;
for(j=1;j<=8;j++)
{
First_Enemy[j]=16;
}
}
}
}
/****
*@brief 根據分數控制蜂鳴器以及燈光
*@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 游戲重新開始處理函數
*@parameter 無
*@ReturnValue 無
*/
void GameRestart(void)
{
if(Restart==1 && Flag.GameOver==1)
{
OLED_Clear();
GameScore=0;
Flag.GameOver=0;
Restart=0;
}
}
/****
*@brief //游戲主體,在主函數中循環調用該函數,運行當前游戲。
*@parameter 無
*@ReturnValue 無
*/
void GameBody(void)
{
KeyNumReturn();
ShowPlayer();
Enemy_Process();
GameRestart();
Bullet_process();
Score_Process();
}
復制代碼
按鍵處理Key.c用于處理按鍵,讓按鍵按下后產生對應的動作,本次的按鍵處理在《
單片機定時器中斷掃描按鍵程序思路詳解
》(
http://www.raoushi.com/bbs/dpj-225674-1.html
)內容上進行修改,修改后Key.c內容如下:
#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時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);// 開啟GPIOB時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//開啟TIM2時鐘
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定時器初始化
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//不對內部時鐘分頻
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上計數模式
TIM_TimeBaseInitStructure.TIM_Period=20-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//設置時鐘計數周期為72000000/7200=10000us=1
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//通用定時器沒有重復計數器,設置為0
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//打開TIM2的更新中斷
TIM_InternalClockConfig(TIM2);//選擇內部時鐘源
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 判斷哪個按鍵被按下
*@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 根據對應的按鍵返回i(1~4)
*/
uint8_t KEY_ValueReturn(void)
{
uint8_t i;
i=KEY_Value;
KEY_Value=0;
return i;
}
/****
*@brief 返回計數器Counter_0的狀態
*@parameter 無
*@ReturnValue i:Counter_0計數滿則返回1,否則返回0
*/
uint8_t Counter_0_FullFlagReturn(void)
{
uint8_t i;
i=Counter_0_FullFlag;
Counter_0_FullFlag=0;
return i;
}
/****
*@brief 每間隔一定時間返回敵軍前移標志位,控制敵軍前移一格
*@parameter無
*@ReturnValue i:計數器滿則返回1,否則返回0;
*/
uint8_t Counter_EnemyMovingFlag(void)
{
uint8_t i;
i=Counter_EnemyMoving;
Counter_EnemyMoving=0;
return i;
}
/****
*@brief 返回計數器Counter_1的狀態
*@parameter 無
*@ReturnValue i:Counter_1計滿則為1,否則為0
*/
uint8_t Counter_1_FullFlagReturn(void)
{
uint8_t i;
i=Counter_1_FullFlag;
Counter_1_FullFlag=0;
return i;
}
/****
*@brief //TIM2定時器中斷函數
*@parameter 無
*@ReturnValue 無
*/
void TIM2_IRQHandler(void)//TIM2定時器中斷函數
{
KEY_LastState=KEY_NowState;//保存好按鍵上一次狀態
KEY_NowState=KEY_Numble();//刷新按鍵當前狀態
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)//根據前后兩次狀態來決定返回值
{
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);
}
復制代碼
Keil代碼下載:
23-打磚塊游戲.7z
(180.88 KB, 下載次數: 29)
2022-12-14 09:06 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
異性朋友
時間:
2023-6-5 14:31
為什么不能左右移動
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1