VS2013編寫貪喫蛇控制檯程序

       貪喫蛇好像是學習C/C++進階的一個好項目,這裏轉載一篇可以正常運行的程序,源碼是VS2008編寫,用高版本亦可運行如我用的VS2013。程序運行沒有問題,但是不完美,整個窗口在重新繪製的時候會有閃爍,貪喫蛇對於方向鍵的響應滯後等,後面有時間我再在此基礎上完善吧。

原文地址:https://www.oschina.net/code/snippet_1265060_27744

程序分爲三個部分,一個Snake_Class.h 頭文件、一個Snake_Class.cpp源文件和一個main.cpp主程序,代碼如下。

Snake_Class.h頭文件程序:

#ifndef SNAKE
#define SNAKE

#include<windows.h>
#include<vector>
#include<string>

//標記界面和菜單項的ID
enum ID_ { ID_1 = 1, ID_2, ID_3, ID_4, ID_5, ID_6, ID_7 };

//標記初級,中級,高級三種遊戲等級
enum Rank_ { first = 150, middle = 100, high = 50 };


//貪喫蛇結構
struct Snake_data{
	bool state;                    //標記蛇狀態
	UINT Snake_size;                //標記蛇長度
	std::vector<COORD> Snake_coord; //蛇的當前座標
	COORD food_coord;               //食物座標
	UINT rank;                     //標記等級
	UINT mark;                      //分數
	UINT key;                       //記錄按鍵方向
	ID_ ID_interface;               //標記當前停留界面ID
	short ID_option;               //標記被選中菜單的ID
	bool Flag;                      //標記刷新
};

//貪喫蛇類
class Snake_class{
public:
	Snake_class(){}
	Snake_class(Snake_data *data) : pSnake(data){}
	void ShowMenu();            //顯示菜單
	void StartGame();          //開始遊戲
	void ShowPause();           //顯示暫停界面
	void SaveRecord();          //保存記錄
	void ShowRank();            //顯示等級
	void ShowRecord();          //顯示存檔記錄列表
	bool Read(size_t);        //讀取記錄
	void ShowArmory();          //顯示英雄榜
	void Die();                 //死亡界面
	size_t Create_file();       //存儲文件
private:
	void JudgeDie();            //判斷死亡
	bool Jesus();               //上榜判斷
	void ShowSnake(COORD&);   //顯示蛇
	void ShowPointer(COORD, std::string); //顯示指針
	void Show_not();            //顯示無數據
	Snake_data *pSnake;
};



#endif;

Snake_Class.cpp程序:

#include"Snake_Class.h"
#include<iostream>
#include<fstream>
#include<ctime>
#include<cstdlib>

//獲取緩衝區句柄
static const HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
static CONSOLE_SCREEN_BUFFER_INFO info;
//保存蛇的記錄數據文件
static const char *Snake_Record[] = { "d://SnakeRecord//Snake1.txt",
"d://SnakeRecord//Snake2.txt",
"d://SnakeRecord//Snake3.txt",
"d://SnakeRecord//Snake4.txt",
"d://SnakeRecord//Snake5.txt" };

static const char *S_Armory[] = { "d://SnakeRecord//Armory1.txt",
"d://SnakeRecord//Armory2.txt",
"d://SnakeRecord//Armory3.txt" };
//顯示主菜單(完成已測試)
void Snake_class::ShowMenu(){
	//獲取緩衝區相關信息
	GetConsoleScreenBufferInfo(handle, &info);
	char *str[] = { "開 始 遊 戲",
		"難 度 等 級",
		"讀 取 存 檔",
		"英 雄 榜",
		"退 出 遊 戲" };
	//輸出菜單選項
	short y = 3;
	COORD cd = { info.srWindow.Right / 2 - 5, y };
	for (size_t n = 0; n<sizeof(str) / sizeof(*str); ++n){
		SetConsoleCursorPosition(handle, cd);
		std::cout << *(str + n);
		cd.Y += 2;
	}
	//判斷指針指向哪個菜單選項
	cd.X -= 2;
	cd.Y = y;
	switch (pSnake->ID_option){
	case ID_1:
		break;
	case ID_2:
		cd.Y = y + 2; break;
	case ID_3:
		cd.Y = y + 4; break;
	case ID_4:
		cd.Y = y + 6; break;
	case ID_5:
		cd.Y = y + 8; break;
	}
	ShowPointer(cd, pSnake->Flag ? std::string("  ") : std::string("><"));
}

