基於stm32、0.96寸OLED實現的貪喫蛇小遊戲(詳細源碼註釋)

簡介:本實驗基於stm32最小系統、0.96寸OLED(68*128)和搖桿實現一個經典的貪喫蛇小遊戲。項目源碼地址點擊下載。

硬件設計:

普通搖桿,0.96寸OLED 單色屏幕(SPI協議通訊),stc32f103c8t6最小系統開發板,如下所示。

器件齊全後,用杜邦線將搖桿和oled正確地連接到stm32開發板上,注意各個器件的電源需要接到同一電壓,下圖是接線說明:

 接好線之後,將源碼編譯下載,進入調試,正常運行如下圖所示,如果屏幕出現花屏,那麼將res引腳接到GND進行復位,再重新進行調試或單片機復位:

接着按下搖桿的中鍵就可以進入遊戲:

屏幕的上方顯示得分,通過搖桿控制蛇的運動方向。

遊戲失敗後可按下搖桿中鍵重新開始遊戲。

代碼設計: 

源代碼下載解壓後,利用keil4工具打開工程可看到:

上面已表明各個文件的作用, 可重點看Snake.c遊戲設計文件。如果代碼裏面的註釋是亂碼,點擊Edit->Configuration->Editor->Encoding->選擇Chinese GB2312。下面面只列舉部分代碼說明。

main函數

int main(void)
{
	  RCC_PCLK1Config(RCC_HCLK_Div4);
	  USART1_Configuration(); //初始化串口
	  TIME_Configuration(); //初始化定時器
	  ADC_Configuration(); //初始化搖桿的ad採集
	
	  OLED_Init(); //oled初始化默認參數
      GameReady(); //進入遊戲準備界面

	  Tick_Updata(&sysms);
      while (1){
		  event=JoyState(); //獲取搖桿的狀態
			
		  ret=Game_InputHandle(event);//蛇移動
		  if(ret){ //ret=1 表示屏幕需刷新
				GameMapToLcdCache(); //將像素從遊戲圖像gamemap位圖經過放大後寫進LcdCache顯存
				OLED_Updata();//將LcdCache[8][128]顯存的數據發送到屏幕進行顯示
				sprintf(str,"Score=%d",GameScore);
				OLED_DispString(0,0,str); //屏幕上方顯示分數
		  }
     }
}

main函數並不複雜,while循環裏面不斷獲取搖桿狀態,將狀態傳進Game_InputHandle函數進行遊戲操作。

實現原理:

運用鏈表的特性,蛇的每一個節點就是鏈表的節點,節點的內容是該點的x,y座標,如上圖所示。遍歷鏈表逐個讀取蛇身的每個節點裏面的x,y座標,根據該座標在屏幕上描點,即可描繪出蛇的形狀來。

蛇的運動的原理是從蛇尾節點開始,其x,y座標等於前一個節點的座標,直至到頭節點,頭節點的新x,y座標跟蛇運動的方向有關。每當蛇遲到食物時,尾部追加節點。

void GAME_NewSnake(SNAKELIST* SnakeList) //初始化鏈表,初始化蛇長度,4+1節
{
	int x=4,y=15,i;//蛇的初始位置
	
	SnakeList->x=x;
	SnakeList->y=y++;
	SnakeList->prev=SnakeList;
	SnakeList->next=SnakeList;
	
	for(i=0;i<4;i++){
		GAME_SnakeListAddNode(SnakeList,x,y+i);
	}
	GAME_SnakeFillInGameMap(gamemap,SnakeList);
}

GAME_NewSnake遊戲開始前,給蛇初始化5個節點,頭節點在x=4,y=15處,其餘4個節點在其下方。通過GAME_SnakeFillInGameMap函數將蛇在gamemap上描畫出來。gamemap再放大映射到LCDcache顯存裏面去,再通過spi把整個屏幕的像素髮送到屏幕進行顯示。

void GAME_NewFood(unsigned char (*gamemap)[WIDTH]) //在地圖上隨機產生新的食物
{
	unsigned int seed1,seed2;
	int x,y;
	
	while(1){
		Tick_Updata(&seed1);
		Tick_Updata(&seed2);
		x=seed1%WIDTH;
		y=seed2%HEIGHT;
		if(gamemap[y][x]==0){
			gamemap[y][x]=2;
			break;
		}
	}
}

GAME_NewFood在地圖上隨機生成一個食物,當然這裏的隨機數,利用不斷變化的時鐘進行求餘,得到的隨機座標後,先判斷該左邊是否可用,若是已經存在東西(蛇身或者邊框)則繼續獲取隨機數,如此反覆直到得到一個空的的隨機座標。所以,當遊戲玩到最後,蛇身很長的時候(界面沒有多少空白點),產生食物的時間會長很多。

unsigned char Game_InputHandle(unsigned char event)//對輸入按鍵事件的處理
{
	unsigned char ret=0;
	
	if(GameStatus==GAMEPAUSE&&event!=RESTART_EV){ //遊戲狀態未運行時,除非按下restart,否則不進入
		return 0;
	}
	
	if(event==5-Snokedirection){//按下蛇前進的相反方向時,忽略
		event=NON; 
	}
	
	switch(event){
		case NON:
			speed_max=200;
			if(If_TimeOut(&speed_move,SPPED_MOVE)){ //自動前進
				Tick_Updata(&speed_move);
			    event=Snokedirection;
		    }else{
				break;
			}
		case TURN_LEFT_EV: //蛇向左移動
		case TURN_RIGHT_EV://蛇向右移動
		case TURN_DOWN_EV:	//蛇向下移動	
		case TURN_UP_EV:		//蛇向上移動	
			if(If_TimeOut(&speed_turn,speed_max)){
				Tick_Updata(&speed_turn);
				speed_max=150;
				Snokedirection=event;
				ret=GAME_SnakeMove(gamemap,&SnokeHeadNode,event,&GameScore);	
				printf("event=%d\r\n",event);
			}
			break;
		case RESTART_EV://遊戲復位
			if(If_TimeOut(&speed_restart,SPPED_RESTART_MAX)){
					Tick_Updata(&speed_restart);
					GameStatus=GAMERUNING;
					GameScore=0;
				    Snokedirection=TURN_UP_EV;
					GAME_BackgroundInit(gamemap);
					GAME_NewSnake(&SnokeHeadNode);
					GAME_NewFood(gamemap);
					ret=1;
					printf("event=%d\r\n",event);
			}
		  break;
		default:
			//error
			break;
	}
	return ret;
}

Game_InputHandle函數在main函數裏被調用,SPPED_MOVE這個宏是控制蛇自動移動的速度的,所設置的值越低則運動的越快。speed_max的值是控制手動移動的速度,當搖桿狀態被持續維持爲一個方向時,就會按照該速度進行前進。

源碼添加了許多註釋,歡迎下載。若有疑問歡迎提出。

相關推薦:

基於stm32、0.96寸OLED實現的俄羅斯方塊小遊戲(詳細源碼註釋)

 

<<天下難事,必做於易;天下大事,必做於細。——老子>>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章