테트리스 소스코드 (더블버퍼 적용)

2024. 11. 7. 16:53c,c++(cpp)

반응형

#include <stdio.h>
#include <windows.h>
#include <time.h>

#define hight 20
#define weight 12
#define BufferWidth 40
#define BufferHeight 24


HANDLE hBuffer[2];
int screenIndex;

int currentBlock;
int block_y = 0;
int block_x = 3;
int rotation = 1;


int map[hight][weight]{
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1}
};


int block1[4][4][4] = {
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{0,0,0,1},
{0,0,0,1},
{0,0,0,1},
{0,0,0,1}
},
{
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{1,1,1,1}
}
};
int block2[4][4][4] = {
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,1,1,0}
},
{
{0,1,1,1},
{0,0,0,1},
{0,0,0,1},
{0,0,0,1}
},
{
{0,0,0,1},
{0,0,0,1},
{0,0,0,1},
{0,1,1,1}
},
{
{0,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,1,1,1}
}
};
int block3[4][4][4] = {
{
{0,0,0,0},
{0,1,1,0},
{0,1,1,0},
{0,0,0,0}
},
{
{0,0,0,0},
{0,1,1,0},
{0,1,1,0},
{0,0,0,0}
},
{
{0,0,0,0},
{0,1,1,0},
{0,1,1,0},
{0,0,0,0}
},
{
{0,0,0,0},
{0,1,1,0},
{0,1,1,0},
{0,0,0,0}
}
};
int block4[4][4][4] = {
{
{1,1,1,0},
{1,0,1,0},
{1,0,1,0},
{0,0,0,0}
},
{
{0,0,0,0},
{1,0,1,0},
{1,0,1,0},
{1,1,1,0}
},
{
{0,1,1,1},
{0,0,0,1},
{0,1,1,1},
{0,0,0,0}
},
{
{0,1,1,1},
{0,1,0,0},
{0,1,1,1},
{0,0,0,0}
}
};

int block[4][4] = {
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}

};
int(*blocks[4])[4][4] = { block1, block2, block3, block4 };


void MoveCursor(int x, int y);
void MapPlay();
void BlockPlay();
void HideCursor();
void ContRoller();
void CheckLeft();
void CheckSideLeft();
void CheckSideRight();
void CheckRight();
void ChekcBottom();
void Merge();
void CheckLine();
void UpdateBlock();
void GenerateRandomBlock();



#pragma region Double Buffer

//버퍼 초기화
void InitBuffer();
//버퍼 뒤집기
void FlipBuffer();
//버퍼 창 깨끗이
void ClearBuffer();
//버퍼 쓰기
void WriteBuffer(int x, int y, const char* shape, int color);
//버퍼 해제
void ReleaseBuffer();
#pragma endregion


int main() {
InitBuffer();
clock_t curtime = clock();

GenerateRandomBlock();
while (1) {
ClearBuffer();
MapPlay();

BlockPlay();

if (clock() - curtime >= 200) {
block_y++;
curtime = clock();
}

ContRoller();

FlipBuffer();
Sleep(50);
}

ReleaseBuffer();
return 0;
}

void MoveCursor(int x, int y)
{
COORD pos;
pos.X = x * 2;
pos.Y = y;

SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

void MapPlay()
{
for (int y = 0; y < hight; y++) {
for (int x = 0; x < weight; x++) {
if (map[y][x] == 1) {
/*MoveCursor(x, y);
printf("■");*/
WriteBuffer(x, y, "■",7);
}
}
}
}

void BlockPlay()
{

for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (block[y][x] == 1) {
/*MoveCursor(x + block_x, y + block_y);
printf("■");*/
WriteBuffer(x + block_x, y + block_y, "■",3);

}
}
}
}

void HideCursor() {
CONSOLE_CURSOR_INFO info;
info.dwSize = 1;
info.bVisible = FALSE;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
}

