貪喫蛇c++實現 實訓認識小遊戲

大一假期幾天的實訓認識課,用 C++ 做了兩個小遊戲,一個是推箱子,一個是貪喫蛇,讓我對編程實現二維遊戲有了點基礎認識,下面是貪喫蛇遊戲的一點簡要認識。
運行環境:vs2012
用到結構體,枚舉enum, if條件語句等
首先,我們要用到地圖Map當然指的是遊戲地圖,我們使用0,1來構造,1爲牆(障礙物),0爲可通過空間,大小隨心,如圖:
蛇地圖

當然,0,1也用於後面的牆的圖案定義以及蛇的撞牆判定,這裏方塊牆(也可以其它圖案)我們使用搜狗輸入法裏的符號大全:
在這裏插入圖片描述
enum用來定義幾個選項,如遊戲菜單界面,遊戲控制區,遊戲輸贏判定,enum枚舉c++學習過程中大家都學過,例如:
enum enumType {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
枚舉量Monday、Tuesday等的值默認分別爲0-6,我們可以顯式的設置枚舉量的值:
enum enumType {Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6, Sunday=7};但指定的值必須是整數。
還有結構體struct:結構體可以將原本意義屬於一個整體的數據組合在一起。

唯一有一個新知識:按鍵控制
在這裏插入圖片描述
函數GetAsyncKeyState確定在調用它時某個按鍵處於彈起還是按下的,以及此按鍵是否在上一次調用GetAsyncKeyState之後(“又”)按下過(重複也算按下)。
這句話的完整意思是:預定義了一個KEYDOWN參數爲vk_code 他的定義的含義是判斷一個鍵是否被按下(GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0如果按下了就是1,沒有按下就是0
然後其它地方用的時候直接用KEYDOWN(vk_code)判斷這個鍵是否按下,相反彈起來是1按下是0。

清屏函數:system(“cls”);執行c++的一些比較大的程序時,可能會需要執行很多功能,但一次一次功能執行過後,會留下以前的字符佔據着屏幕,看起來特別亂,也影響接下來的功能調用,這個函數可以在每執行完一次功能,選擇回到一開始的初始界面。
作用是清除程序先前顯示的內容,但不會清除先前調用程序功能而實現的對內存的改變.而由於是清除先前顯示的內容,所以對此函數的寫入位置要考慮一下,避免連初始界面也給清空了。
若想調用此函數,在程序代碼的頭文件上,要加上#include <stdlib.h> 纔可以使用。

我們把它放在循環中,最合適不過,不斷把循環出的界面清屏,利用視覺暫留,造成動畫效果。

延時函數:Sleep(1);//延時函數,減慢蛇的速度,便於控制,我的代碼只有一關,所以直接自己隨意改時間,覺得若是好多關卡,可以寫一個函數,每關改變括號內的數值,改變遊戲難度。
要加上頭文件 #include<time.h>

最後就是不知爲何,筆記本運行會出現好多莫名其妙的點閃啊閃,在學校機房運行卻沒有。

運行部分截圖如下:
菜單界面
在這裏插入圖片描述
遊戲開始界面:
在這裏插入圖片描述
遊戲中界面:這張截圖考手速

在這裏插入圖片描述
撞牆之後:
在這裏插入圖片描述
食物必須隨機出現,所以使用隨機函數生成食物座標,蛇頭控制,蛇的移動是核心,還有蛇的長度增加,蛇移動時身體要跟着蛇頭,所以我們總是要備份前一個點的位置,將其賦給後一點,實現蛇的移動,還有用判斷語句實現喫完食物蛇的長度加一。

接下來附上代碼(含註釋):

// GREED Snake.cpp : 定義控制檯應用程序的入口點。
//


#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include<time.h>//蛇走的太快,利用此頭文件的函數讓他慢下來

using namespace std;

#define KEY_DOWN(vk_code) GetAsyncKeyState(vk_code)&0x8000?1:0

int g_arrMap1[15][20]={
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
enum
{
	E_MENU_START,
	E_MENU_SETTING,
	E_MENU_EXIT
};
enum
{
	E_GAME_MENU,
	E_GAME_MAP,
	E_GAME_WIN,
	E_GAME_LOSE
};
enum
{
	E_DIR_NONE,
	E_DIR_DOWN,
	E_DIR_UP,
	E_DIR_LEFT,
	E_DIR_RIGHT
};

struct SData
{
	SData()
	{
		nRow = 0;
		nCol = 0;
		nRowBk = 0;
		nColBk = 0;
	}
	SData(int nInRow,int nInCol)
	{
		nRow = nInRow;
		nCol = nInCol;
		nRowBk = nInRow;
		nColBk = nInCol;
	}
	void backUp()//備份函數
	{
		nRowBk = nRow;
		nColBk = nCol;
	}
	void restore()//座標釋放函數
	{
		nRow = nRowBk;
		nCol = nColBk;
	}
	int nRow;
	int nCol;
	int nRowBk;
	int nColBk;

};

int _tmain(int argc, _TCHAR* argv[])
{   Sleep(1);//延時函數,減慢蛇的速度
	int nMenuState =  E_MENU_START;//菜單狀態
	int nGameState =  E_GAME_MENU;//遊戲狀態
	//定義蛇:
	SData arrSnake[15]={};
	//蛇頭座標初始化
	arrSnake[0] = SData(2,2);
	//蛇長度初始化
	int nlength = 1;
	int foodnumber=1;
	//定義蛇頭的移動方向,
	int  nDir = E_DIR_NONE;
	//食物座標
	SData sFood = SData( rand()%13+1, rand()%18+1) ;  //食物隨機出現
	while(true)
	{
	system("cls");
		if(E_GAME_MENU == nGameState)
		{
			if(KEY_DOWN(VK_RETURN))//菜單數據更新按下enter鍵進入遊戲地圖
			{
				if(E_MENU_START == nMenuState)/*按下enter鍵時要判斷當前箭頭是否指示在遊戲開始的位置
			    判斷nMenuState的值是否是0,是則切換,不是則不管*/
				{nGameState = E_GAME_MAP;}
				else if(E_MENU_EXIT==nMenuState)//退出程序運行框
			     {
			     exit(0);
			     }
			}
			
		    if(KEY_DOWN(VK_UP))
			{
				nMenuState--;
			    if(nMenuState<E_MENU_START)
				  {
					nMenuState = E_MENU_EXIT;
				  }
			}
			else if(KEY_DOWN(VK_DOWN))
			{
				nMenuState++;
				if(nMenuState > E_MENU_EXIT)
				{
					nMenuState = E_MENU_START;
				}
			}
				//菜單渲染
			if(E_MENU_START == nMenuState)
			{
				cout <<"->遊戲開始"<< endl;
				cout <<"  遊戲設置"<< endl;
				cout <<"  遊戲結束"<< endl;
			}
			else if(E_MENU_SETTING == nMenuState)
			{
				cout <<"  遊戲開始"<< endl;
				cout <<"->遊戲設置"<< endl;
				cout <<"  遊戲結束"<< endl;
			}
			else if(E_MENU_EXIT == nMenuState)
			{
				cout <<"  遊戲開始"<< endl;
				cout <<"  遊戲設置"<< endl;
				cout <<"->遊戲結束"<< endl;
			}
		}
		//切地圖	
		else if(nGameState == E_GAME_MAP)
		{
			if(KEY_DOWN(VK_ESCAPE))//按下esc鍵返回菜單
			{
				nGameState = E_GAME_MENU;
			}

			//蛇頭的座標的備份
			arrSnake[0].nRowBk = arrSnake[0].nRow;
			arrSnake[0].nColBk = arrSnake[0].nCol;


			//控制蛇頭的自動
			if(KEY_DOWN(VK_UP))
			{
				nDir = E_DIR_UP;
			}
			if(KEY_DOWN(VK_DOWN))
			{
				nDir = E_DIR_DOWN;
			}
			if(KEY_DOWN(VK_LEFT))
			{
				nDir = E_DIR_LEFT;
			}
			if(KEY_DOWN(VK_RIGHT))
			{
				nDir = E_DIR_RIGHT;
			}
			if(nDir == E_DIR_UP)
			{
				arrSnake[0].nRow--;
			}
		
			if(nDir == E_DIR_DOWN)
			{
				arrSnake[0].nRow++;
			}
		
			if(nDir == E_DIR_LEFT)
			{
				arrSnake[0].nCol--;
			}
			
			if(nDir == E_DIR_RIGHT)
			{
				arrSnake[0].nCol++;
			}
			//喫食物
			if(arrSnake[0].nRow == sFood.nRow && arrSnake[0].nCol == sFood.nCol)
			{
				nlength++;
				sFood = SData(rand()%13+1 ,rand()%18+1);
				//foodnumber++;
			}
			//身體跟隨蛇頭
			for(int i = 1;i < nlength;i++)
				{
					//備份當前這一節座標
					arrSnake[i].backUp();
						//arrSnake[i].nRowBk = arrSnake[i].nRow;
						//arrSnake[i].nColBk = arrSnake[i].nCol;
					//把這一節的座標給下一節
						arrSnake[i].nRow = arrSnake[i-1].nRowBk;
						arrSnake[i].nCol = arrSnake[i-1].nColBk;
					
					//在這一節座標中輸出
						
			  }
			//遊戲勝負的判斷
			//撞牆則失敗
			if(1 == g_arrMap1[arrSnake[0].nRow][arrSnake[0].nCol] )
			{
				nGameState = E_GAME_LOSE;
			}
			for(int i=1;i<15;i++)
			{
				if(arrSnake[0].nRow == arrSnake[1].nRow && arrSnake[0].nCol == arrSnake[1].nCol)
				{
					nGameState = E_GAME_LOSE;
					break;
				}
			}
			
			

			//地圖渲染
			for(int i=0;i<15;i++)
			{
				for(int j=0;j<20;j++)
				{
					bool bDrawSnake = false;
					for(int m=0; m<15; m++)
					{
						if(i == arrSnake[m].nRow && j == arrSnake[m].nCol)
						{
							bDrawSnake = true;
							break;
						}
					}
					if(1 == g_arrMap1[i][j])
					{
						cout<<"■";
					}
					else if(bDrawSnake)
					{
						cout<<"□";
					}
					else if(i == sFood.nRow && j == sFood.nCol) //輸出食物的位置
					{
						cout<<"●";
					}
					else
					{
						cout<<"  ";
					}
				}
				cout<<endl;
			}
		}
		else if ( nGameState == E_GAME_LOSE )
			{
				if(KEY_DOWN(VK_ESCAPE))
				{
					nGameState = E_GAME_MENU;   //按向下鍵 返回遊戲菜單
				}
				cout<<"    很遺憾,你輸了這場遊戲!"<<endl;
				cout<<"按Esc鍵退至菜單並進行新遊戲吧!";
			}
		
	}
	return 0;
}
 
 



假期實訓認識之貪喫蛇。其實一開始不會蛇頭自動走時,是仿照推箱子寫的手動貪喫蛇,牽着蛇鼻子走,哈哈。
推箱子傳送:
推箱子C++實現

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