1. 程式人生 > >C語言 貪吃蛇實現(不閃屏)

C語言 貪吃蛇實現(不閃屏)

  不費話,直接上程式碼。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);//等待退出 }