//開始遊戲(完成待測試)
void Snake_class::StartGame(){
	COORD cd;
	//判斷是否已有食物
	if (!pSnake->food_coord.X){
		srand((unsigned int)time(NULL));
		while (1){
			//限制食物出現的座標不與圍牆相同
			++(cd.X = rand() % 78);
			++(cd.Y = rand() % 18);
			//判斷食物座標是否與蛇身吻合
			std::vector<COORD>::iterator ite;
			for (ite = pSnake->Snake_coord.begin(); ite != pSnake->Snake_coord.end(); ++ite){
				if (ite->X == cd.X && ite->Y == cd.Y)
					break;
			}
			if (ite == pSnake->Snake_coord.end()){
				pSnake->food_coord.X = cd.X;
				pSnake->food_coord.Y = cd.Y;
				break;
			}
		}
	}
	SetConsoleCursorPosition(handle, pSnake->food_coord);
	std::cout << "*";
	//判定按鍵方向
	cd.X = pSnake->Snake_coord.begin()->X;
	cd.Y = pSnake->Snake_coord.begin()->Y;
	switch (pSnake->key){
	case VK_UP:
		--cd.Y; break;
	case VK_DOWN:
		++cd.Y; break;
	case VK_LEFT:
		--cd.X; break;
	case VK_RIGHT:
		++cd.X; break;
	}
	ShowSnake(cd);
	JudgeDie();
}

//顯示暫停界面(完成已測試)
void Snake_class::ShowPause(){
	COORD cd = { info.srWindow.Right / 2 - 10, info.srWindow.Bottom / 5 };
	SetConsoleCursorPosition(handle, cd);
	std::cout << "遊 戲 暫 停 中 ......";
	char *str[] = { "繼 續 遊 戲",
		"保 存 遊 戲",
		"退 出 遊 戲" };
	//輸出菜單選項
	short X = info.srWindow.Right / 3;
	cd.X = X / 2 - 5;
	cd.Y = info.srWindow.Bottom / 3 * 2 - 4;
	for (size_t i = 0; i<sizeof(str) / sizeof(*str); ++i){
		SetConsoleCursorPosition(handle, cd);
		std::cout << *(str + i);
		cd.X += X;
	}

	//判斷指針應指向的菜單選項
	switch (pSnake->ID_option){
	case ID_1:
		cd.X = X / 2 - 7; break;
	case ID_2:
		cd.X = X / 2 + X - 7; break;
	case ID_3:
		cd.X = X / 2 + 2 * X - 7; break;
	}
	ShowPointer(cd, pSnake->Flag ? std::string("  ") : std::string("><"));
}

//保存記錄(完成未測試)
void Snake_class::SaveRecord(){
	std::ofstream outopen;
	outopen.open(*(Snake_Record + Create_file()));
	if (!outopen){
		std::cerr << "\n打開文件失敗!\n";
		exit(0);
	}
	//保存記錄到文件中,前面加"0"是爲了後面檢測是否文件爲空使用
	outopen << "0 " << pSnake->Snake_size << " ";
	for (std::vector<COORD>::iterator ite = pSnake->Snake_coord.begin();
		ite != pSnake->Snake_coord.end(); ++ite)
		outopen << ite->X << " " << ite->Y << " ";
	outopen << pSnake->rank << " " << pSnake->mark << " " << pSnake->key;
	outopen.close();
	//輸出保存成功
	COORD cd = { info.srWindow.Right / 2 - 4, info.srWindow.Bottom / 3 * 2 - 1 };
	SetConsoleCursorPosition(handle, cd);
	std::cout << "保存成功!\a";
}

//顯示等級(已測試)
void Snake_class::ShowRank(){
	COORD cd = { info.srWindow.Right / 2 - 6, info.srWindow.Bottom / 3 + 2 };
	char *str[] = { "初       級",
		"中       級",
		"高       級" };
	for (size_t i = 0; i<sizeof(str) / sizeof(*str); ++i){
		SetConsoleCursorPosition(handle, cd);
		std::cout << *(str + i);
		cd.Y += 2;
	}
	//判斷指針所停留的選項
	cd.X -= 2;
	cd.Y = info.srWindow.Bottom / 3 + 2;
	switch (pSnake->ID_option){
	case ID_1:
		break;
	case ID_2:
		cd.Y += 2; break;
	case ID_3:
		cd.Y += 4; break;
	}
	ShowPointer(cd, pSnake->Flag ? std::string("  ") : std::string("><"));
}

