안녕하세요. 언제나휴일입니다.
동영상 강의를 제작하면서 만든 코드입니다.
불필요한 코드가 남아있지만 그대로 올립니다.
동영상 강의(유튜브 무료 동영상입니다.)
Program.cpp
#include <Windows.h>
#include "Document.h"
#define BOARD_SX 70
#define BOARD_SY 50
#define MY_WIDTH 15
#define MY_HEIGHT 15
#define MY_RX(x) (BOARD_SX+(x)*MY_WIDTH)
#define MY_RY(y) (BOARD_SY+(y)*MY_HEIGHT)
#define NEXT_SX 270
#define MY_NRX(x) (NEXT_SX+(x)*MY_WIDTH)
#define MY_NRY(y) (MY_RY(y))
#define DIAGRAM_WIDTH 4
#define DIAGRAM_HEIGHT 4
#define DW DIAGRAM_WIDTH
#define DH DIAGRAM_HEIGHT
#define TID_DROP 1032
#define SCORE_X MY_NRX(0)
#define SCORE_Y MY_NRY(5)
HBRUSH hbrushes[MAX_DIAGRAM];
void OnCreate(HWND hWnd, CREATESTRUCT* pcs)
{
Document* doc = Document::GetSingleton();
doc->MakeDiagram();
SetTimer(hWnd, TID_DROP, 500, 0);
hbrushes[0] = CreateSolidBrush(RGB(200, 20, 30));
hbrushes[1] = CreateSolidBrush(RGB(20, 200, 30));
hbrushes[2] = CreateSolidBrush(RGB(30, 20, 200));
hbrushes[3] = CreateSolidBrush(RGB(127, 50, 80));
hbrushes[4] = CreateSolidBrush(RGB(50, 80, 127));
hbrushes[5] = CreateSolidBrush(RGB(80, 127, 50));
hbrushes[6] = CreateSolidBrush(RGB(120, 50, 120));
}
void Ending(HWND hWnd)
{
KillTimer(hWnd, TID_DROP);
MessageBox(hWnd, TEXT("게임 오버"), TEXT("끝"), MB_OK);
DestroyWindow(hWnd);
}
void OnTimer(HWND hWnd, DWORD tid)
{
Document* doc = Document::GetSingleton();
bool is_end = false;
if (doc->MoveDown(&is_end) == false)
{
}
InvalidateRect(hWnd, 0, true);
if (is_end)
{
Ending(hWnd);
}
}
void MoveLeftProc(HWND hWnd)
{
Document* doc = Document::GetSingleton();
doc->MoveLeft();
}
void MoveRightProc(HWND hWnd)
{
Document* doc = Document::GetSingleton();
doc->MoveRight();
}
void TurnProc(HWND hWnd)
{
Document* doc = Document::GetSingleton();
doc->MoveTurn();
}
void MoveDownAsFar(HWND hWnd)
{
Document* doc = Document::GetSingleton();
bool is_end = false;
while (doc->MoveDown(&is_end));
InvalidateRect(hWnd, 0, true);
if (is_end)
{
Ending(hWnd);
}
}
void OnKeyDown(HWND hWnd, DWORD key, LPARAM lParam)
{
switch (key)
{
case VK_UP: TurnProc(hWnd); break;
case VK_LEFT: MoveLeftProc(hWnd); break;
case VK_RIGHT: MoveRightProc(hWnd); break;
case VK_SPACE: MoveDownAsFar(hWnd); break;
}
InvalidateRect(hWnd, 0, true);
}
void DrawBoardGrid(HWND hWnd, HDC hdc)
{
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(40, 40, 40));
HPEN oPen = (HPEN)SelectObject(hdc, hPen);
for (int r = 0; r <= BOARD_ROW; r++)
{
MoveToEx(hdc, BOARD_SX, MY_RY(r), 0);
LineTo(hdc, MY_RX(BOARD_COL), MY_RY(r));
}
for (int c = 0; c <= BOARD_COL; c++)
{
MoveToEx(hdc, MY_RX(c), MY_RY(0), 0);
LineTo(hdc, MY_RX(c), MY_RY(BOARD_ROW));
}
SelectObject(hdc, oPen);
DeleteObject(hPen);
}
void DrawGameBoard(HWND hWnd, HDC hdc)
{
DrawBoardGrid(hWnd, hdc);
Document* doc = Document::GetSingleton();
bs_arr bs = doc->GetBoard();
HBRUSH hBrush, oBrush;
oBrush = (HBRUSH)SelectObject(hdc, hbrushes[0]);
for (int y = 0; y < BOARD_ROW; y++)
{
for (int x = 0; x < BOARD_COL; x++)
{
if (bs[y][x])
{
int bindex = bs[y][x] - 1;
hBrush = hbrushes[bindex];
SelectObject(hdc, hBrush);
Ellipse(hdc, MY_RX(x), MY_RY(y), MY_RX(x + 1) - 1, MY_RY(y + 1) - 1);
}
}
}
SelectObject(hdc, oBrush);
}
void DrawDiagram(HWND hWnd, HDC hdc)
{
Document* doc = Document::GetSingleton();
Diagram* now = doc->GetNow();
block bl = now->GetBlock();
int x = now->GetX();
int y = now->GetY();
HBRUSH hBrush = hbrushes[now->GetBNum()];
HBRUSH oBrush = (HBRUSH)SelectObject(hdc, hBrush);
for (int cx = 0; cx < DW; cx++)
{
for (int cy = 0; cy < DH; cy++)
{
if (bl[cy][cx] == 1)
{
Ellipse(hdc,
MY_RX(x+cx),
MY_RY(y+cy),
MY_RX(x + cx+1) - 1,
MY_RY(y + cy+ 1) - 1);
}
}
}
SelectObject(hdc, oBrush);
}
void DrawNextBoard(HWND hWnd, HDC hdc)
{
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(40, 40, 40));
HPEN oPen = (HPEN)SelectObject(hdc, hPen);
for (int r = 0; r <= DH; r++)
{
MoveToEx(hdc, NEXT_SX, MY_NRY(r), 0);
LineTo(hdc, MY_NRX(DH), MY_NRY(r));
}
for (int c = 0; c <= DW; c++)
{
MoveToEx(hdc, MY_NRX(c), MY_NRY(0), 0);
LineTo(hdc, MY_NRX(c), MY_NRY(DW));
}
SelectObject(hdc, oPen);
DeleteObject(hPen);
}
void DrawNextDiagram(HWND hWnd, HDC hdc)
{
Document* doc = Document::GetSingleton();
Diagram* next = doc->GetNext();
block bl = next->GetBlock();
int x = 0;
int y = 0;
HBRUSH hBrush = hbrushes[next->GetBNum()];
HBRUSH oBrush = (HBRUSH)SelectObject(hdc, hBrush);
for (int cx = 0; cx < DW; cx++)
{
for (int cy = 0; cy < DH; cy++)
{
if (bl[cy][cx] == 1)
{
Ellipse(hdc,
MY_NRX(x + cx),
MY_NRY(y + cy),
MY_NRX(x + cx + 1) - 1,
MY_NRY(y + cy + 1) - 1);
}
}
}
SelectObject(hdc, oBrush);
}
void DrawScore(HWND hWnd, HDC hdc)
{
Document* doc = Document::GetSingleton();
int score = doc->GetScore();
wchar_t buf[256];
wsprintf(buf, TEXT("점수: %d"), score);
TextOut(hdc, SCORE_X, SCORE_Y, buf, lstrlen(buf));
}
void OnDraw(HWND hWnd, HDC hdc)
{
DrawGameBoard(hWnd, hdc);
DrawDiagram(hWnd, hdc);
DrawNextBoard(hWnd, hdc);
DrawNextDiagram(hWnd, hdc);
DrawScore(hWnd, hdc);
}
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
OnDraw(hWnd, hdc);
EndPaint(hWnd, &ps);
}
void OnDestroy(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
for (int i = 0; i < MAX_DIAGRAM; i++)
{
DeleteObject(hbrushes[i]);
}
PostQuitMessage(0);
}
LRESULT CALLBACK MainProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch (iMessage)
{
case WM_CREATE: OnCreate(hWnd, (CREATESTRUCT*)lParam); return 0;
case WM_TIMER: OnTimer(hWnd, (DWORD)wParam); return 0;
case WM_KEYDOWN: OnKeyDown(hWnd, (DWORD)wParam, lParam); return 0;
case WM_PAINT: OnPaint(hWnd); return 0;
case WM_DESTROY: OnDestroy(hWnd, wParam, lParam); return 0;
}
return DefWindowProc(hWnd, iMessage, wParam, lParam);
}
INT APIENTRY WinMain(HINSTANCE hIns, HINSTANCE hPrev, LPSTR cmd, INT nShow)
{
WNDCLASS wndclass = { 0 };
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.style = CS_DBLCLKS;
wndclass.lpfnWndProc = MainProc;
wndclass.lpszClassName = TEXT("테트리스");
wndclass.hCursor = LoadCursor(0, IDC_ARROW);
wndclass.hIcon = LoadIcon(0, IDI_APPLICATION);
wndclass.hInstance = hIns;
RegisterClass(&wndclass);
HWND hWnd = CreateWindow(TEXT("테트리스"),
TEXT("테트리스"), WS_OVERLAPPEDWINDOW, 100, 100, 410, 400,
0, 0, hIns, 0);
ShowWindow(hWnd, nShow);
MSG Message;
while (GetMessage(&Message, 0, 0, 0))
{
DispatchMessage(&Message);
}
return 0;
}
Document.h
#pragma once
#include "Diagram.h"
#include "Board.h"
#define SX 3
#define SY 0
class Document
{
static Document* singleton;
Diagram* now;
Diagram* next;
Board* board;
int score;
public:
static Document *GetSingleton();
void MakeDiagram();
bool MoveDown(bool* is_end);
bool MoveLeft();
bool MoveRight();
Diagram* GetNow();
bool MoveTurn();
Diagram *GetNext();
bs_arr GetBoard();
int GetScore()const;
private:
void ChangeDiagram();
Document();
bool MoveEnable(Diagram *now,int cx,int cy,bool is_turn=false);
};
Document.cpp
#include "Document.h"
Document* Document::singleton;
Document* Document::GetSingleton()
{
if (singleton == 0)
{
singleton = new Document();
}
return singleton;
}
Document::Document()
{
now = new Diagram();
next = new Diagram();
board = new Board();
score = 0;
MakeDiagram();
}
int Document::GetScore()const
{
return score;
}
void Document::MakeDiagram()
{
next->SetPosition(SX, SY);
now->SetPosition(SX, SY);
}
void Document::ChangeDiagram()
{
now->SetPosition(next);
next->SetPosition(SX, SY);
}
bool Document::MoveDown(bool *is_end)
{
*is_end = false;
if (MoveEnable(now, 0, 1))
{
now->Move(0, 1);
return true;
}
else
{
int bnum = now->GetBNum();
block bl = now->GetBlock();
int x = now->GetX();
int y = now->GetY();
score +=board->AddBlock(bnum, bl, x, y);
}
ChangeDiagram();
block bl = now->GetBlock();
int x = now->GetX();
int y = now->GetY();
if (board->IsCrash(bl, x, y))
{
*is_end = true;
}
return false;
}
bool Document::MoveLeft()
{
if (MoveEnable(now, -1, 0))
{
now->Move(-1, 0);
return true;
}
return false;
}
bool Document::MoveRight()
{
if (MoveEnable(now, 1, 0))
{
now->Move(1, 0);
return true;
}
return false;
}
bool Document::MoveTurn()
{
if (MoveEnable(now, 0, 0,true))
{
now->Turn();
return true;
}
return false;
}
Diagram* Document::GetNow()
{
return now;
}
Diagram* Document::GetNext()
{
return next;
}
bool Document::MoveEnable(Diagram* now, int cx, int cy , bool is_turn)
{
block bl = now->GetBlock(is_turn);
int x = now->GetX() + cx;
int y = now->GetY() + cy;
return board->IsCrash(bl, x, y) == false;
}
bs_arr Document::GetBoard()
{
return board->GetBoardSpace();
}
Board.h
#pragma once
#define BOARD_COL 10
#define BOARD_ROW 18
#include "Diagram.h"
typedef const int(*bs_arr)[BOARD_COL];
class Board
{
int bs[BOARD_ROW][BOARD_COL];
public:
Board();
bool IsCrash(block bl, int x, int y);
int AddBlock(int bnum, block bl, int x, int y);
bs_arr GetBoardSpace();
private:
int LineCheck(int cy);
bool IsFull(int cy);
void MoveLine(int cy);
};
Board.cpp
#include "Board.h"
#include <string.h>
Board::Board()
{
for (int y = 0; y < BOARD_ROW; y++)
{
for (int x = 0; x < BOARD_COL; x++)
{
bs[y][x] = 0;
}
}
}
bool Board::IsCrash(block bl, int x, int y)
{
for (int cx = 0; cx < DW; cx++)
{
for (int cy = 0; cy < DH; cy++)
{
if (bl[cy][cx])
{
if ((y + cy) >= BOARD_ROW || (x + cx < 0) || (x + cx) >= BOARD_COL)
{
return true;
}
if (bs[y + cy][x + cx])
{
return true;
}
}
}
}
return false;
}
int Board::AddBlock(int bnum, block bl, int x, int y)
{
for (int cy = 0; cy < DH; cy++)
{
for (int cx = 0; cx < DW; cx++)
{
if (bl[cy][cx])
{
bs[y + cy][x + cx] = bnum + 1;
}
}
}
return LineCheck(y+3);
}
bs_arr Board::GetBoardSpace()
{
return bs;
}
int Board::LineCheck(int cy)
{
int clc = 0;
for (int i = 0; i < DH; i++)
{
if (IsFull(cy))
{
MoveLine(cy);
clc++;
}
else
{
cy--;
}
}
return clc;
}
bool Board::IsFull(int cy)
{
for (int x = 0; x < BOARD_COL; x++)
{
if (bs[cy][x] == 0)
{
return false;
}
}
return true;
}
void Board::MoveLine(int cy)
{
memcpy(bs + 1, bs, sizeof(int) * BOARD_COL * cy);
}
Diagram.h
#pragma once
#define MAX_DIAGRAM 7
#define MAX_TURN 4
#define DIAGRAM_WIDTH 4
#define DIAGRAM_HEIGHT 4
#define DW DIAGRAM_WIDTH
#define DH DIAGRAM_HEIGHT
typedef const int(*block)[4];
class Diagram
{
int dindex;
int turn;
int x;
int y;
public:
Diagram();
int GetX()const;
int GetY()const;
int GetBNum()const;
void SetPosition(int sx, int sy);
void SetPosition(Diagram* next);
void Move(int cx, int cy);
void Turn();
block GetBlock(bool is_turn=false);
};
Diagram.cpp
#include "Diagram.h"
#include <stdlib.h>
#include <time.h>
const int block_vals[MAX_DIAGRAM][MAX_TURN][DH][DW] =
{
{
{
{0, 0, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{1, 1, 1, 1},
{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},
{1, 1, 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}
},
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
}
},//1
{
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 1, 1, 0},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 1, 1, 1},
{0, 0, 0, 0}
},
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 0, 1, 1},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 1, 1, 1},
{0, 0, 1, 0}
}
},//2
{
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 1}
},
{
{0, 0, 0, 0},
{0, 0, 0, 1},
{0, 0, 1, 1},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 1}
},
{
{0, 0, 0, 0},
{0, 0, 0, 1},
{0, 0, 1, 1},
{0, 0, 1, 0}
}
},//3
{
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 1, 1},
{0, 1, 1, 0}
},
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 1, 1},
{0, 1, 1, 0}
},
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0}
}
},//4
{
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 0, 1},
{0, 1, 1, 1},
{0, 0, 0, 0}
},
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 1}
},
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 1, 1, 1},
{0, 1, 0, 0}
}
},//5
{
{
{0, 0, 0, 0},
{0, 0, 1, 1},
{0, 0, 1, 0},
{0, 0, 1, 0}
},
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 1, 1, 1},
{0, 0, 0, 1}
},
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 0, 1, 0},
{0, 1, 1, 0}
},
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 1},
{0, 0, 0, 0}
}
}//6
};
Diagram::Diagram()
{
dindex = 0;
turn = 0;
x = 0;
y = 0;
}
int Diagram::GetX()const
{
return x;
}
int Diagram::GetY()const
{
return y;
}
int Diagram::GetBNum()const
{
return dindex;
}
void Diagram::SetPosition(int sx, int sy)
{
dindex = rand() % MAX_DIAGRAM;
turn = 0;
x = sx;
y = sy;
}
void Diagram::SetPosition(Diagram* next)
{
dindex = next->dindex;
turn = next->turn;
x = next->x;
y = next->y;
}
void Diagram::Move(int cx, int cy)
{
x += cx;
y += cy;
}
void Diagram::Turn()
{
turn = (turn + 1) % MAX_TURN;
}
block Diagram::GetBlock(bool is_turn)
{
if (is_turn)
{
int nturn = (turn + 1) % MAX_TURN;
return block_vals[dindex][nturn];
}
return block_vals[dindex][turn];
}