c++雙緩存技術實作控制台不閃屏
貪吃蛇為例
實作雙緩存技術實作控制台不閃屏,以上次寫的貪吃蛇為例子。
連結:簡單的貪吃蛇
話不多說,上代碼。
#include<iostream>
#include<Windows.h>
#include<conio.h>
using namespace std;
typedef struct Node
{
int Data[2]; //資料域
struct Node *next; //指針域
}Snake;
Snake * NewSnake(){//初始化蛇
Snake *head, *p,*tail;
head = (Snake*)malloc(sizeof(Snake));
p = (Snake*)malloc(sizeof(Snake));
tail = (Snake*)malloc(sizeof(Snake));
if (head == NULL || p == NULL || tail == NULL)
return head;
head->Data[0] = 10;
head->Data[1] = 10;
p->Data[0] = 11;
p->Data[1] = 10;
tail->Data[0] = 12;
tail->Data[1] = 10;
head->next = p;
p->next = tail;
tail->next = NULL;
return head;
}
void PrintSnake(Snake *head,int Map[20][20])
{//載入地圖
Snake* p = head;
if (p != NULL){
while (p != NULL)
{
Map[p->Data[0]][p->Data[1]] = 2;
p = p->next;
}
}
}
void Move(Snake * head,bool & GameState, int Map[20][20], int cx, int cy){
//改變方向,重新整理資料
Snake *one = head;
Snake *two = (Snake*)malloc(sizeof(Snake));
two->Data[0] = one->Data[0];
two->Data[1] = one->Data[1];
two->next = one->next;
one->Data[0] += cx;
one->Data[1] += cy;
one->next = two;
if (Map[one->Data[0]][one->Data[1]] == 3)
{//如果吃到豆子,則産生新的豆子
Map[one->Data[0]][one->Data[1]] = 2;
while (true)
{
int Dx = rand() % 20;
int Dy = rand() % 20;
if (Map[Dx][Dy] == 0){
Map[Dx][Dy] = 3;
break;
}
}
}
else if (Map[one->Data[0]][one->Data[1]] == 0)
{//什麼都沒有吃到
Map[one->Data[0]][one->Data[1]] = 2;
Snake *delone, *deltwo;
delone = one;
deltwo = one->next;
while (deltwo->next != NULL){
delone = deltwo;
deltwo = delone->next;
}
Map[deltwo->Data[0]][deltwo->Data[1]] = 0;
free(deltwo);
delone->next = NULL;
}
else{//吃到牆壁或是自己
GameState = false;
}
}
void MapPrint(int Map[20][20]){
//繪制地圖
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (Map[i][j] == 0){ cout << " "; }
else if (Map[i][j] == 1){ cout << "■"; }
else if (Map[i][j] == 2){ cout << "●"; }
else if (Map[i][j] == 3){ cout << "★"; }
}
cout << endl;
}
}
void main(){
//HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
//CONSOLE_CURSOR_INFO CursorInfo;
//GetConsoleCursorInfo(handle, &CursorInfo);//擷取控制台光标資訊
//CursorInfo.bVisible = false; //隐藏控制台光标
//SetConsoleCursorInfo(handle, &CursorInfo);
int Map[20][20] = {//地圖的初始化
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
};
bool GameState = true;
char State = 'x';
Snake *MySnake = NewSnake();//實體化蛇
PrintSnake(MySnake,Map);
//載入地圖和蛇
MapPrint(Map);
HANDLE hOutput;
COORD coord = { 0, 0 };
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//建立新的緩沖區
HANDLE hOutBuf = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
//設定新的緩沖區為活動顯示緩沖
SetConsoleActiveScreenBuffer(hOutBuf);
//隐藏兩個緩沖區的光标
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize = 1;
SetConsoleCursorInfo(hOutput, &cci);
SetConsoleCursorInfo(hOutBuf, &cci);
//雙緩沖處理顯示
DWORD bytes = 100;
char data[1600];
while (GameState){
Sleep(200);//重新整理時間,機關毫秒
//system("cls");
MapPrint(Map);
char Control;
if (_kbhit()){
Control = _getch();
if ((Control == 'w' && State != 's') || (Control == 's' && State != 'w') || (Control == 'a' && State != 'd') || (Control == 'd' && State != 'a'))
{//判斷是否可以操作
State = Control;
}
}
switch (State)
{
case 'w':
Move(MySnake, GameState, Map, -1, 0);
break;
case 'a':
Move(MySnake, GameState, Map, 0, -1);
break;
case 's':
Move(MySnake, GameState, Map, 1, 0);
break;
case 'd':
Move(MySnake, GameState, Map, 0, 1);
break;
default:break;
}
ReadConsoleOutputCharacterA(hOutput, data, 1600, coord, &bytes);
WriteConsoleOutputCharacterA(hOutBuf, data, 1600, coord, &bytes);
system("cls");
}
//1.讀取按鍵
//2.根據下一步修改連結清單資料并更改地圖資料
//3.判斷是否結束如果沒有檢視是否要重新整理地圖資料,重新整理/不重新整理
//4.地圖重新整理
system("cls");
cout << "遊戲結束" << endl;
cout<< "按任意鍵退出" << endl;
ReadConsoleOutputCharacterA(hOutput, data, 1600, coord, &bytes);
WriteConsoleOutputCharacterA(hOutBuf, data, 1600, coord, &bytes);
system("pause");
}
PS:歡迎交流讨論。