//顯示存檔記錄(已測試)
void Snake_class::ShowRecord(){
	COORD cd = { info.srWindow.Right / 2 - 12, 8 };
	//輸出記錄
	std::ifstream inopen;
	SetConsoleCursorPosition(handle, cd);
	for (size_t i = 0; i<sizeof(Snake_Record) / sizeof(*Snake_Record); ++i){
		inopen.open(*(Snake_Record + i));
		if (!inopen || (inopen.get() == EOF && i == 0)){
			Show_not();
			pSnake->ID_option = ID_7;//第7個選項標記,在按回車時檢測下
			return;
		}
		if (inopen.get() != EOF){
			UINT _rank, _mark;
			inopen >> _mark;
			++(_mark *= 2);
			while (_mark--)
				inopen >> _rank;
			inopen >> _mark;
			switch (_rank){
			case first:
				std::cout << "初級"; break;
			case middle:
				std::cout << "中級"; break;
			case high:
				std::cout << "高級"; break;
			}
			std::cout << "\t\t\t  " << _mark;
		}
		else
			std::cout << " ---\t\t\t  ---";

		cd.Y += 2;
		SetConsoleCursorPosition(handle, cd);
		inopen.close();
		inopen.clear();//重置流狀態
	}
	std::cout << "\t   返 回 菜 單";
	cd.X = info.srWindow.Right / 2 - 4;
	cd.Y = 4;
	SetConsoleCursorPosition(handle, cd);
	std::cout << "存 檔 記 錄";
	cd.X -= 10;
	cd.Y += 2;
	SetConsoleCursorPosition(handle, cd);
	std::cout << "遊戲等級\t\t當前分數";
	//輸出指針
	cd.X = info.srWindow.Right / 2 - 14;
	cd.Y = 8;
	switch (pSnake->ID_option){
	case ID_1:
		break;
	case ID_2:
		cd.Y += 2; break;
	case ID_3:
		cd.Y += 4; break;
	case ID_4:
		cd.Y += 6; break;
	case ID_5:
		cd.Y += 8; break;
	case ID_6:
		cd.Y += 10; break;
	}
	ShowPointer(cd, pSnake->Flag ? std::string("  ") : std::string("><"));
}

//讀取記錄
bool Snake_class::Read(size_t i){
	std::ifstream inopen(*(Snake_Record + i));
	if (inopen.get() == EOF){
		std::cout << "\a";
		inopen.close();
		return false;
	}
	inopen >> pSnake->Snake_size;
	COORD cd;
	pSnake->Snake_coord.clear();
	for (int n = 1; n <= pSnake->Snake_size; ++n){
		inopen >> cd.X >> cd.Y;
		pSnake->Snake_coord.push_back(cd);
	}
	inopen >> pSnake->rank >> pSnake->mark >> pSnake->key;
	inopen.close();
	inopen.clear();
	return true;
}

//顯示英雄榜(未測試)
void Snake_class::ShowArmory(){
	short nt = 0;
	COORD cd = { info.srWindow.Right / 3, info.srWindow.Bottom / 3 };
	std::ifstream inopen;
	for (size_t i = 0; i<sizeof(S_Armory) / sizeof(*S_Armory); ++i){
		UINT _rank = 0, _mark = 0;
		inopen.open(*(S_Armory + i));
		if (!inopen){
			++nt;
			continue;
		}
		inopen >> _rank >> _mark;
		switch (_rank){
		case first:
			SetConsoleCursorPosition(handle, cd);
			std::cout << "小牛 :初級\t\t  " << _mark;
			break;
		case middle:
			cd.Y += 2;
			SetConsoleCursorPosition(handle, cd);
			std::cout << "中牛 :中級\t\t  " << _mark;
			break;
		case high:
			cd.Y += 2;
			SetConsoleCursorPosition(handle, cd);
			std::cout << "大牛 :高級\t\t  " << _mark;
			break;
		}
		inopen.close();
		inopen.clear();
	}
	if (nt == 3){
		Show_not();
		return;
	}
	cd.X = info.srWindow.Right / 2 - 3;
	cd.Y = 4;
	SetConsoleCursorPosition(handle, cd);
	std::cout << "英 雄 榜";
	cd.X -= 10;
	cd.Y += 2;
	SetConsoleCursorPosition(handle, cd);
	std::cout << "\t等 級\t\t分 數";
	cd.Y = info.srWindow.Bottom - 7;
	SetConsoleCursorPosition(handle, cd);
	std::cout << "按回車返回主菜單........";
}

