目錄
(2)void srand(unsigned int seed);
(1)HANDLE GetStdHandle( DWORD nStdHandle );
(3)SetConsoleCursorPosition(HANDLE ,coord);
(1)time_t time(time_t * timer)
前言:程序包下載
下載方式一:CSDN下載:https://download.csdn.net/download/qq_38351824/12142282
下載方式二:微信公衆號 ① 關注Tech雲 ② 暫不提供下載鏈接
下載方式三:文章下評論
一、涉及C語言知識點
數組、結構體、全局變量、局部變量、宏定義、條件語句、循環語句
二、貪喫蛇相關庫函數及其頭文件簡介:
1、#include<stdio.h>
(1)void fflush(stdin)
① 簡介
清空輸入緩衝區,通常是爲了確保不影響後面的數據讀取(例如在讀完一個字符串後緊接着又要讀取一個字符,此時應該先執行 fflush(stdin);
② 語法
int fflush(FILE *stream)
(2)CONSOLE_CURSOR_INFO
① 簡介
包含有關控制檯光標的信息。
② 語法
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
③ 參數
dwSize:光標填充的字符單元格的百分比。該值介於1和100之間。光標外觀會發生變化,從完全填充單元格到顯示爲單元格底部的水平線。
bVisible:光標的可見性。如果光標可見,則此成員爲TRUE。
(3)GetConsoleCursorInfo
① 簡介
獲取有關指定控制檯屏幕緩衝區的光標大小和可見性的信息。
② 語法
BOOL WINAPI GetConsoleCursorInfo(
_In_ HANDLE hConsoleOutput,
_Out_ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
);
③ 參數
參數:
- hConsoleOutput 控制檯屏幕緩衝區的句柄。句柄必須具有GENERIC_READ訪問權限。
- lpConsoleCursorInfo 指向CONSOLE_CURSOR_INFO結構的指針,該結構接收有關控制檯遊標的信息。
返回值:
- 如果函數成功,則返回值爲非零值。
- 如果函數失敗,則返回值爲零。
(4)SetConsoleCursorInfo
① 簡介
設置指定控制檯屏幕緩衝區的光標大小和可見性。
② 語法
BOOL WINAPI SetConsoleCursorInfo(
_In_ HANDLE hConsoleOutput,
_In_ const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);
③ 參數
參數:
- hConsoleOutput 控制檯屏幕緩衝區的句柄。句柄必須具有GENERIC_READ訪問權限。
- lpConsoleCursorInfo 指向CONSOLE_CURSOR_INFO結構的指針,該結構爲控制檯屏幕緩衝區的遊標提供新規範。
返回值:
- 如果函數成功,則返回值爲非零值。
- 如果函數失敗,則返回值爲零。
2、#include<stdlib.h>
(1)rand()
① 簡介
rand()函數產生隨機數的一個隨機函數。
② 語法
rand()
③ 參數
若要生成 a 與 b 之間的隨機實數,應使用: RAND()*(b-a)+a
(2)void srand(unsigned int seed);
① 簡介
srand函數是隨機數發生器的初始化函數。
② 語法
void srand(unsigned int seed);
③ 參數
unsigned seed:隨機數產生器的初始值(種子值)。
3、#include<conio.h>
(1)int kbhit(void);
① 簡介
用於非阻塞地響應鍵盤輸入事件。
② 語法
int kbhit(void);
③ 參數
功能及返回值: 檢查當前是否有鍵盤輸入,若有則返回一個非0值,否則返回0。
(2)int getch(void)
① 簡介
一個不回顯函數,當用戶按下某個字符時,函數自動讀取,無需按回車,有的C語言命令行程序會用到此函數做遊戲
② 語法
int getch(void)
③ 參數
返回值:讀取的字符
4、#include<windows.h>
(1)HANDLE GetStdHandle( DWORD nStdHandle );
① 簡介
GetStdHandle是一個Windows API函數。它用於從一個特定的標準設備(標準輸入、標準輸出或標準錯誤)中取得一個句柄(用來標識不同設備的數值)。
② 語法
HANDLE GetStdHandle( DWORD nStdHandle );
GetStdHandle()返回標準的輸入、輸出或錯誤的設備的句柄,也就是獲得輸入、輸出/錯誤的屏幕緩衝區的句柄。
③ 參數
值 |
含義 |
---|---|
STD_INPUT_HANDLE |
標準輸入的句柄 |
STD_OUTPUT_HANDLE |
標準輸出的句柄 |
STD_ERROR_HANDLE |
標準錯誤的句柄 |
(2)COORD coord={x,y};
① 簡介
COORD是Windows API中定義的一種結構,表示一個字符在控制檯屏幕上的座標。
② 語法
typedef struct _COORD {
SHORT X; 水平座標
SHORT Y; 垂直座標
} COORD;
③ 參數
SHORT 爲一種數據類型,範圍-32768~+32767。
SHORT X; 水平座標
SHORT Y; 垂直座標
(3)SetConsoleCursorPosition(HANDLE ,coord);
① 簡介
SetConsoleCursorPosition是API中定位光標位置的函數。
② 語法
SetConsoleCursorPosition(HANDLE ,coord); 設置控制檯光標座標(設備句柄, 光標座標)
③ 參數
使用這個函數需要兩個參數:第一個參數類型爲HANDLE,第二個參數類型爲COORD
5、#include<time.h>
(1)time_t time(time_t * timer)
① 簡介
獲取當前的系統時間,返回的結果是一個time_t類型
② 語法
time_t time(time_t * timer)
③ 參數
獲取當前時間:NULL。
返回的結果是一個time_t類型,其實就是一個大整數。
三、貪喫蛇相關子函數
1、光標移動到 (X,Y)
光標移動 到 (X,Y)
void gotoxy(int x, int y)
{
COORD coord={x,y}; 初始化結構體coord (座標系X,Y)
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 獲取輸出屏幕緩衝區句柄
SetConsoleCursorPosition(handle, coord); 移動光標
}
2、畫牆體、蛇、食物
//畫牆體、蛇、食物
//卍 ※ 代表牆體
//♂ 代表蛇體
//♀ 代表食物
void drawMap(void)
{
//畫 --- 遊戲說明
gotoxy(100, 7);
printf("按鍵說明:");
gotoxy(100, 10);
printf("W:向上");
gotoxy(100, 13);
printf("A:向左");
gotoxy(100, 16);
printf("S:向下");
gotoxy(100, 19);
printf("D:向右");
gotoxy(100,22);
printf("當前分數:%d",score);
//畫 --- 貪喫蛇牆體
// 畫左右兩面牆
for (int i = 0; i <= MAP_HIGHTH; i++) {
gotoxy(0,i);
printf("※");
gotoxy(MAP_WIDTH,i);
printf("※");
Sleep(20);
}
// 畫上下兩面牆
for (int i = 0; i <= MAP_WIDTH; i += 2) {
gotoxy(i, 0);
printf("卍");
gotoxy(MAP_WIDTH-i, MAP_HIGHTH);
printf("卍");
Sleep(20);
}
//畫 --- 蛇身
snake.len = SNAKE_BEGIN_LEN; // 賦值剛開始的蛇身長度
srand((unsigned)time(NULL)); // 防止僞隨機數
do {
snake.x[0] = rand() % (MAP_WIDTH/2 ) + MAP_WIDTH/4;
snake.y[0] = rand() % (MAP_HIGHTH/2 ) + MAP_HIGHTH/4;
} while (snake.x[0] % 2 != 0); // 隨機出現蛇頭,保證蛇頭在地圖中間範圍內,而不在牆體上 ,並且符合蛇是偶數的要求
gotoxy(snake.x[0], snake.y[0]);// 光標移動到蛇頭的位置
printf("♂"); // 打印蛇頭
for (int i = 1; i < snake.len; i++) {// 打印蛇身
snake.x[i] = snake.x[0];
snake.y[i] = snake.y[0] + 1;
gotoxy(snake.x[i], snake.y[i]);
printf("♂");
}
do {
food.x = rand() % (MAP_WIDTH - 4) + 2;
food.y = rand() % (MAP_HIGHTH - 2) + 1;
} while (food.x % 2 != 0); // 隨機出現食物,保證食物不在牆體上,並且符合食物是偶數的要求
gotoxy(food.x, food.y); // 光標移動到食物的位置
printf("♀"); // 打印食物
}
3、按鍵操作
//按鍵操作
void keyDown(void)
{
//按鍵的處理
if (_kbhit()) // 檢查當前是否有鍵盤輸入
{
fflush(stdin); // 清空輸入緩衝區,讀完一個字符串後緊接着又要讀取一個字符,此時應該先執行該函數
key = _getch(); // 一個不回顯函數,當用戶按下某個字符時,函數自動讀取,無需按回車
//這一大段代碼是爲了防止回頭自殺的情況發生,如果用戶輸入反方向或者非wasd鍵,key的值不會改變
if (key != 'w' && key != 'W' && key != 's' && key != 'S' && key != 'A' && key != 'a' && key != 'd' && key != 'D')
key = tempkey; // 如果用戶輸入非wasd鍵,key的值不會改變
else { // 如果用戶輸入反方向,key的值不會改變
if (tempkey == 'w' || tempkey == 'W')
if (key == 's' || key == 'S')
key = tempkey;
if (tempkey == 's' || tempkey == 'S')
if (key == 'w' || key == 'W')
key = tempkey;
if (tempkey == 'a' || tempkey == 'A')
if (key == 'D' || key == 'd')
key = tempkey;
if (tempkey == 'D' || tempkey == 'd')
if (key == 'a' || key == 'A')
key = tempkey;
tempkey = key;
}
}
if (!changeflag)// 如果蛇沒喫東西,蛇尾就空了 ,擦除尾巴
{
gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
printf(" ");
}
else { // 蛇吃了一個食物,變長了
snake.x[snake.len] = snake.x[snake.len - 1];
snake.y[snake.len] = snake.y[snake.len - 1];
snake.len++;
}
for (int i = snake.len-1; i>0; i--) { // 後面一個的蛇身,替換前面的一個 ,蛇頭變成食物的位置
snake.x[i] = snake.x[i - 1];
snake.y[i] = snake.y[i - 1];
}
switch (key) {// 判斷按鍵數據
case 'w':
case 'W':
snake.y[0]--;
break;
case 's':
case 'S':
snake.y[0]++;
break;
case 'a':
case 'A':
snake.x[0] -= 2;
break;
case 'd':
case 'D':
snake.x[0] += 2;
break;
}
gotoxy(snake.x[0], snake.y[0]); // 改變頭的方向
printf("♂");
changeflag =false; // 清空標誌位
}
4、食物刷新
//食物的刷新
void createFood(void)
{
if (snake.x[0] == food.x&&snake.y[0] == food.y) {// 如果食物被吃了
score++; // 分數 +1
gotoxy(100, 22);
printf("當前分數:%d", score);
srand((unsigned)time(NULL));
while (1)
{
bool flag = true;
food.x = rand() % (MAP_WIDTH - 4) + 2; // 隨機產生食物 ,不在牆體上
food.y = rand() % (MAP_HIGHTH - 2) + 1;
for (int k = 0; k < snake.len; k++) // 判斷食物不在貪喫蛇身上
{
if (snake.x[k] == food.x&&snake.y[k] == food.y)
{
flag = false;
break;
}
}
if (flag&&food.x % 2 == 0)// 食物合不合適標記 --- 蛇喫不到
break;
}
gotoxy(food.x, food.y);
printf("♂");
changeflag = true; // 吃了食物,表示蛇長度有變化,標誌位
}
}
5、蛇的狀態
//蛇的狀態
bool snakeStatus(void)
{
if (snake.x[0] == 0 || snake.x[0] == MAP_WIDTH || snake.y[0] == 0 || snake.y[0] == MAP_HIGHTH)
return false; // 如果蛇在牆上,宣佈死亡
for (int i = 1; i < snake.len; i++)
if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
return false;// 如果蛇自己吃了自己,宣佈死亡
return true;
}
6、開始遊戲
void playGame(void)
{
key = 'w';
score = 0;
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取輸出屏幕緩衝區句柄
CONSOLE_CURSOR_INFO cci; // 初始化結構體cci
GetConsoleCursorInfo(hOut, &cci); // 獲取有關指定控制檯屏幕緩衝區的光標大小和可見性的信息。
cci.bVisible = FALSE; // 光標的不可見
SetConsoleCursorInfo(hOut, &cci); //設置指定控制檯屏幕緩衝區的光標大小和可見性。
system("CLS");
drawMap(); //畫牆體、蛇、食物
while (1) {
keyDown();//按鍵操作
Sleep(snake.speed); // 蛇的速度設定
createFood();//食物的刷新
if (!snakeStatus())//蛇的狀態
break;
}
system("CLS");
gotoxy(50, 8);
printf("——遊戲結束——");
gotoxy(52, 10);
printf("你的分數爲%d", score);
gotoxy(53, 13);
printf("再來一次");
gotoxy(53, 16);
printf("退出遊戲");
gotoxy(53, 19);
printf("回主菜單");
while (1) {
while (1) {
if (_kbhit()) {// 檢查當前是否有鍵盤輸入
key3 = _getch();// 獲取鍵值
if (0 == key3 || 0xE0 == key3)
key3 = key3 << 8 | _getch();
}
else break;
}
switch (flag3) {
case 0:
gotoxy(51, 13);
printf("→");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf(" ");
key3 = _getch();// 獲取鍵值
if (key3 == 13) // 確定
playGame(); // 開始遊戲
break;
case 1:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf("→");
gotoxy(51, 19);
printf(" ");
key3 = _getch();// 獲取鍵值
if (key3 == 13) // 確定
exit(0); // 退出
break;
case 2:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf("→");
key3 = _getch(); // 獲取鍵值
if (key3 == 13) // 確定
main(); // 回到主菜單
break;
}
switch (key3) { // 獲取鍵值
case 's':
case 'S':
if (flag3 < 2)
flag3++;
break;
case 'W':
case 'w':
if (flag3 > 0)
flag3--;
break;
}
}
}
7、難度選擇
void settingMeau(void)
{
system("CLS");
gotoxy(50, 8);
printf("——遊戲難度——");
gotoxy(53, 13);
printf("地獄");
gotoxy(53, 15);
printf("狂暴");
gotoxy(53, 17);
printf("正常");
gotoxy(53, 19);
printf("平和");
gotoxy(53, 23);
printf("返回菜單");
switch (setflag) {
case 0:
gotoxy(58, 13);
printf("←");
break;
case 1:
gotoxy(58, 15);
printf("←");
break;
case 2:
gotoxy(58, 17);
printf("←");
break;
case 3:
gotoxy(58, 19);
printf("←");
break;
}
while (1) {
switch (flag2) {
case 0:
gotoxy(51, 13);
printf("→");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 60;
setflag = 0;
gotoxy(58, 13);
printf("→");
gotoxy(58, 15);
printf(" ");
gotoxy(58, 17);
printf(" ");
gotoxy(58, 19);
printf(" ");
}
break;
case 1:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf("→");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 100;
setflag = 1;
gotoxy(58, 13);
printf(" ");
gotoxy(58, 15);
printf("→");
gotoxy(58, 17);
printf(" ");
gotoxy(58, 19);
printf(" ");
}
break;
case 2:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf("→");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 200;
setflag = 2;
gotoxy(58, 13);
printf(" ");
gotoxy(58, 15);
printf(" ");
gotoxy(58, 17);
printf("→");
gotoxy(58, 19);
printf(" ");
}
break;
case 3:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf("→");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 300;
setflag = 3;
gotoxy(58, 13);
printf(" ");
gotoxy(58, 15);
printf(" ");
gotoxy(58, 17);
printf(" ");
gotoxy(58, 19);
printf("→");
}
break;
case 4:gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf("→");
key4 = _getch();// 獲取鍵值
if (key4 == 13) // 確定
main(); // 回到主菜單
}
switch (key4) { // 獲取鍵值
case 's':
case 'S':
if (flag2 < 4)
flag2++;
break;
case 'W':
case 'w':
if (flag2 > 0)
flag2--;
break;
}
}
}
8、主菜單
void meau(void)
{
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取輸出屏幕緩衝區句柄
CONSOLE_CURSOR_INFO cci; // 初始化結構體cci
GetConsoleCursorInfo(hOut, &cci); // 獲取有關指定控制檯屏幕緩衝區的光標大小和可見性的信息。
cci.bVisible = FALSE; // 光標的不可見
SetConsoleCursorInfo(hOut, &cci); //設置指定控制檯屏幕緩衝區的光標大小和可見性。
system("CLS"); // 調用系統命令cls完成清屏操作
gotoxy(50, 8);
printf("——貪喫蛇——");
gotoxy(53, 13);
printf("開始遊戲");
gotoxy(53, 16);
printf("遊戲難度");
gotoxy(53, 19);
printf("退出遊戲");
gotoxy(44, 22);
printf("※ ※ CSDN:Sumjess ※ ※");
gotoxy(43, 25);
printf("※ ※ 公衆號 :Tech雲 ※ ※");
while (1) {
switch (flag) {
case 0:
gotoxy(51, 13);
printf("→");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf(" ");
key2 = _getch();// 獲取鍵值
if (key2 == 13) // 如果是確定
playGame(); // 進入遊戲
break;
case 1:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf("→");
gotoxy(51, 19);
printf(" ");
key2 = _getch();// 獲取鍵值
if (key2 == 13) // 如果是確定
settingMeau();// 進入難度設定
break;
case 2:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf("→");
key2 = _getch();// 獲取鍵值
if (key2 == 13) // 如果是確定
exit(0); // 退出
break;
}
switch (key2) {// 獲取鍵值
case 's':
case 'S':
if (flag < 2)
flag++;
break;
case 'W':
case 'w':
if (flag > 0)
flag--;
break;
}
}
}
9、主函數
int main(void)
{
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取輸出屏幕緩衝區句柄
CONSOLE_CURSOR_INFO cci; // 初始化結構體cci
GetConsoleCursorInfo(hOut, &cci); // 獲取有關指定控制檯屏幕緩衝區的光標大小和可見性的信息。
cci.bVisible = FALSE; // 光標的不可見
SetConsoleCursorInfo(hOut, &cci); //設置指定控制檯屏幕緩衝區的光標大小和可見性。
meau();
}
四、項目代碼
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<windows.h>
#include<time.h>
//輔助宏定義
#define GAME_H
#define MAP_HIGHTH 29 //地圖高度
#define MAP_WIDTH 90 //地圖寬度
#define SNAKE_MAX_LEN 1000 //蛇的最大長度
#define SNAKE_BEGIN_LEN 3 //蛇的初始長度
//數據設計
//蛇結構體
struct
{
int x[SNAKE_MAX_LEN];
int y[SNAKE_MAX_LEN];
int len;
int speed=150;
}snake;
//食物結構體
struct
{
int x;
int y;
}food;
//其他全局變量
char key = 'w';
char key2; //key2代表在初始菜單界面的鍵盤輸入
char key3; //key3代表在遊戲結束後菜單的鍵盤輸入
char key4; //key4代表在遊戲難度內的菜單的鍵盤輸入
int tempkey = 'w'; //這裏的tempkey是爲了防止貪喫蛇回頭自殺而設定的,詳細見keyDown()函數
bool changeflag = 0;
int flag = 0; //這三個flag是爲了反映按下w與s鍵後的狀態,詳細請看下面代碼
int flag2 = 0;
int flag3 = 0;
int setflag = 2; //這個setflag是爲了記錄遊戲難度裏選擇難度後再難度後面打印◇
int score = 0; //記錄分數
//函數模塊設計
//畫地圖
void drawMap(void);
//按鍵操作
void keyDown(void);
//食物的刷新
void createFood(void);
//蛇的狀態
bool snakeStatus(void);
//光標移動
void gotoxy(int x, int y);
void playGame(void);
void meau(void);
void settingMeau(void);
int main(void)
{
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取輸出屏幕緩衝區句柄
CONSOLE_CURSOR_INFO cci; // 初始化結構體cci
GetConsoleCursorInfo(hOut, &cci); // 獲取有關指定控制檯屏幕緩衝區的光標大小和可見性的信息。
cci.bVisible = FALSE; // 光標的不可見
SetConsoleCursorInfo(hOut, &cci); //設置指定控制檯屏幕緩衝區的光標大小和可見性。
meau(); // 主菜單
}
void meau(void)
{
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取輸出屏幕緩衝區句柄
CONSOLE_CURSOR_INFO cci; // 初始化結構體cci
GetConsoleCursorInfo(hOut, &cci); // 獲取有關指定控制檯屏幕緩衝區的光標大小和可見性的信息。
cci.bVisible = FALSE; // 光標的不可見
SetConsoleCursorInfo(hOut, &cci); //設置指定控制檯屏幕緩衝區的光標大小和可見性。
system("CLS"); // 調用系統命令cls完成清屏操作
gotoxy(50, 8);
printf("——貪喫蛇——");
gotoxy(53, 13);
printf("開始遊戲");
gotoxy(53, 16);
printf("遊戲難度");
gotoxy(53, 19);
printf("退出遊戲");
gotoxy(44, 22);
printf("※ ※ CSDN:Sumjess ※ ※");
gotoxy(43, 25);
printf("※ ※ 公衆號 :Tech雲 ※ ※");
while (1) {
switch (flag) {
case 0:
gotoxy(51, 13);
printf("→");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf(" ");
key2 = _getch();// 獲取鍵值
if (key2 == 13) // 如果是確定
playGame(); // 進入遊戲
break;
case 1:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf("→");
gotoxy(51, 19);
printf(" ");
key2 = _getch();// 獲取鍵值
if (key2 == 13) // 如果是確定
settingMeau();// 進入難度設定
break;
case 2:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf("→");
key2 = _getch();// 獲取鍵值
if (key2 == 13) // 如果是確定
exit(0); // 退出
break;
}
switch (key2) {// 獲取鍵值
case 's':
case 'S':
if (flag < 2)
flag++;
break;
case 'W':
case 'w':
if (flag > 0)
flag--;
break;
}
}
}
void settingMeau(void)
{
system("CLS");
gotoxy(50, 8);
printf("——遊戲難度——");
gotoxy(53, 13);
printf("地獄");
gotoxy(53, 15);
printf("狂暴");
gotoxy(53, 17);
printf("正常");
gotoxy(53, 19);
printf("平和");
gotoxy(53, 23);
printf("返回菜單");
switch (setflag) {
case 0:
gotoxy(58, 13);
printf("←");
break;
case 1:
gotoxy(58, 15);
printf("←");
break;
case 2:
gotoxy(58, 17);
printf("←");
break;
case 3:
gotoxy(58, 19);
printf("←");
break;
}
while (1) {
switch (flag2) {
case 0:
gotoxy(51, 13);
printf("→");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 60;
setflag = 0;
gotoxy(58, 13);
printf("→");
gotoxy(58, 15);
printf(" ");
gotoxy(58, 17);
printf(" ");
gotoxy(58, 19);
printf(" ");
}
break;
case 1:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf("→");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 100;
setflag = 1;
gotoxy(58, 13);
printf(" ");
gotoxy(58, 15);
printf("→");
gotoxy(58, 17);
printf(" ");
gotoxy(58, 19);
printf(" ");
}
break;
case 2:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf("→");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 200;
setflag = 2;
gotoxy(58, 13);
printf(" ");
gotoxy(58, 15);
printf(" ");
gotoxy(58, 17);
printf("→");
gotoxy(58, 19);
printf(" ");
}
break;
case 3:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf("→");
gotoxy(52, 23);
printf(" ");
key4 = _getch();
if (key4 == 13) {
snake.speed = 300;
setflag = 3;
gotoxy(58, 13);
printf(" ");
gotoxy(58, 15);
printf(" ");
gotoxy(58, 17);
printf(" ");
gotoxy(58, 19);
printf("→");
}
break;
case 4:gotoxy(51, 13);
printf(" ");
gotoxy(51, 15);
printf(" ");
gotoxy(51, 17);
printf(" ");
gotoxy(51, 19);
printf(" ");
gotoxy(52, 23);
printf("→");
key4 = _getch();// 獲取鍵值
if (key4 == 13) // 確定
main(); // 回到主菜單
}
switch (key4) { // 獲取鍵值
case 's':
case 'S':
if (flag2 < 4)
flag2++;
break;
case 'W':
case 'w':
if (flag2 > 0)
flag2--;
break;
}
}
}
void playGame(void)
{
key = 'w';
score = 0;
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取輸出屏幕緩衝區句柄
CONSOLE_CURSOR_INFO cci; // 初始化結構體cci
GetConsoleCursorInfo(hOut, &cci); // 獲取有關指定控制檯屏幕緩衝區的光標大小和可見性的信息。
cci.bVisible = FALSE; // 光標的不可見
SetConsoleCursorInfo(hOut, &cci); //設置指定控制檯屏幕緩衝區的光標大小和可見性。
system("CLS");
drawMap(); //畫牆體、蛇、食物
while (1) {
keyDown();//按鍵操作
Sleep(snake.speed); // 蛇的速度設定
createFood();//食物的刷新
if (!snakeStatus())//蛇的狀態
break;
}
system("CLS");
gotoxy(50, 8);
printf("——遊戲結束——");
gotoxy(52, 10);
printf("你的分數爲%d", score);
gotoxy(53, 13);
printf("再來一次");
gotoxy(53, 16);
printf("退出遊戲");
gotoxy(53, 19);
printf("回主菜單");
while (1) {
while (1) {
if (_kbhit()) {// 檢查當前是否有鍵盤輸入
key3 = _getch();// 獲取鍵值
if (0 == key3 || 0xE0 == key3)
key3 = key3 << 8 | _getch();
}
else break;
}
switch (flag3) {
case 0:
gotoxy(51, 13);
printf("→");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf(" ");
key3 = _getch();// 獲取鍵值
if (key3 == 13) // 確定
playGame(); // 開始遊戲
break;
case 1:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf("→");
gotoxy(51, 19);
printf(" ");
key3 = _getch();// 獲取鍵值
if (key3 == 13) // 確定
exit(0); // 退出
break;
case 2:
gotoxy(51, 13);
printf(" ");
gotoxy(51, 16);
printf(" ");
gotoxy(51, 19);
printf("→");
key3 = _getch(); // 獲取鍵值
if (key3 == 13) // 確定
main(); // 回到主菜單
break;
}
switch (key3) { // 獲取鍵值
case 's':
case 'S':
if (flag3 < 2)
flag3++;
break;
case 'W':
case 'w':
if (flag3 > 0)
flag3--;
break;
}
}
}
//畫牆體、蛇、食物
//卍 ※ 代表牆體
//♂ 代表蛇體
//♀ 代表食物
void drawMap(void)
{
//畫 --- 遊戲說明
gotoxy(100, 7);
printf("按鍵說明:");
gotoxy(100, 10);
printf("W:向上");
gotoxy(100, 13);
printf("A:向左");
gotoxy(100, 16);
printf("S:向下");
gotoxy(100, 19);
printf("D:向右");
gotoxy(100,22);
printf("當前分數:%d",score);
gotoxy(98, 25);
printf("※CSDN:Sumjess ※");
gotoxy(97, 28);
printf("※公衆號 :Tech雲 ※");
//畫 --- 貪喫蛇牆體
// 畫左右兩面牆
for (int i = 0; i <= MAP_HIGHTH; i++) {
gotoxy(0,i);
printf("※");
gotoxy(MAP_WIDTH,i);
printf("※");
Sleep(20);
}
// 畫上下兩面牆
for (int i = 0; i <= MAP_WIDTH; i += 2) {
gotoxy(i, 0);
printf("卍");
gotoxy(MAP_WIDTH-i, MAP_HIGHTH);
printf("卍");
Sleep(20);
}
//畫 --- 蛇身
snake.len = SNAKE_BEGIN_LEN; // 賦值剛開始的蛇身長度
srand((unsigned)time(NULL)); // 防止僞隨機數
do {
snake.x[0] = rand() % (MAP_WIDTH/2 ) + MAP_WIDTH/4;
snake.y[0] = rand() % (MAP_HIGHTH/2 ) + MAP_HIGHTH/4;
} while (snake.x[0] % 2 != 0); // 隨機出現蛇頭,保證蛇頭在地圖中間範圍內,而不在牆體上 ,並且符合蛇是偶數的要求
gotoxy(snake.x[0], snake.y[0]);// 光標移動到蛇頭的位置
printf("♂"); // 打印蛇頭
for (int i = 1; i < snake.len; i++) {// 打印蛇身
snake.x[i] = snake.x[0];
snake.y[i] = snake.y[0] + 1;
gotoxy(snake.x[i], snake.y[i]);
printf("♂");
}
do {
food.x = rand() % (MAP_WIDTH - 4) + 2;
food.y = rand() % (MAP_HIGHTH - 2) + 1;
} while (food.x % 2 != 0); // 隨機出現食物,保證食物不在牆體上,並且符合食物是偶數的要求
gotoxy(food.x, food.y); // 光標移動到食物的位置
printf("♀"); // 打印食物
}
//按鍵操作
void keyDown(void)
{
//按鍵的處理
if (_kbhit()) // 檢查當前是否有鍵盤輸入
{
fflush(stdin); // 清空輸入緩衝區,讀完一個字符串後緊接着又要讀取一個字符,此時應該先執行該函數
key = _getch(); // 一個不回顯函數,當用戶按下某個字符時,函數自動讀取,無需按回車
//這一大段代碼是爲了防止回頭自殺的情況發生,如果用戶輸入反方向或者非wasd鍵,key的值不會改變
if (key != 'w' && key != 'W' && key != 's' && key != 'S' && key != 'A' && key != 'a' && key != 'd' && key != 'D')
key = tempkey; // 如果用戶輸入非wasd鍵,key的值不會改變
else { // 如果用戶輸入反方向,key的值不會改變
if (tempkey == 'w' || tempkey == 'W')
if (key == 's' || key == 'S')
key = tempkey;
if (tempkey == 's' || tempkey == 'S')
if (key == 'w' || key == 'W')
key = tempkey;
if (tempkey == 'a' || tempkey == 'A')
if (key == 'D' || key == 'd')
key = tempkey;
if (tempkey == 'D' || tempkey == 'd')
if (key == 'a' || key == 'A')
key = tempkey;
tempkey = key;
}
}
if (!changeflag)// 如果蛇沒喫東西,蛇尾就空了 ,擦除尾巴
{
gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
printf(" ");
}
else { // 蛇吃了一個食物,變長了
snake.x[snake.len] = snake.x[snake.len - 1];
snake.y[snake.len] = snake.y[snake.len - 1];
snake.len++;
}
for (int i = snake.len-1; i>0; i--) { // 後面一個的蛇身,替換前面的一個 ,蛇頭變成食物的位置
snake.x[i] = snake.x[i - 1];
snake.y[i] = snake.y[i - 1];
}
switch (key) {// 判斷按鍵數據
case 'w':
case 'W':
snake.y[0]--;
break;
case 's':
case 'S':
snake.y[0]++;
break;
case 'a':
case 'A':
snake.x[0] -= 2;
break;
case 'd':
case 'D':
snake.x[0] += 2;
break;
}
gotoxy(snake.x[0], snake.y[0]); // 改變頭的方向
printf("♂");
changeflag =false; // 清空標誌位
}
//食物的刷新
void createFood(void)
{
if (snake.x[0] == food.x&&snake.y[0] == food.y) {// 如果食物被吃了
score++; // 分數 +1
gotoxy(100, 22);
printf("當前分數:%d", score);
srand((unsigned)time(NULL));
while (1)
{
bool flag = true;
food.x = rand() % (MAP_WIDTH - 4) + 2; // 隨機產生食物 ,不在牆體上
food.y = rand() % (MAP_HIGHTH - 2) + 1;
for (int k = 0; k < snake.len; k++) // 判斷食物不在貪喫蛇身上
{
if (snake.x[k] == food.x&&snake.y[k] == food.y)
{
flag = false;
break;
}
}
if (flag&&food.x % 2 == 0)// 食物合不合適標記 --- 蛇喫不到
break;
}
gotoxy(food.x, food.y);
printf("♂");
changeflag = true; // 吃了食物,表示蛇長度有變化,標誌位
}
}
//蛇的狀態
bool snakeStatus(void)
{
if (snake.x[0] == 0 || snake.x[0] == MAP_WIDTH || snake.y[0] == 0 || snake.y[0] == MAP_HIGHTH)
return false; // 如果蛇在牆上,宣佈死亡
for (int i = 1; i < snake.len; i++)
if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
return false;// 如果蛇自己吃了自己,宣佈死亡
return true;
}
//光標移動 到 (X,Y)
void gotoxy(int x, int y)
{
COORD coord={x,y}; // 初始化結構體coord (座標系X,Y)
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取輸出屏幕緩衝區句柄
SetConsoleCursorPosition(handle, coord); // 移動光標
}