貪吃蛇
效果演示:
操作說明:
W
、S
、A
、D
控制 上 、下、左、右 方向,空格
暫停,按下任意鍵繼續- 每吃掉一個食物長度加1,界面下方顯示當前長度
- 蛇頭撞到自身或邊界後顯示
game over!
2秒(時間可更改),任意鍵退出
- 由於上下字符間隔與左右字符間隔不一致,縱向移動時移動速度會超過橫向移動速度。
- 畫面顯示:遊戲畫面信息存入二維數組:數組下標映射遊戲中位置座標,數組元素的值(0,1…)分別表示遊戲場景中不同的對象(空白處,蛇頭…),遍歷數組根據不同的值輸出遊戲畫面。每次輸出前將光標調至首行首列處,覆蓋之前的輸出畫面,達到刷新遊戲畫面的效果。
- 小蛇移動與成長:根據方向變量的值(1,2,3,4)來向某一方向(上,下,左,右)持續前進,當方向按鍵按下時,修改方向變量的值以改變方向。蛇頭對應的數組元素的數值爲1,從頭到尾,數值遞增(2,3,4,5…),每次更新畫面,使數組中大於0的數組元素(蛇頭蛇身)的值加一,蛇頭的值變爲2,根據行進方向在新方向上生成新的蛇頭(數值爲1),未吃到食物的情況下,將蛇尾變爲空白。即通過向目標方向生成一個新蛇頭,去掉蛇尾,來達到移動的效果,而吃掉食物時生成新蛇頭而不去掉蛇尾,使長度加一。
- 食物生成:當食物被吃掉後,隨機生成一個處於空白處的座標,改變該座標的值爲新的食物。
以下爲帶註釋的完整源代碼:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define high 25 //畫布高
#define width 60 //畫布寬
#define border -1 //邊界
#define blank 0 //空白
#define head 1 //蛇頭
#define food -2 //食物
int canvas[high+1][width+1]; //畫布數組
int direction; //行進方向
int head_h,head_w; //蛇頭座標
int tail_h,tail_w; //蛇尾座標
int food_h,food_w; //食物座標
int length; //貪吃蛇長度(包括蛇頭)
int Isover; //遊戲結束標誌
void Startup(); //遊戲數值初始化
void Show(); //遊戲界面輸出
void UpdateInput(); //因輸入導致的遊戲狀態更新
void UpdateNormal(); //與輸入無關的遊戲狀態更新
int main()
{
Startup();
while(Isover){
Show();
UpdateInput();
UpdateNormal();
}
printf("\ngame over!\n");
Sleep(2000);
system("pause");
return 0;
}
void Startup(){
/*設置邊界值*/
for(int i=0;i<=width;i++){
canvas[0][i]=border;
canvas[high][i]=border;
}
for(int i=0;i<=high;i++){
canvas[i][0]=border;
canvas[i][width]=border;
}
/*設置貪吃蛇初始位置*/
head_h=high/2;
head_w=width/2;
canvas[head_h][head_w]=head;
/*貪吃蛇初始長度*/
length=6;
for(int i=1;i<length;i++){ //設置蛇身,應與初始移動方向相反
canvas[head_h][head_w-i]=i+1;
}
/*設置初始方向*/
direction=4;
/*設置食物位置,隨機出現*/
srand(time(NULL));
do{
food_h=rand()%high;
food_w=rand()%width;
}while(canvas[food_h][food_w]!=blank);
canvas[food_h][food_w]= food;
/*設置遊戲結束條件*/
Isover=1;
}
void Show(){
HideCursor(); //隱藏光標
gotoxy(1,1); //回調光標位置,刷新畫面
for(int i=0;i<=high;i++){ //輸出遊戲界面
for(int j=0;j<=width;j++){
if(canvas[i][j] == border){ //邊界
printf("#");
}
else if(canvas[i][j] == head ){ //蛇頭
printf("@");
}
else if(canvas[i][j]== blank){ //空白處
printf(" ");
}
else if(canvas[i][j]== food){ //食物
printf("O");
}
else if(canvas[i][j]> 0){ //蛇身
printf("*");
}
}
printf("\n");
}
printf("\nLength of the snake:%2d",length);
}
void UpdateInput(){
char key_W=GetKeyState('W'), //監測 W 鍵是否按下
key_S=GetKeyState('S'), //監測 S 鍵是否按下
key_A=GetKeyState('A'), //監測 A 鍵是否按下
key_D=GetKeyState('D'), //監測 D 鍵是否按下
key_BS=GetKeyState(' '); //監測 空格 鍵是否按下
if(kbhit()){ //當有鍵按下時
if(key_BS<0){ //當按下 空格鍵 時,遊戲暫停
printf("\n遊戲暫停!");
system("pause");
system("cls");
}
if(key_W<0 && direction!=2){ //當按下 W 鍵,且原方向不爲下時,上移
direction=1;
}
if(key_S<0 && direction!=1){ //當按下 S 鍵,且原方向不爲上時,下移
direction=2;
}
if(key_A<0 && direction!=4){ //當按下 A 鍵,且原方向不爲右時,左移
direction=3;
}
if(key_D<0 && direction!=3){ //當按下 D 鍵,且原方向不爲左時,右移
direction=4;
}
}
}
void UpdateNormal(){
int max=0;
for(int i=1;i<high;i++){ //遍歷畫布
for(int j=1;j<width;j++){
if(canvas[i][j] > 0){ //使蛇身的值自增
canvas[i][j]++;
if(canvas[i][j]>max){ //定位數值最大點,即蛇尾處
max=canvas[i][j];
tail_h=i;
tail_w=j;
}
}
}
}
switch(direction){ //蛇頭位置向當前方向移動
case 1:head_h--;break;
case 2:head_h++;break;
case 3:head_w--;break;
case 4:head_w++;break;
}
if(canvas[head_h][head_w] == blank){ //新蛇頭在空白處
canvas[head_h][head_w] = head;
canvas[tail_h][tail_w] = blank;
}
else if(canvas[head_h][head_w] == food){ //新蛇頭在食物處
length++;
canvas[head_h][head_w] = head;
do{ //隨機出現食物,且食物只能刷新在空白處
food_h=rand()%high;
food_w=rand()%width;
}while(canvas[food_h][food_w]!=blank);
canvas[food_h][food_w]= food;
}
else{ //新蛇頭在邊界處或蛇身處
Isover=0;
}
}
void gotoxy(int x,int y){ //回調光標
COORD pos;
pos.X=x-1;
pos.Y=y-1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void HideCursor(){ //隱藏光標函數
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = sizeof(cursor);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(handle, &cursor);
}
以上內容在觀看河海大學童晶老師的C語言遊戲課程的基礎上總結改進完成。