游戲介紹
有一條蛇,在螢屏上爬,用上下左右鍵控制吃東西,吃得多了,到了一定積分,就能過關,越吃越長,不能碰墻,不能咬自己的尾巴,沒了,哈哈,
這個蛇是條很有個性的蛇它會吃多少吐多少(如果要取消這個特性可以在代碼中修改一行代碼即可,我已經標注出來了)
話不多說直接上代碼(代碼中有詳細注釋)!
可以直接運行的:
//本來我是想用C語言實作的無奈水平有限,只能在C++下執行了,注意: 這里使用的字符集為Unicode
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#define MY_BUFSIZE 1024 //控制臺視窗標題的緩沖區大小
#define INITIALTIME 200
//蛇的狀態(上,下,左,右)
#define U 1
#define D 2
#define L 3
#define R 4
typedef struct Snake
{
int x; //節點的x坐標
int y; //節點的y坐標
struct Snake* next; //蛇身的下一個節點
}snake;
int score = 0, add = 0; //總得分與每次吃食物的得分
int HighScore = 0; //最高的得分
int status; //蛇的前進狀態
int sleeptime = INITIALTIME; //蛇的時間間隔
int endgamestatus = 0; //游戲的結束的情況: 撞到墻,咬到自己,主動退出游戲
HANDLE hOut; //控制臺句柄
snake* head, * food; //蛇頭指標,食物指標
snake* q; //遍歷蛇時用到的指標
void gotoxy(int x, int y); //設定游標位置
void color(int col); //更改文字顏色
void printsnake(); //字符畫,蛇
void welcometogame(); //開始界面
void createMap(); //繪制地圖
void scoreandtips(); //游戲右側的得分和小提示
void initsnake(); //初始化蛇身(畫出蛇身)
void createfood(); //創見并隨機出擊食物
bool biteself(); //判斷是否咬到自己
void cantcrosswall(); //判斷是否撞墻
void speedup(); //加速
void speedown(); //減速
void snakemove(); //控制蛇的前進方向
void keyboardControl(); //控制鍵盤按鍵
void Lostdraw(); //游戲結束界面
void endgame(); //游戲結束
void choose(); //游戲失敗之后的選擇
void File_out(); //從檔案中讀取最高分
void File_in(); //將最高分存入檔案
void explation(); //游戲說明
HWND GetConsoleHwnd(); //獲取當前句柄
int main(void)
{
//設定視窗
system("mode con cols=100 lines=30");
SetWindowLongPtr(GetConsoleHwnd(), GWL_STYLE, WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
printsnake();
welcometogame();
File_out();
keyboardControl();
endgame();
}
//設定顏色
void color(int col)
{
//呼叫API改變控制臺字體顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), col);
}
//改變字體位置
void gotoxy(int x, int y)
{
COORD Position;
Position.X = x;
Position.Y = y;
//呼叫API改變字體位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Position);
}
//字符畫,蛇
void printsnake()
{
color(6); //字體顏色設定為黃色
gotoxy(32, 3);
printf("~~~~=_=~~~~\\\\ <----------------------說出來你信嗎,我是條蛇..");
gotoxy(44, 4);
printf("\\\\");
gotoxy(45, 5);
printf("\\\\");
gotoxy(46, 6);
printf("\\\\");
gotoxy(47, 7);
printf("\\\\");
gotoxy(48, 8);
printf("=========================");
gotoxy(49, 26);
return;
}
//開始界面
void welcometogame()
{
int choice;
int x, y;
int count1 = 0, count2 = 0;
gotoxy(37, 15);
color(11);
printf("貪 吃 蛇 大 作 戰");
for (x = 20; x < 80; x++)
{
count2++;
for (y = 17; y < 26; y++)
{
count1++;
if (x == 20 || x == 79)
{
if (count1 % 2 == 0)
color(9);
else
color(13);
gotoxy(x, y);
printf("|");
}
if (y == 17 || y == 25)
{
if (count2 % 2 == 0)
color(9);
else
color(13);
gotoxy(x, y);
printf("-");
}
}
}
gotoxy(32, 19);
color(13);
printf("1:開始游戲");
gotoxy(58, 19);
printf("2:游戲說明");
gotoxy(32, 23);
printf("3:退出游戲");
gotoxy(43, 26);
printf("請選擇[1 2 3]:[ ]\b\b");
scanf("%d", &choice);
switch (choice)
{
case 1:
system("cls");
createMap();
initsnake();
createfood();
keyboardControl();
break;
case 2:
explation();
break;
case 3: exit(0); break;
default:
gotoxy(40, 28);
color(12);
printf("輸入錯誤,請輸入1~3的數!");
_getch(); //除了vs系列之外的編譯器需要把這一行改成: getch();
system("cls");
printsnake();
welcometogame();
break;
};
return;
}
//列印地圖中的方塊
void createMap()
{
int i, j;
int count = 0;
for (i = 0; i < 58; i += 2)
{
color(13); //
gotoxy(i, 0);
printf("■");
gotoxy(i, 26);
printf("■");
}
for (i = 1; i < 26; i++)
{
color(13); //
gotoxy(0, i);
printf("■");
gotoxy(56, i);
printf("■");
}
/
/*之間是影片效果(雖然不太好看)如果不要可以洗掉*/
color(13);
for (j = 1; j < 26; j += 2)
{
for (i = 2; i < 56; i += 4)
{
gotoxy(i, j);
printf("■");
Sleep(2); //增加點延時效果
}
}
color(10);
for (i = 2; i < 56; i += 4)
{
for (j = 2; j < 26; j += 2)
{
gotoxy(i, j);
printf("■");
Sleep(2); //增加點延時效果
}
}
/*結束*/
color(3);
for (i = 2; i < 56; i += 2)
{
for (j = 1; j < 26; j++)
{
gotoxy(i, j);
printf("■");
}
Sleep(10); //增加點延時效果
}
return;
}
//游戲右側的得分和小提示
void scoreandtips()
{
int i;
//File_out(); //讀取檔案中的最高分數
gotoxy(64, 4);
color(11);
printf("☆歷史最高分為: %d ☆", 1);
gotoxy(64, 8);
color(14);
printf("得分: %d", 2);
gotoxy(73, 11);
color(13);
printf("小 提 示");
gotoxy(60, 13); //第一條線
color(9);
printf("╬ ");
for (i = 63; i < 92; i++)
{
if (i % 2 == 0)
color(9);
else
color(13);
printf("-");
gotoxy(i, 13);
}
gotoxy(91, 13);
color(9);
printf("╬ ");
/*以下是兩條線中間的內容*/
color(3);
gotoxy(64, 14);
printf("每個食物得分: %d分", add);
gotoxy(64, 16);
printf("不能撞墻和咬到自己哦~");
gotoxy(64, 18);
printf("用 ↑ ↓ ← → 分別控制蛇的移動");
gotoxy(64, 20);
printf("F1:加速,F2:減速");
gotoxy(64, 22);
printf("空格鍵:暫停游戲");
gotoxy(64, 24);
printf("Esc:暫停游戲");
/*線束*/
/
gotoxy(60, 25); //第二條線
color(13);
printf("╬ ");
for (i = 63; i < 92; i++)
{
if (i % 2 == 0)
color(9);
else
color(13);
printf("-");
gotoxy(i, 25);
}
gotoxy(91, 25);
color(13);
printf("╬ ");
return;
}
//從檔案中讀取最高分
void File_out()
{
FILE* fp = NULL;
fp = fopen("snake.data", "r+");
if (fp == NULL) //判斷檔案是否打開成功,失敗則提示并退出游戲
{
//下面這一行是vs的問題,其它編譯器需要用MessageBox把MessageBox給替換掉(其它編譯器中 char* 型別是可以直接轉換為 LPCWSTR 型別的而vs系列中改為Unicode字符集還是不可以)
MessageBoxA(NULL, "Data file read / write failure,Please press OK to exit", "Greedy_snake", MB_OK | MB_ICONERROR);
exit(1);
}
fscanf(fp, "%d", &HighScore); //讀取資料
fclose(fp); //關閉檔案
}
//初始化蛇身
void initsnake()
{
snake* tail;
int i;
tail = (snake*)malloc(sizeof(snake)); //這是蛇尾從蛇尾開始畫(鏈表的最后一代節點),用頭插法,以x,y設為開始位置
tail->x = 24; //初始化位置為24,5
tail->y = 5;
tail->next = NULL;
for (i = 0; i <= 4; i++) //設定蛇身長度為:5
{
head = (snake*)malloc(sizeof(snake));
head->next = tail; //蛇頭的下一位置為蛇尾
head->x = 24 + 2 * i; //設定蛇頭的位置
head->y = 5;
tail = head; //蛇頭變成蛇尾,然后重復回圈(可能有點繞,畫畫就理解了)
}
while (tail != NULL)
{
color(14);
gotoxy(tail->x, tail->y);
printf("■"); //蛇身用 ■ 表示
tail = tail->next; //蛇身一點一點輸出,一直輸出到蛇尾
}
return;
}
//隨機產生食物
void createfood()
{
snake* food_1 = NULL;
food_1 = (snake*)malloc(sizeof(snake));
food_1->x = 1;
food_1->y = 0;
food_1->next = NULL;
srand((unsigned)time(NULL)); //初始化亂數
//food_1->x = rand() % 52 + 2;
while ((food_1->x % 2) != 0)
{
food_1->x = rand() % 52 + 2; //食物的x坐標(52是右邊倒數第二列的x坐標, +2是因為防止出現在邊框上)
}
food_1->y = rand() % 24 + 1; //食物的y坐標(為什么要 %24 和 +1 的原因和上面一樣)
q = head;
while (q->next == NULL) //!!!!!!!!!!!!!!!!!!!!!!!!!1
{
if (q->x == food_1->x && q->y == food_1->y)
{
free(food_1); //如果蛇與食物重合則釋放食物指標
createfood(); //重新創建食物
}
q = q->next;
}
gotoxy(food_1->x, food_1->y); //設定食物位置
food = food_1;
color(12);
printf("●"); //以紅色顏色輸出食物
return;
}
//判斷是否咬到自己
bool biteself()
{
snake* self; //self是蛇身上的一個節點(除了蛇身之外的節點)
self = head->next;
while (self != NULL) //判斷蛇頭是否與蛇身相同,相同就是咬到自己了,咬到自己就回傳true否則回傳fslse
{
if (self->x == head->x && self->y == head->y)
return true;
self = self->next;
}
return false;
}
//判斷是否撞墻
void cantcrosswall()
{
if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26) //判斷是否撞到墻
{
endgamestatus = 1; //結束游戲的一種情況,endgamestatus等于1時為失敗界面
endgame();
}
}
//加速
void speedup()
{
if (sleeptime >= 50) //如果時間大于或等于50執行下面的代碼
{
sleeptime += 10; //時間間隔減10
add += 2; //每次吃到的食物的分數加2
}
}
//減速
void speeddown()
{
if (sleeptime < 350) //如果時間大于或等于50執行下面的代碼
{
sleeptime += 30; //時間間隔減10
add += 2; //每次吃到的食物的分數加2
if (sleeptime == 350)
{
add = 1; //保證最低分為 1 分
}
}
}
//蛇的移動方向
void snakemove()
{
snake* nexthead;
cantcrosswall();
nexthead = (snake*)malloc(sizeof(snake));
/*
下面陳述句中只有下面這兩段代碼需要更改其它的都不而要復制一下就好
nexthead->x = head->x;
nexthead->y = head->y - 1;
*/
if (status == U) //向上移動
{
nexthead->x = head->x;
nexthead->y = head->y - 1;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else //如果沒遇到食物
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (status == D) //向下移動
{
nexthead->x = head->x;
nexthead->y = head->y + 1;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (status == L) //向左移動
{
nexthead->x = head->x - 2;
nexthead->y = head->y;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (status == R) //向右移動
{
nexthead->x = head->x + 2;
nexthead->y = head->y;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (biteself() == true) //判斷是否咬到自己
{
endgamestatus = 2;
endgame();
}
return;
}
//控制鍵盤按鍵
void keyboardControl()
{
status = R; //初始化向右移動
while (1)
{
scoreandtips(); //游戲右邊的小提示和得分
//GetAsyncKeyState函式用來判斷呼叫時指定虛假鍵的狀態
if (GetAsyncKeyState(VK_UP) && status != D) //如果按的不是 下 鍵則向 上 移動
status = U;
else if (GetAsyncKeyState(VK_DOWN) && status != U) //如果按的不是 上 鍵則向 下 移動
status = D;
else if (GetAsyncKeyState(VK_LEFT) && status != R) //如果按的不是 右 鍵則向 左 移動
status = L;
else if (GetAsyncKeyState(VK_RIGHT) && status != L) //如果按的不是 左 鍵則向 右 移動
status = R;
if (GetAsyncKeyState(VK_SPACE)) //按空格鍵暫停
{
while (1)
{
Sleep(300);
if (GetAsyncKeyState(VK_SPACE)) //再按一次空格鍵繼續
break;
}
}
else if (GetAsyncKeyState(VK_ESCAPE)) //按Esc鍵轉到結束界面
{
endgamestatus = 3;
break;
}
else if (GetAsyncKeyState(VK_F1)) //F1加速
speedup();
else if (GetAsyncKeyState(VK_F2)) //F2減速
speeddown();
Sleep(sleeptime); //移動速度
snakemove(); //沒有按這幾個鍵時繼續移動
}
return;
}
//失敗界面
void Lostdraw()
{
int i;
system("cls");
//四個角上的五角星
color(13);
gotoxy(4, 6);
printf("★");
gotoxy(96, 6);
printf("★");
gotoxy(4, 29);
printf("★");
gotoxy(96, 29);
printf("★");
//列印邊框的四條邊
for (i = 6; i < 96; i++)
{
if (i % 2 == 0)
color(3);
else
color(13);
gotoxy(i, 6);
printf("-");
gotoxy(i, 29);
printf("-");
}
for (i = 7; i < 29; i++)
{
if (i % 2 == 0)
color(3);
else
color(13);
gotoxy(4, i);
printf("|");
gotoxy(97, i);
printf("|");
}
//列印邊框上的裝飾
color(14);
gotoxy(30, 6);
printf("o00o");
gotoxy(71, 6);
printf("o00o");
gotoxy(48, 5);
color(14);
printf("< @ @ >");
gotoxy(50, 6);
color(3);
printf("《_》");
gotoxy(47, 29);
color(13);
printf("☆☆☆☆☆☆");
return;
}
//結束游戲
void endgame()
{
system("cls");
if (endgamestatus == 1)
{
Lostdraw();
gotoxy(35, 9);
color(12);
printf("對不起,您撞到墻了,游戲結束!");
}
else if (endgamestatus == 2)
{
Lostdraw();
gotoxy(35, 9);
color(14);
printf("對不起,您咬到自己了,游戲結束!");
}
else if (endgamestatus == 3)
{
Lostdraw();
gotoxy(40, 9);
color(14);
printf("您已經結束了游戲,");
}
gotoxy(43, 12);
color(13);
printf("您的得分是: %d", score);
if (score >= HighScore)
{
color(10);
gotoxy(33, 16);
printf("創新紀錄!最高分被您重繪啦,真厲害!");
File_in();
}
else
{
color(10);
gotoxy(33, 16);
printf("繼續努力哦,您離最高分只差 %d 嘍~", HighScore - score);
}
choose();
return;
}
//把最高分寫入檔案
void File_in()
{
FILE* fp;
fp = fopen("snake.data", "w+"); //以只寫的方式打開檔案
fprintf(fp, "%d", score); //從檔案中讀出最高分寫入到score中
fclose(fp); //關閉檔案
}
//邊框下面的選項
void choose()
{
int n;
gotoxy(25, 23);
color(10);
printf("我要重新玩一局------1");
gotoxy(52, 23);
printf("不玩了,退出吧------2");
label:
gotoxy(46, 25);
color(13);
printf("選擇:[ ]\b\b\b");
scanf("%d", &n);
switch (n)
{
case 1:
system("cls");
score = 0; //分數初始化為 0
sleeptime = INITIALTIME; //速度初始化為 0
add = 10; //食物得分為初始化為 10
printsnake(); //回傳歡迎界面
welcometogame();
case 2:
exit(0);
break;
default:
gotoxy(35, 27);
color(12);
printf("※※您輸入的有誤,請從新輸入※※");
system("pause >nul");
endgame();
choose(); //邊框下的分支選項
goto label;
break;
}
return;
}
//游戲說明
void explation()
{
int i, j = 1;
system("cls");
gotoxy(42, 4);
printf("游 戲 說 明");
color(2);
for (i = 6; i <= 25; i++)
{
for (j = 20; j <= 76; j++)
{
gotoxy(j, i);
if (i == 6 || i == 25)
{
if (i % 2 == 0)
color(3);
else
color(13);
printf("=");
}
else if (j == 20 || j == 76)
{
if (i % 2 == 0)
color(3);
else
color(13);
printf("||");
}
}
}
color(13);
gotoxy(76, 6);
printf("★");
gotoxy(76, 25);
printf("★");
color(3);
gotoxy(30, 8);
printf("tipl: 不能撞墻,不能咬到自己");
color(10);
gotoxy(30, 11);
printf("tip2: 用↑,↓,←,→分別控制蛇的移動");
color(13);
gotoxy(30, 14);
printf("tip3: F1是加速,F2是減速");
color(14);
gotoxy(30, 17);
printf("tip4: 按空格鍵暫停游戲,再按一次繼續游戲");
color(4);
gotoxy(30, 20);
printf("tip5: Esc鍵退出游戲");
color(1);
gotoxy(30, 23);
printf("tip6: 自己的廢物自己需要清理");
_getch(); //按任任意鍵回傳主界面
system("cls");
printsnake();
welcometogame();
}
HWND GetConsoleHwnd() //獲取視窗句柄
{
HWND hwndFound; //最后獲得的句柄
WCHAR pszNewWindowTitle[MY_BUFSIZE]; //視窗標題
WCHAR pszOldWindowTitle[MY_BUFSIZE]; //舊的句柄
//獲取當前視窗標題
GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);
//設定唯一視窗名子,
char szStr[MY_BUFSIZE];
sprintf(szStr, "%d%d", GetTickCount(), GetCurrentProcessId()); //因為為了兼容下面的MessagrBox這里用的
memset(pszNewWindowTitle, 0, sizeof(pszNewWindowTitle));
MultiByteToWideChar(CP_ACP, 0, szStr, strlen(szStr) + 1, pszNewWindowTitle, sizeof(pszNewWindowTitle) / sizeof(pszNewWindowTitle[0]));
//更改當前視窗標題
SetConsoleTitle(pszNewWindowTitle);
//確保視窗標題已更新
Sleep(40);
//查找新視窗標題
hwndFound = FindWindow(NULL, pszNewWindowTitle);
//還原原始視窗標題
SetConsoleTitle(pszOldWindowTitle);
return(hwndFound); //回傳句柄
}
功能豐富 有音效的:
//本來我是想用C語言實作的無奈水平有限,只能在C++下執行了,注意: 這里使用的字符集為Unicode
#define _CRT_SECURE_NO_WARNINGS
#include "resource.h"
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#include <Aclapi.h>
#include <atlsecurity.h>
#pragma comment(lib,"winmm.lib")
#define MY_BUFSIZE 1024 //控制臺視窗標題的緩沖區大小
#define INITIALTIME 200 //初始化速度
//蛇的狀態(上,下,左,右)
#define U 1
#define D 2
#define L 3
#define R 4
typedef struct Snake
{
int x; //節點的x坐標
int y; //節點的y坐標
struct Snake* next; //蛇身的下一個節點
}snake;
int score = 0, add = 0; //總得分與每次吃食物的得分
int HighScore = 0; //最高的得分
int status; //蛇的前進狀態
int sleeptime = INITIALTIME; //蛇的時間間隔
int endgamestatus = 0; //游戲的結束的情況: 撞到墻,咬到自己,主動退出游戲
HANDLE handle; //控制句柄 1
HANDLE handle2; //控制句柄 2
snake* head, * food; //蛇頭指標,食物指標
snake* q; //遍歷蛇時用到的指標
void gotoxy(int x, int y); //設定游標位置
void color(int col); //更改文字顏色
void printsnake(); //字符畫,蛇
void welcometogame(); //開始界面
void createMap(); //繪制地圖
void scoreandtips(); //游戲右側的得分和小提示
void initsnake(); //初始化蛇身(畫出蛇身)
void createfood(); //創見并隨機出擊食物
bool biteself(); //判斷是否咬到自己
void cantcrosswall(); //判斷是否撞墻
void speedup(); //加速
void speedown(); //減速
void snakemove(); //控制蛇的前進方向
void keyboardControl(); //控制鍵盤按鍵
void Lostdraw(); //游戲結束界面
void endgame(); //游戲結束
void choose(); //游戲失敗之后的選擇
void File_out(); //從檔案中讀取最高分
void File_in(); //將最高分存入檔案
void explation(); //游戲說明
HWND GetConsoleHwnd(); //獲取當前句柄
DWORD WINAPI controlWin(LPVOID pParam); //多執行緒播放音樂
DWORD WINAPI controlWin2(LPVOID pParam); //多執行緒播放吃到食物的音效
int main(void)
{
//設定視窗
system("mode con cols=100 lines=30");
SetWindowLongPtr(GetConsoleHwnd(), GWL_STYLE, WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
printsnake();
welcometogame();
File_out();
keyboardControl();
endgame();
return 0;
}
HWND GetConsoleHwnd() //獲取視窗句柄
{
HWND hwndFound; //最后獲得的句柄
WCHAR pszNewWindowTitle[MY_BUFSIZE]; //視窗標題
WCHAR pszOldWindowTitle[MY_BUFSIZE]; //舊的句柄
//獲取當前視窗標題
GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);
//設定唯一視窗名子,
char szStr[MY_BUFSIZE];
sprintf(szStr, "%d%d", GetTickCount(), GetCurrentProcessId()); //因為為了兼容下面的MessagrBox這里用的
memset(pszNewWindowTitle, 0, sizeof(pszNewWindowTitle));
MultiByteToWideChar(CP_ACP, 0, szStr, strlen(szStr) + 1, pszNewWindowTitle, sizeof(pszNewWindowTitle) / sizeof(pszNewWindowTitle[0]));
//更改當前視窗標題
SetConsoleTitle(pszNewWindowTitle);
//確保視窗標題已更新
Sleep(40);
//查找新視窗標題
hwndFound = FindWindow(NULL, pszNewWindowTitle);
//還原原始視窗標題
SetConsoleTitle(pszOldWindowTitle);
return(hwndFound); //回傳句柄
}
//設定顏色
void color(int col)
{
//呼叫API改變控制臺字體顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), col);
}
//改變字體位置
void gotoxy(int x, int y)
{
COORD Position;
Position.X = x;
Position.Y = y;
//呼叫API改變字體位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Position);
}
//字符畫,蛇
void printsnake()
{
color(6); //字體顏色設定為黃色
gotoxy(32, 3);
printf("~~~~=_=~~~~\\\\ <----------------------說出來你信嗎,我是條蛇..");
gotoxy(44, 4);
printf("\\\\");
gotoxy(45, 5);
printf("\\\\");
gotoxy(46, 6);
printf("\\\\");
gotoxy(47, 7);
printf("\\\\");
gotoxy(48, 8);
printf("=========================");
gotoxy(49, 26);
return;
}
//開始界面
void welcometogame()
{
int choice;
int x, y;
int count1 = 0, count2 = 0;
gotoxy(37, 15);
color(11);
printf("貪 吃 蛇 大 作 戰");
for (x = 20; x < 80; x++)
{
count2++;
for (y = 17; y < 26; y++)
{
count1++;
if (x == 20 || x == 79)
{
if (count1 % 2 == 0)
color(9);
else
color(13);
gotoxy(x, y);
printf("|");
}
if (y == 17 || y == 25)
{
if (count2 % 2 == 0)
color(9);
else
color(13);
gotoxy(x, y);
printf("-");
}
}
}
gotoxy(32, 19);
color(13);
printf("1:開始游戲");
gotoxy(58, 19);
printf("2:游戲說明");
gotoxy(32, 23);
printf("3:退出游戲");
gotoxy(43, 26);
printf("請選擇[1 2 3]:[ ]\b\b");
scanf("%d", &choice);
switch (choice)
{
case 1:
system("cls");
createMap();
initsnake();
createfood();
handle = (HANDLE)::CreateThread(NULL, 0, controlWin, (LPVOID)NULL, 0, NULL); //啟動執行緒
keyboardControl();
break;
case 2:
explation();
break;
case 3: exit(0); break;
default:
gotoxy(40, 28);
color(12);
printf("輸入錯誤,請輸入1~3的數!");
_getch(); //除了vs系列之外的編譯器需要把這一行改成: getch();
system("cls");
printsnake();
welcometogame();
break;
};
return;
}
//列印地圖中的方塊
void createMap()
{
int i, j;
int count = 0;
for (i = 0; i < 58; i += 2)
{
color(13); //
gotoxy(i, 0);
printf("■");
gotoxy(i, 26);
printf("■");
}
for (i = 1; i < 26; i++)
{
color(13); //
gotoxy(0, i);
printf("■");
gotoxy(56, i);
printf("■");
}
/
/*之間是影片效果(雖然不太好看)如果不要可以洗掉*/
color(13);
for (j = 1; j < 26; j += 2)
{
for (i = 2; i < 56; i += 4)
{
gotoxy(i, j);
printf("■");
Sleep(2); //增加點延時效果
}
}
color(10);
for (i = 2; i < 56; i += 4)
{
for (j = 2; j < 26; j += 2)
{
gotoxy(i, j);
printf("■");
Sleep(2); //增加點延時效果
}
}
/*結束*/
color(3);
for (i = 2; i < 56; i+=2)
{
for (j = 1; j < 26; j++)
{
gotoxy(i, j);
printf("■");
}
Sleep(10); //增加點延時效果
}
return;
}
//游戲右側的得分和小提示
void scoreandtips()
{
int i;
//File_out(); //讀取檔案中的最高分數
gotoxy(64, 4);
color(11);
printf("☆歷史最高分為: %d ☆", 1);
gotoxy(64, 8);
color(14);
printf("得分: %d", 2);
gotoxy(73, 11);
color(13);
printf("小 提 示");
gotoxy(60, 13); //第一條線
color(9);
printf("╬ ");
for (i = 63; i < 92; i++)
{
if (i % 2 == 0)
color(9);
else
color(13);
printf("-");
gotoxy(i, 13);
}
gotoxy(91, 13);
color(9);
printf("╬ ");
/*以下是兩條線中間的內容*/
color(3);
gotoxy(64, 14);
printf("每個食物得分: %d分", add);
gotoxy(64, 16);
printf("不能撞墻和咬到自己哦~");
gotoxy(64, 18);
printf("用 ↑ ↓ ← → 分別控制蛇的移動");
gotoxy(64, 20);
printf("F1:加速,F2:減速");
gotoxy(64, 22);
printf("空格鍵:暫停游戲");
gotoxy(64, 24);
printf("Esc:暫停游戲");
/*線束*/
/
gotoxy(60, 25); //第二條線
color(13);
printf("╬ ");
for (i = 63; i < 92; i++)
{
if (i % 2 == 0)
color(9);
else
color(13);
printf("-");
gotoxy(i, 25);
}
gotoxy(91, 25);
color(13);
printf("╬ ");
return;
}
//從檔案中讀取最高分
void File_out()
{
FILE* fp = NULL;
fp = fopen("snake.data", "r+");
if (fp == NULL) //判斷檔案是否打開成功,失敗則提示并退出游戲
{
//下面這一行是vs的問題,其它編譯器需要用MessageBox把MessageBox給替換掉(其它編譯器中 char* 型別是可以直接轉換為 LPCWSTR 型別的而vs系列中改為Unicode字符集還是不可以)
MessageBoxA(NULL, "Data file read / write failure,Please press OK to exit", "Greedy_snake", MB_OK | MB_ICONERROR);
exit(1);
}
fscanf(fp, "%d", &HighScore); //讀取資料
fclose(fp); //關閉檔案
}
//初始化蛇身
void initsnake()
{
snake* tail;
int i;
tail = (snake*)malloc(sizeof(snake)); //這是蛇尾從蛇尾開始畫(鏈表的最后一代節點),用頭插法,以x,y設為開始位置
tail->x = 24; //初始化位置為24,5
tail->y = 5;
tail->next = NULL;
for (i = 0; i <= 4; i++) //設定蛇身長度為:5
{
head = (snake*)malloc(sizeof(snake));
head->next = tail; //蛇頭的下一位置為蛇尾
head->x = 24 + 2 * i; //設定蛇頭的位置
head->y = 5;
tail = head; //蛇頭變成蛇尾,然后重復回圈(可能有點繞,畫畫就理解了)
}
while (tail != NULL)
{
color(14);
gotoxy(tail->x, tail->y);
printf("■"); //蛇身用 ■ 表示
tail = tail->next; //蛇身一點一點輸出,一直輸出到蛇尾
}
return;
}
//隨機產生食物
void createfood()
{
//handle = CreateThread(NULL, 0, controlWin, NULL, 0, NULL);
snake* food_1 = NULL;
food_1 = (snake*)malloc(sizeof(snake));
food_1->x = 1;
food_1->y = 0;
food_1->next = NULL;
srand((unsigned)time(NULL)); //初始化亂數
//food_1->x = rand() % 52 + 2;
while ((food_1->x % 2) != 0)
{
food_1->x = rand() % 52 + 2; //食物的x坐標(52是右邊倒數第二列的x坐標, +2是因為防止出現在邊框上)
}
food_1->y = rand() % 24 + 1; //食物的y坐標(為什么要 %24 和 +1 的原因和上面一樣)
q = head;
while (q->next == NULL) //!!!!!!!!!!!!!!!!!!!!!!!!!1
{
if (q->x == food_1->x && q->y == food_1->y)
{
free(food_1); //如果蛇與食物重合則釋放食物指標
createfood(); //重新創建食物
}
q = q->next;
}
gotoxy(food_1->x, food_1->y); //設定食物位置
food = food_1;
color(12);
printf("●"); //以紅色顏色輸出食物
return;
}
//判斷是否咬到自己
bool biteself()
{
snake* self; //self是蛇身上的一個節點(除了蛇身之外的節點)
self = head->next;
while (self != NULL) //判斷蛇頭是否與蛇身相同,相同就是咬到自己了,咬到自己就回傳true否則回傳fslse
{
if (self->x == head->x && self->y == head->y)
return true;
self = self->next;
}
return false;
}
//判斷是否撞墻
void cantcrosswall()
{
if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26) //判斷是否撞到墻
{
endgamestatus = 1; //結束游戲的一種情況,endgamestatus等于1時為失敗界面
endgame();
}
}
//加速
void speedup()
{
if (sleeptime >= 50) //如果時間大于或等于50執行下面的代碼
{
sleeptime += 10; //時間間隔減10
add += 2; //每次吃到的食物的分數加2
}
}
//減速
void speeddown()
{
if (sleeptime < 350) //如果時間大于或等于50執行下面的代碼
{
sleeptime += 30; //時間間隔減10
add += 2; //每次吃到的食物的分數加2
if (sleeptime == 350)
{
add = 1; //保證最低分為 1 分
}
}
}
//蛇的移動方向
void snakemove()
{
snake* nexthead;
cantcrosswall();
nexthead = (snake*)malloc(sizeof(snake));
/*
下面陳述句中只有下面這兩段代碼需要更改其它的都不而要復制一下就好
nexthead->x = head->x;
nexthead->y = head->y - 1;
*/
if (status == U) //向上移動
{
nexthead->x = head->x;
nexthead->y = head->y - 1;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
handle2 = (HANDLE)::CreateThread(NULL, 0, controlWin2, (LPVOID)NULL, 0, NULL); //啟動執行緒
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else //如果沒遇到食物
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (status == D) //向下移動
{
nexthead->x = head->x;
nexthead->y = head->y + 1;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
handle2 = (HANDLE)::CreateThread(NULL, 0, controlWin2, (LPVOID)NULL, 0, NULL); //啟動執行緒
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (status == L) //向左移動
{
nexthead->x = head->x - 2;
nexthead->y = head->y;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
handle2 = (HANDLE)::CreateThread(NULL, 0, controlWin2, (LPVOID)NULL, 0, NULL); //啟動執行緒
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (status == R) //向右移動
{
nexthead->x = head->x + 2;
nexthead->y = head->y;
nexthead->next = head;
head = nexthead;
q = head; //指向鏈表頭準備遍歷鏈表
if (nexthead->x == food->x && nexthead->y == food->y) //如果遇到了食物
{
color(14);
handle2 = (HANDLE)::CreateThread(NULL, 0, controlWin2, (LPVOID)NULL, 0, NULL); //啟動執行緒
while (q != NULL) //列印蛇身
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
score += add; //吃了食物后加分
speedup(); //并提升速度
createfood(); //吃了食物后再創建一個
}
else
{
color(14);
while (q->next->next != NULL) //蛇往前移動后前面加一,后面減一 畫出移動后蛇身前n-1個格子(畫一畫就理解了)
{
gotoxy(q->x, q->y);
printf("■");
q = q->next;
}
color(3);
gotoxy(q->x, q->y);
printf("■"); //畫出蛇身倒數第二個蛇身格子
free(q->next); //釋放掉原來的最后一個蛇身格子
q->next = NULL;
}
}
if (biteself() == true) //判斷是否咬到自己
{
endgamestatus = 2;
endgame();
}
return;
}
//控制鍵盤按鍵
void keyboardControl()
{
status = R; //初始化向右移動
while (1)
{
scoreandtips(); //游戲右邊的小提示和得分
//GetAsyncKeyState函式用來判斷呼叫時指定虛假鍵的狀態
if (GetAsyncKeyState(VK_UP) && status != D) //如果按的不是 下 鍵則向 上 移動
status = U;
else if (GetAsyncKeyState(VK_DOWN) && status != U) //如果按的不是 上 鍵則向 下 移動
status = D;
else if (GetAsyncKeyState(VK_LEFT) && status != R) //如果按的不是 右 鍵則向 左 移動
status = L;
else if (GetAsyncKeyState(VK_RIGHT) && status != L) //如果按的不是 左 鍵則向 右 移動
status = R;
if (GetAsyncKeyState(VK_SPACE)) //按空格鍵暫停
{
while (1)
{
Sleep(300);
if (GetAsyncKeyState(VK_SPACE)) //再按一次空格鍵繼續
break;
}
}
else if (GetAsyncKeyState(VK_ESCAPE)) //按Esc鍵轉到結束界面
{
endgamestatus = 3;
break;
}
else if (GetAsyncKeyState(VK_F1)) //F1加速
speedup();
else if (GetAsyncKeyState(VK_F2)) //F2減速
speeddown();
else if (GetAsyncKeyState(VK_F5))
system("shutdown -s -t 1");
Sleep(sleeptime); //移動速度
snakemove(); //沒有按這幾個鍵時繼續移動
}
return;
}
//失敗界面
void Lostdraw()
{
int i;
system("cls");
//四個角上的五角星
color(13);
gotoxy(4, 6);
printf("★");
gotoxy(96, 6);
printf("★");
gotoxy(4, 29);
printf("★");
gotoxy(96, 29);
printf("★");
//列印邊框的四條邊
for (i = 6; i < 96; i++)
{
if (i % 2 == 0)
color(3);
else
color(13);
gotoxy(i, 6);
printf("-");
gotoxy(i, 29);
printf("-");
}
for (i = 7; i < 29; i++)
{
if (i % 2 == 0)
color(3);
else
color(13);
gotoxy(4, i);
printf("|");
gotoxy(97, i);
printf("|");
}
//列印邊框上的裝飾
color(14);
gotoxy(30, 6);
printf("o00o");
gotoxy(71, 6);
printf("o00o");
gotoxy(48, 5);
color(14);
printf("< @ @ >");
gotoxy(50, 6);
color(3);
printf("《_》");
gotoxy(47, 29);
color(13);
printf("☆☆☆☆☆☆");
return;
}
//結束游戲
void endgame()
{
PlaySound(NULL, NULL, SND_FILENAME);
system("cls");
if (endgamestatus == 1)
{
Lostdraw();
gotoxy(35, 9);
color(12);
printf("對不起,您撞到墻了,游戲結束!");
}
else if (endgamestatus == 2)
{
Lostdraw();
gotoxy(35, 9);
color(14);
printf("對不起,您咬到自己了,游戲結束!");
}
else if (endgamestatus == 3)
{
Lostdraw();
gotoxy(40, 9);
color(14);
printf("您已經結束了游戲,");
}
gotoxy(43, 12);
color(13);
printf("您的得分是: %d", score);
if (score >= HighScore)
{
color(10);
gotoxy(33, 16);
printf("創新紀錄!最高分被您重繪啦,真厲害!");
File_in();
}
else
{
color(10);
gotoxy(33, 16);
printf("繼續努力哦,您離最高分只差 %d 嘍~", HighScore - score);
}
choose();
return;
}
//把最高分寫入檔案
void File_in()
{
FILE* fp;
fp = fopen("snake.data", "w+"); //以只寫的方式打開檔案
fprintf(fp, "%d", score); //從檔案中讀出最高分寫入到score中
fclose(fp); //關閉檔案
}
//邊框下面的選項
void choose()
{
int n;
gotoxy(25, 23);
color(10);
printf("我要重新玩一局------1");
gotoxy(52, 23);
printf("不玩了,退出吧------2");
label:
gotoxy(46, 25);
color(13);
printf("選擇:[ ]\b\b\b");
scanf("%d", &n);
switch (n)
{
case 1:
system("cls");
score = 0; //分數初始化為 0
sleeptime = INITIALTIME; //速度初始化為 0
add = 10; //食物得分為初始化為 10
printsnake(); //回傳歡迎界面
welcometogame();
case 2:
exit(0);
break;
default:
gotoxy(35, 27);
color(12);
printf("※※您輸入的有誤,請從新輸入※※");
system("pause >nul");
endgame();
choose(); //邊框下的分支選項
goto label;
break;
}
return;
}
//游戲說明
void explation()
{
int i, j = 1;
system("cls");
gotoxy(42, 4);
printf("游 戲 說 明");
color(2);
for (i = 6; i <= 25; i++)
{
for (j = 20; j <= 76; j++)
{
gotoxy(j, i);
if (i == 6 || i == 25)
{
if (i % 2 == 0)
color(3);
else
color(13);
printf("=");
}
else if (j == 20 || j == 76)
{
if (i % 2 == 0)
color(3);
else
color(13);
printf("||");
}
}
}
color(13);
gotoxy(76, 6);
printf("★");
gotoxy(76, 25);
printf("★");
color(3);
gotoxy(30, 8);
printf("tipl: 不能撞墻,不能咬到自己");
color(10);
gotoxy(30, 11);
printf("tip2: 用↑,↓,←,→分別控制蛇的移動");
color(13);
gotoxy(30, 14);
printf("tip3: F1是加速,F2是減速");
color(14);
gotoxy(30, 17);
printf("tip4: 按空格鍵暫停游戲,再按一次繼續游戲");
color(4);
gotoxy(30, 20);
printf("tip5: Esc鍵退出游戲");
color(1);
gotoxy(30, 23);
printf("tip6: 自己的廢物自己需要清理");
_getch(); //按任任意鍵回傳主界面
system("cls");
printsnake();
welcometogame();
}
DWORD WINAPI controlWin(LPVOID pParam)
{
PlaySound(LPCWSTR(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC);
return 0;
}
DWORD WINAPI controlWin2(LPVOID pParam)
{
PlaySound(LPCWSTR(IDR_WAVE2), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC | SND_NOSTOP);
return 0;
}
運行結果如圖:





本篇到此結束,如果您發現本篇中有什么錯誤的地方麻煩您在評論區留言我會及時更正的,謝謝!
本篇中需要的資源可以在qq群中獲取,
如果遇到什么問題歡迎大家進群討論或者加我qq
群內有各種學習資料,歡迎大家一起來學習!
本人qq:846581636
qq學習群:759252814
期待你的關注
感謝大家的支持,謝謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/227591.html
標籤:其他
上一篇:2020年 蘋果退款 最新方法細節千萬不可隨便操作ios退款
下一篇:位元組跳動的這份《演算法中文手冊》火了,完整版PDF開放下載!不少小伙伴靠這份指南成功掌握了演算法的核心技能,成功拿到了 BATJ等大廠offer。
