C語言 貪吃蛇實現(不閃屏)
阿新 • • 發佈:2019-01-27
不費話,直接上程式碼。VC++ 6.0可以完美執行,VS2015等版本需要做點修改,請按提示將“scanf”這些函式改成“_scanf”這樣的形式即可。
不閃屏的原理部分請參考這篇文章
程式碼只有兩百多行,很多地方都加上了註釋,有疑問可以留言
/*
* File : myRetroSnake.cpp
* Author : weixinhum
* Date : 2017.5.16
* Function : Snake game of overcoming the splash screen
*/
#include "stdio.h"
#include "stdlib.h"
#include <Windows.h>
#include <time.h>
#include <conio.h> //鍵盤按下判斷相關標頭檔案
#define LENGTH 15
int i;
HANDLE hOutput, hOutBuf;//控制檯螢幕緩衝區控制代碼
HANDLE *houtpoint;//顯示指標
COORD coord = { 0,0 };
//雙緩衝處理顯示
DWORD bytes = 0;
unsigned char data[LENGTH + 2][LENGTH + 2];//最後的+2為牆符號
bool showcircle = false;
char direction = 'd';//蛇頭方向標誌位,'d'為向右,'s'為向下,'a'為向左,'w'為向上
int headx = 2, heady = 0;//蛇頭座標
int foodx = 0, foody = 0;//食物座標
bool running = true;//遊戲結束標誌位
char level[LENGTH];
int gamelevel = 1;//遊戲等級
int eatcount = 0;
struct SnakeBody//蛇身結構體
{
int x[LENGTH*LENGTH];
int y[LENGTH*LENGTH];
}snake;
int snakelength = 3;//蛇身長度
void show()//顯示要繪製的遊戲介面
{
showcircle = !showcircle;
if (showcircle)
{
houtpoint = &hOutput;
}
else
{
houtpoint = &hOutBuf;
}
//遊戲等級列印
coord.X = 50;//以(45,5)為起點,不用貼著左上角
coord.Y = 3;
sprintf(level, "level:%2d", gamelevel);
WriteConsoleOutputCharacterA(*houtpoint, level, strlen(level), coord, &bytes);
//遊戲內容列印
for (i = 0; i < LENGTH + 2; i++)
{
coord.X = 44;//以(45,5)為起點,不用貼著左上角
coord.Y = i + 5;
WriteConsoleOutputCharacterA(*houtpoint, (char*)data[i], (LENGTH + 2), coord, &bytes);
}
//設定新的緩衝區為活動顯示緩衝
SetConsoleActiveScreenBuffer(*houtpoint);
Sleep(200 / gamelevel);
}
void showover()//顯示遊戲結束
{
showcircle = !showcircle;
if (showcircle)
{
houtpoint = &hOutput;
}
else
{
houtpoint = &hOutBuf;
}
memset(data, 255, (LENGTH + 2)*(LENGTH + 2));//清零
for (i = 0; i < LENGTH + 2; i++)
{
coord.X = 44;//以(45,5)為起點,不用貼著左上角
coord.Y = i + 5;
WriteConsoleOutputCharacterA(*houtpoint, (char*)data[i], (LENGTH + 2), coord, &bytes);
}
coord.X = 44 + LENGTH / 2 - 3;
coord.Y = 5;
WriteConsoleOutputCharacterA(*houtpoint, "GAME OVER", 9, coord, &bytes);
//設定新的緩衝區為活動顯示緩衝
SetConsoleActiveScreenBuffer(*houtpoint);
}
void draw()//繪製遊戲介面
{
//遊戲介面繪製,裡面用到了擴充套件的ASCII碼錶對應的字元數字值
memset(data, 255, (LENGTH + 2)*(LENGTH + 2));//清零
//繪製邊界
for (i = 0; i < (LENGTH + 2); i++)
{
data[0][i] = 205; // ═
data[i][0] = 186; // ║
data[LENGTH + 1][i] = 205; // ═
data[i][LENGTH + 1] = 186; // ║
}
data[0][0] = 201; // ╔
data[LENGTH + 1][0] = 200; // ╚
data[0][(LENGTH + 2) - 1] = 187; // ╗
data[LENGTH + 1][(LENGTH + 2) - 1] = 188; // ╝
//畫蛇
for (i = 0; i < snakelength; i++)
{
data[snake.y[i] + 1][(snake.x[i] + 1)] = 233;
}
//畫食物
data[foody + 1][(foodx + 1)] = 236;
}
void generatefood()//食物生成
{
bool dogenerate = true;
while (dogenerate)
{
srand((unsigned)time(NULL)); //初始化隨機數
foodx = rand() % LENGTH;
foody = rand() % LENGTH;
dogenerate = false;
for (i = 0; i < snakelength; i++)
{
if (snake.y[i] == foody && foodx == snake.x[i])
{
dogenerate = true;
}
}
}
}
bool control()//控制資訊處理
{
//鍵盤按下判斷
char getkeych;
if (kbhit())
{/* 判斷是否按下鍵盤,如果按下,ch接收鍵盤輸入 */
char key = _getch();
switch (key)
{
case 'd':
case 's':
case 'a':
case 'w':direction = key; break;
}
}
switch (direction)
{
case 'd':headx++; break;
case 's':heady++; break;
case 'a':headx--; break;
case 'w':heady--; break;
}
//越界穿牆
if (headx < 0)
{
headx = LENGTH - 1;
}
else if (headx > LENGTH - 1)
{
headx = 0;
}
if (heady < 0)
{
heady = LENGTH - 1;
}
else if (heady > LENGTH - 1)
{
heady = 0;
}
//遊戲結束判斷
for (i = 0; i < snakelength; i++)
{
if (snake.x[i] == headx && snake.y[i] == heady)
{
return false;
}
}
//吃到食物判斷
if (foodx == headx && foody == heady)
{
snakelength++;
snake.x[snakelength - 1] = headx;
snake.y[snakelength - 1] = heady;
generatefood();
eatcount++;
gamelevel = eatcount / 10 + 1;
}
//蛇身資料更新
for (i = 0; i < snakelength - 1; i++)
{
snake.x[i] = snake.x[i + 1];
snake.y[i] = snake.y[i + 1];
}
snake.x[snakelength - 1] = headx;
snake.y[snakelength - 1] = heady;
return true;
}
void main()
{
SetConsoleOutputCP(437);//改成標準英文輸出標誌,這樣可以使用擴充套件ASCII碼錶,以方便後面遊戲介面的製作
//建立新的控制檯緩衝區
hOutBuf = CreateConsoleScreenBuffer(
GENERIC_WRITE,//定義程序可以往緩衝區寫資料
FILE_SHARE_WRITE,//定義緩衝區可共享寫許可權
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
hOutput = CreateConsoleScreenBuffer(
GENERIC_WRITE,//定義程序可以往緩衝區寫資料
FILE_SHARE_WRITE,//定義緩衝區可共享寫許可權
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
//隱藏兩個緩衝區的游標
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize = 1;
SetConsoleCursorInfo(hOutput, &cci);
SetConsoleCursorInfo(hOutBuf, &cci);
//蛇身初設資料初始化
snake.x[2] = 2; snake.y[2] = 0;
snake.x[1] = 1; snake.y[1] = 0;
snake.x[0] = 0; snake.y[0] = 0;
generatefood();//生成食物
while (running)
{
if (!control())
{
showover();
break;
}
draw();
show();
}
scanf("%d", &i);//等待退出
}