void ContRoller()
{
CheckLine();
ChekcBottom();
if (GetAsyncKeyState(VK_LEFT))
{
CheckSideLeft();
CheckLeft();
block_x--;
}
if (GetAsyncKeyState(VK_RIGHT))
{
CheckSideRight();
CheckRight();
block_x++;
}
if (GetAsyncKeyState(VK_UP)) {
rotation = (rotation + 1) % 4;
UpdateBlock();
}
if (GetAsyncKeyState(VK_DOWN)) {
rotation = (rotation - 1 + 4) % 4;
UpdateBlock();
}
if (GetAsyncKeyState(VK_SPACE)) 
{
block_y++; 
}


}

void CheckLeft()
{
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (block[y][x] == 1) {
if (block_x + x <= 1) {
block_x++;
return;
}

}
}
}
}
void CheckRight()
{
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (block[y][x] == 1) {
if (block_x + x >= weight - 2) {
block_x--;
return;
}

}
}
}
}

void ChekcBottom() {

for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (block[y][x] == 1) {
if (block_y + y >= hight - 1 || map[block_y + y][block_x + x] == 1) {
Merge();
block_x = 3;
block_y = 0;
GenerateRandomBlock();
return;
}
}
}
}
}

void Merge() {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (block[y][x] == 1) {
map[block_y + y - 1][block_x + x] = 1;
}
}
}
}

void CheckSideLeft() {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (block[y][x] == 1) {
if (map[block_y + y][block_x + x - 1] == 1) {
block_x++;
return;
}

}
}
}
}

void CheckSideRight() {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (block[y][x] == 1) {
if (map[block_y + y][block_x + x + 1] == 1) {
block_x--;
return;
}
}
}
}
}


void CheckLine() {
for (int y = hight - 2; y >= 0; y--) {
int flag = 1;

for (int x = 1; x < weight - 1; x++) {
if (map[y][x] == 0) {
flag = 0;
break;
}
}

if (flag == 1) {
for (int ty = y; ty > 0; ty--) {
for (int x = 1; x < weight - 1; x++) {
map[ty][x] = map[ty - 1][x];
}
}
for (int x = 1; x < weight - 1; x++) {
map[0][x] = 0;
}
y++;
}

}
}

void UpdateBlock() {
srand((unsigned int)time(NULL));
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
block[y][x] = blocks[currentBlock][rotation][y][x];
}
}
}

void GenerateRandomBlock() {
srand((unsigned int)time(NULL));
currentBlock = rand() % 4;
rotation = 0;
block_x = 3;
block_y = 0;
UpdateBlock();
}

#pragma region Double Buffer
void InitBuffer()
{
screenIndex = 0;

COORD size = { BufferWidth, BufferHeight };
SMALL_RECT rect = { 0, 0, (SHORT)(BufferWidth - 1), (SHORT)(BufferHeight - 1) };

hBuffer[0] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleScreenBufferSize(hBuffer[0], size);
SetConsoleWindowInfo(hBuffer[0], TRUE, &rect);

hBuffer[1] = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleScreenBufferSize(hBuffer[1], size);
SetConsoleWindowInfo(hBuffer[1], TRUE, &rect);

CONSOLE_CURSOR_INFO info;
info.dwSize = 1;
info.bVisible = FALSE;
SetConsoleCursorInfo(hBuffer[0], &info);
SetConsoleCursorInfo(hBuffer[1], &info);


HWND consoleWindow = GetConsoleWindow();
RECT r;
GetWindowRect(consoleWindow, &r); 
MoveWindow(consoleWindow, r.left, r.top, BufferWidth * 10, BufferHeight * 20, TRUE);
}

void FlipBuffer()
{
SetConsoleActiveScreenBuffer(hBuffer[screenIndex]);

screenIndex = !screenIndex;
}

void ClearBuffer()
{
COORD pos = { 0, 0 };
DWORD dw;
FillConsoleOutputCharacter(hBuffer[screenIndex],' ', BufferWidth * BufferHeight, pos, &dw);
}

void WriteBuffer(int x, int y, const char* shape, int color)
{
COORD pos = { x * 2, y };

SetConsoleCursorPosition(hBuffer[screenIndex], pos);
SetConsoleTextAttribute(hBuffer[screenIndex], color);

DWORD dw;
WriteFile(hBuffer[screenIndex], shape, strlen(shape), &dw, NULL);
}
void ReleaseBuffer()
{
CloseHandle(hBuffer[0]);
CloseHandle(hBuffer[1]);
}

#pragma endregion

반응형