//死亡界面(未測試)
void Snake_class::Die(){
	COORD cd = { info.srWindow.Right / 2 - 10, info.srWindow.Bottom / 5 };
	SetConsoleCursorPosition(handle, cd);
	std::cout << "    您 已 x_x 了 !";
	char *str[] = { "返 回 菜 單",
		"退 出 遊 戲" };
	//輸出菜單選項
	short X = info.srWindow.Right / 2;
	cd.X = X / 2 - 5;
	cd.Y = info.srWindow.Bottom / 3 * 2 - 4;
	for (size_t i = 0; i<sizeof(str) / sizeof(*str); ++i){
		SetConsoleCursorPosition(handle, cd);
		std::cout << *(str + i);
		cd.X += X;
	}

	//判斷指針應指向的菜單選項
	switch (pSnake->ID_option){
	case ID_1:
		cd.X = X / 2 - 7; break;
	case ID_2:
		cd.X = X / 2 + X - 7; break;
	}
	ShowPointer(cd, pSnake->Flag ? std::string("  ") : std::string("><"));
	if (Jesus()){
		cd.X = X / 2;
		cd.Y = info.srWindow.Bottom / 3;
		SetConsoleCursorPosition(handle, cd);
		std::cout << "喲...這分? ╮(╯▽╰)╭ 也能上榜。。。!";
		cd.Y += 2;
		SetConsoleCursorPosition(handle, cd);
		std::cout << "上榜等級:";
		switch (pSnake->rank){
		case first:
			std::cout << "初級"; break;
		case middle:
			std::cout << "中級"; break;
		case high:
			std::cout << "高級"; break;
		}
		std::cout << "\t上榜分數:" << pSnake->mark;
	}
}

//存儲記錄文件(完成未測試)
size_t Snake_class::Create_file(){
	std::ifstream inopen;
	size_t fn = 0, fc = 0, iend = sizeof(Snake_Record) / sizeof(*Snake_Record);
	//判斷文件是否存在或文件已被存滿
	for (size_t i = 0; i<iend; ++i){
		inopen.open(*(Snake_Record + i));
		if (!inopen) ++fn;
		else if (inopen.get() == EOF){
			inopen.close();
			return i;
		}
		else { ++fc; inopen.close(); }
	}
	if (fn == iend || fc == iend){
		std::ofstream outopen;
		//創建文本
		for (size_t i = 0; i<iend; ++i){
			outopen.open(*(Snake_Record + i));
			outopen.close();
		}
	}
	//返回打開成功的文件索引
	return 0;
}

//判斷死亡(未測試)
void Snake_class::JudgeDie(){
	std::vector<COORD>::iterator hbeg = pSnake->Snake_coord.begin(),
		beg = hbeg + 1;
	while (beg != pSnake->Snake_coord.end()){
		if (beg->X == hbeg->X && beg->Y == hbeg->Y){
			pSnake->state = FALSE;
			return;
		}
		++beg;
	}
	COORD cd;
	if (hbeg->X <= 0 || hbeg->Y <= 0 ||
		hbeg->X >= info.srWindow.Right || hbeg->Y >= info.srWindow.Bottom - 5){
		if (pSnake->Snake_size < 40){
			pSnake->state = FALSE;
			return;
		}
		//如果達到了40級可以穿牆
		switch (pSnake->key){
		case VK_UP:
			cd.X = pSnake->Snake_coord.begin()->X;
			cd.Y = info.srWindow.Bottom - 6;
			break;
		case VK_DOWN:
			cd.X = pSnake->Snake_coord.begin()->X;
			cd.Y = 1;
			break;
		case VK_LEFT:
			cd.X = info.srWindow.Right - 1;
			cd.Y = pSnake->Snake_coord.begin()->Y;
			break;
		case VK_RIGHT:
			cd.X = 1;
			cd.Y = pSnake->Snake_coord.begin()->Y;
			break;
		}
		ShowSnake(cd);
	}
}

//上榜判斷(未測試)
bool Snake_class::Jesus(){
	std::ifstream inopen;
	size_t i;
	//判斷相應等級打開相應文件
	switch (pSnake->rank){
	case first:
		i = 0; break;
	case middle:
		i = 1; break;
	case high:
		i = 2; break;
	}
	inopen.open(*(S_Armory + i));
	if (inopen){
		UINT _mark;
		inopen >> _mark >> _mark;
		if (_mark >= pSnake->mark){
			inopen.close();
			return FALSE;
		}
	}
	std::ofstream outopen(*(S_Armory + i));//創建文件並輸入
	if (!outopen){
		std::cerr << "打開英雄榜文件出錯" << std::endl;
		exit(0);
	}
	outopen << pSnake->rank << " " << pSnake->mark;
	outopen.close();
	return TRUE;
}
//顯示蛇(未測試)
void Snake_class::ShowSnake(COORD& cd){
	if (cd.X == pSnake->food_coord.X && cd.Y == pSnake->food_coord.Y){
		//在最後添加一個座標
		pSnake->Snake_coord.push_back(*(pSnake->Snake_coord.rbegin()));
		pSnake->food_coord.X = pSnake->food_coord.Y = 0;//標誌食物已被喫掉
		++pSnake->mark;
		++pSnake->Snake_size;
	}
	COORD cod;
	cod.X = (pSnake->Snake_coord.rbegin())->X;
	cod.Y = (pSnake->Snake_coord.rbegin())->Y;
	std::vector<COORD>::reverse_iterator rbeg = pSnake->Snake_coord.rbegin();
	while (rbeg != pSnake->Snake_coord.rend() - 1){
		rbeg->X = (rbeg + 1)->X;
		rbeg->Y = (rbeg + 1)->Y;
		++rbeg;
	}
	//顯示蛇
	pSnake->Snake_coord.begin()->X = cd.X;
	pSnake->Snake_coord.begin()->Y = cd.Y;
	for (std::vector<COORD>::iterator beg = pSnake->Snake_coord.begin();
		beg != pSnake->Snake_coord.end(); ++beg){
		SetConsoleCursorPosition(handle, *beg);
		std::cout << "*";
	}
	SetConsoleCursorPosition(handle, cod);
	std::cout << " ";
}

//顯示指針(完成)
inline void Snake_class::ShowPointer(COORD cd, std::string str){
	SetConsoleCursorPosition(handle, cd);
	std::cout << str[0];
	pSnake->ID_interface != ID_6 ? cd.X += 14 : cd.X = info.srWindow.Right / 3 * 2 + 3;
	SetConsoleCursorPosition(handle, cd);
	std::cout << str[1];
}

//顯示無數據(完成)
inline void Snake_class::Show_not(){
	COORD cd = { info.srWindow.Right / 2 - 4, info.srWindow.Bottom / 2 };
	SetConsoleCursorPosition(handle, cd);
	std::cout << "無 數 據 !";
	cd.X -= 6;
	cd.Y += 2;
	SetConsoleCursorPosition(handle, cd);
	std::cout << "請按回車返回主菜單......";
}

main函數主程序:

#include<iostream>
#include<direct.h>
#include"Snake_Class.h"

#define _max(ID) --snake.ID_option < ID_1?ID : snake.ID_option
#define _min(ID) ++snake.ID_option > ID?ID_1 : snake.ID_option

//鉤子過程
LRESULT CALLBACK _HookProc(int, WPARAM, LPARAM);

void Wall();       //畫牆函數
void Frame();      //畫框函數
void initialize_();//初始化蛇結構數據

Snake_data snake;
Snake_class csnake(&snake);
static HANDLE handle;  //控制檯句柄
//控制檯信息結構
static CONSOLE_SCREEN_BUFFER_INFO info;

int main(){
	using namespace std;
	//獲取輸出緩衝區句柄
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//獲取相關信息(主要是緩衝區大小)
	GetConsoleScreenBufferInfo(handle, &info);
	initialize_();
	_mkdir("d://SnakeRecord"); //創建目錄

	CONSOLE_CURSOR_INFO cursor;           //光標結構 
	cursor.dwSize = 10;
	cursor.bVisible = 0;                  //0爲隱藏光標
	SetConsoleCursorInfo(handle, &cursor);//設置隱藏光標函數 

	//csnake.ShowMenu();
	HHOOK hook;
	MSG msg;
	//相應的鉤子有相應的過程函數MSDN中可看,安裝鍵盤鉤子 
	hook = SetWindowsHookEx(WH_KEYBOARD_LL, _HookProc, GetModuleHandle(NULL), 0);
	while (1){
		//判斷蛇是否還活着
		Wall();
		if (!snake.state && snake.ID_interface == ID_2){
			//csnake.Die();
			snake.ID_interface = ID_4;
			Frame();
		}
		if (snake.ID_interface == ID_2){
			csnake.StartGame();
			Sleep(snake.rank);
		}
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){//循環接收消息
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	UnhookWindowsHookEx(hook);    //卸載鉤子 
	return 0;
}

//定義鉤子過程(未完成)
LRESULT CALLBACK _HookProc(int message, WPARAM wParam, LPARAM lParam){
	//判斷是否彈起按鍵消息
	if (wParam == WM_KEYUP){
		bool state = true;
		switch (((LPKBDLLHOOKSTRUCT)lParam)->vkCode){//lParam:指向一個結構 
			//按下上鍵
		case VK_UP:
			switch (snake.ID_interface){
			case ID_1:
				snake.Flag = true;
				csnake.ShowMenu();
				snake.Flag = false;
				snake.ID_option = _max(ID_5);
				csnake.ShowMenu();
				break;
			case ID_2:
				if (snake.key != VK_DOWN && snake.key != VK_UP){
					snake.key = VK_UP;
				}
				break;
			case ID_5:
				snake.Flag = true;
				csnake.ShowRank();
				snake.ID_option = _max(ID_3);
				snake.Flag = false;
				csnake.ShowRank();
				break;
			case ID_6:
				snake.Flag = true;
				csnake.ShowRecord();
				snake.ID_option = _max(ID_6);
				snake.Flag = false;
				csnake.ShowRecord();
				break;
			}
			break;
			//按下下鍵
		case VK_DOWN:
			switch (snake.ID_interface){
			case ID_1:
				snake.Flag = true;
				csnake.ShowMenu();
				snake.Flag = false;
				snake.ID_option = _min(ID_5);
				csnake.ShowMenu();
				break;
			case ID_2:
				if (snake.key != VK_UP && snake.key != VK_DOWN){
					snake.key = VK_DOWN;
				}
				break;
			case ID_5:
				snake.Flag = true;
				csnake.ShowRank();
				snake.ID_option = _min(ID_3);
				snake.Flag = false;
				csnake.ShowRank();
				break;
			case ID_6:
				snake.Flag = true;
				csnake.ShowRecord();
				snake.ID_option = _min(ID_6);
				snake.Flag = false;
				csnake.ShowRecord();
				break;
			}
			break;
			//按下左鍵
		case VK_LEFT:
			switch (snake.ID_interface){
			case ID_2:
				if (snake.key != VK_RIGHT && snake.key != VK_LEFT){
					snake.key = VK_LEFT;
				}
				break;
			case ID_3:
				snake.Flag = true;
				csnake.ShowPause();
				snake.ID_option = _max(ID_3);
				snake.Flag = false;
				csnake.ShowPause();
				break;
			case ID_4:
				snake.Flag = true;
				csnake.Die();
				snake.ID_option = _max(ID_2);
				snake.Flag = false;
				csnake.Die();
				break;
			}
			break;
			//按下右鍵
		case VK_RIGHT:
			switch (snake.ID_interface){
			case ID_2:
				if (snake.key != VK_LEFT && snake.key != VK_RIGHT){
					snake.key = VK_RIGHT;
				}
				break;
			case ID_3:
				snake.Flag = true;
				csnake.ShowPause();
				snake.ID_option = _min(ID_3);
				snake.Flag = false;
				csnake.ShowPause();
				break;
			case ID_4:
				snake.Flag = true;
				csnake.Die();
				snake.ID_option = _min(ID_2);
				snake.Flag = false;
				csnake.Die();
				break;
			}
			break;
			//按下空格和回車鍵
		case VK_SPACE:
		case VK_RETURN:
			system("cls");
			switch (snake.ID_interface){
			case ID_1://主菜單界面
				switch (snake.ID_option){
				case ID_1:
					snake.ID_interface = ID_2;//開始遊戲界面ID
					csnake.StartGame();
					break;
				case ID_2:
					snake.ID_interface = ID_5;//等級界面
					snake.ID_option = ID_1;
					Frame();
					//csnake.ShowRank();
					break;
				case ID_3:
					snake.ID_interface = ID_6;//讀取記錄界面
					snake.ID_option = ID_1;
					csnake.ShowRecord();
					break;
				case ID_4:
					snake.ID_interface = ID_7;//英雄榜界面
					csnake.ShowArmory();
					break;
				case ID_5:
					state = false;
					break;
				}
				break;

			case ID_2://遊戲界面
				snake.ID_interface = ID_3;
				snake.ID_option = ID_1;
				Frame();
				//csnake.ShowPause();
				break;

			case ID_3://暫停界面
				switch (snake.ID_option){
				case ID_1:
					snake.ID_interface = ID_2;
					csnake.StartGame();
					break;
				case ID_2:
					csnake.SaveRecord();
					break;
				case ID_3:
					state = false;
					break;
				}
				break;

			case ID_4://死亡界面
				switch (snake.ID_option){
				case ID_1:
					snake.ID_interface = ID_1;
					snake.ID_option = ID_1;
					initialize_();
					csnake.ShowMenu();
					break;
				case ID_2:
					state = false;
					break;
				}
				break;

			case ID_5://等級界面
				switch (snake.ID_option){
				case ID_1:
					snake.rank = first;
					break;
				case ID_2:
					snake.rank = middle;
					break;
				case ID_3:
					snake.rank = high;
					break;
				}
				snake.ID_interface = ID_1;
				snake.ID_option = ID_1;
				csnake.ShowMenu();
				break;

			case ID_6://讀取界面
				size_t id;
				switch (snake.ID_option){
				case ID_1:
					id = 0; break;
				case ID_2:
					id = 1; break;
				case ID_3:
					id = 2; break;
				case ID_4:
					id = 3; break;
				case ID_5:
					id = 4; break;
				}
				//進行讀取文件
				if (snake.ID_option != ID_6&&snake.ID_option != ID_7){
					initialize_();
					if (csnake.Read(id)){
						snake.ID_interface = ID_2;
						csnake.StartGame();
					}
					else snake.ID_interface = ID_6;
				}
				else {
					snake.ID_interface = ID_1;
					snake.ID_option = ID_1;
					csnake.ShowMenu();
				}
				break;

			case ID_7://英雄榜界面
				snake.ID_interface = ID_1;
				snake.ID_option = ID_1;
				csnake.ShowMenu();
				break;
			}
			if (!state){
				COORD cd = { info.srWindow.Right / 4, info.srWindow.Bottom / 5 * 4 };
				SetConsoleCursorPosition(handle, cd);
				exit(0);
			}
			snake.ID_option = ID_1;
			break;
		}
	}
	//消息傳給下個鉤子
	return CallNextHookEx(NULL, message, wParam, lParam);
}

//畫牆函數和調用相應界面(已測試完成)
void Wall(){
	short i;
	COORD coord = { 0, 0 };  //座標結構
	//繪牆
	SetConsoleCursorPosition(handle, coord);
	for (i = 0; i <= info.srWindow.Right; ++i)
		std::cout << "#";

	coord.X = info.srWindow.Right;
	coord.Y = 1;
	for (i = 1; i<info.srWindow.Bottom; ++i){
		SetConsoleCursorPosition(handle, coord);
		std::cout << "#";
		++coord.Y;
	}

	coord.X = 0;
	coord.Y = info.srWindow.Bottom;
	for (i = 1; i <= info.srWindow.Right; ++i){
		SetConsoleCursorPosition(handle, coord);
		std::cout << "#";
		++coord.X;
	}

	coord.X = 0;
	coord.Y = 1;
	for (i = 1; i<info.srWindow.Bottom; ++i){
		SetConsoleCursorPosition(handle, coord);
		std::cout << "#";
		++coord.Y;
	}
	//判斷所在界面顯示相關界面的菜單選項及其它
	int j = info.srWindow.Right / 4;
	switch (snake.ID_interface){
	case ID_1:
		csnake.ShowMenu();
		coord.X = j;
		coord.Y = info.srWindow.Bottom - 6;
		SetConsoleCursorPosition(handle, coord);
		std::cout << "o(-\"-)o  貪  #^_^#  喫  →_→  蛇  \\(^o^)/";
		break;//顯示菜單選項

	case ID_2:
	case ID_3:
	case ID_4:
		//繪輸出信息框
		coord.X = 1;
		coord.Y = info.srWindow.Bottom - 5;
		SetConsoleCursorPosition(handle, coord);
		for (i = 1; i<info.srWindow.Right; std::cout << "#", ++i);
		for (coord.X = j; coord.X <= info.srWindow.Right - j; coord.X += j){
			coord.Y = info.srWindow.Bottom - 5;
			for (i = coord.Y; i<info.srWindow.Bottom; ++i){
				SetConsoleCursorPosition(handle, coord);
				std::cout << "#";
				++coord.Y;
			}
		}
		//輸出每個框的信息
		coord.X = 2;
		coord.Y -= 4;
		SetConsoleCursorPosition(handle, coord);
		std::cout << "遊戲難度:";
		coord.Y += 2;
		SetConsoleCursorPosition(handle, coord);
		std::cout << "\t   ";
		switch (snake.rank){
		case first:
			std::cout << "初 級"; break;
		case middle:
			std::cout << "中 級"; break;
		case high:
			std::cout << "高 級"; break;
		}
		//當前分數
		coord.X += j;
		coord.Y -= 2;
		SetConsoleCursorPosition(handle, coord);
		std::cout << "  當 前 分 數";
		coord.X += j / 2 - 3;
		coord.Y += 2;
		SetConsoleCursorPosition(handle, coord);
		std::cout << snake.mark;
		//操作說明
		coord.X = j * 2 + 1;
		coord.Y = info.srWindow.Bottom - 4;
		SetConsoleCursorPosition(handle, coord);
		std::cout << " 操作說明: ";
		coord.Y += 2;
		SetConsoleCursorPosition(handle, coord);
		std::cout << "  ↑ ↓ ←  →";
		++coord.Y;
		SetConsoleCursorPosition(handle, coord);
		std::cout << " 空格: 暫停遊戲";
		//製作人
		coord.X += j;
		SetConsoleCursorPosition(handle, coord);
		std::cout << "\t製作人: _ 翼";
		break;

	case ID_5:
		csnake.ShowRank(); break;//顯示遊戲等級

	case ID_6:
		csnake.ShowRecord(); break;//顯示存檔記錄

	case ID_7:
		csnake.ShowArmory(); break;//顯示英雄榜
	}

}

//畫框函數(完成)
void Frame(){
	COORD coord = { 0, info.srWindow.Bottom / 3 };
	SetConsoleCursorPosition(handle, coord);
	for (short i = 0; i <= info.srWindow.Right; std::cout << "-", ++i);

	coord.Y = info.srWindow.Bottom / 3 * 2;
	SetConsoleCursorPosition(handle, coord);
	for (short i = 0; i <= info.srWindow.Right; std::cout << "-", ++i);

	switch (snake.ID_interface){
	case ID_3:
		csnake.ShowPause(); break;//顯示暫停菜單
	case ID_4:
		csnake.Die(); break;//顯示死亡界面菜單
	case ID_5:
		csnake.ShowRank(); break;//顯示等級選項
	}
}

//初始化蛇數據(完成)
void initialize_(){
	snake.state = true; //蛇狀態
	snake.Snake_size = 5; //蛇初始化長度
	//初始化蛇位置
	COORD cd;
	cd.Y = 3;
	snake.Snake_coord.clear();
	for (size_t i = 10; i>5; --i){
		cd.X = i;
		snake.Snake_coord.push_back(cd);
	}
	snake.food_coord.X = 0;
	snake.food_coord.Y = 0;
	snake.rank = first;   //默認等級
	snake.mark = 0; //分數
	snake.key = VK_RIGHT;
	snake.ID_interface = ID_1;//界面標記
	snake.ID_option = ID_1;   //選項標記
	snake.Flag = false;
}

 

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