카테고리 없음

원블록 테트리스 만들기

뽀로로친구에디 2018. 4. 25. 10:41

VC++ (MFC) 공부하면서 SDI(싱글 도큐먼트 인터페이스)에서 Drawing(그리기) 예제를 이용하여 1블록 테트리스를 만들었습니다. 저는 예전에도 테트리스를 만들어봐서 즉흥적으로 만들었습니다. 다시 프로그래밍을 공부중이어서 옛날 생각을 더듬어 만들었는데 허접하네요. 





// SDrawingView.cpp : implementation of the CSDrawingView class

//  즉흥적으로 만들어본 한칸짜리 테트리스


#include "stdafx.h"

// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail

// and search filter handlers and allows sharing of document code with that project.

#ifndef SHARED_HANDLERS

#include "SDrawing.h"

#endif


#include "SDrawingDoc.h"

#include "SDrawingView.h"


#ifdef _DEBUG

#define new DEBUG_NEW

#endif






int x = 160;  // 초기 블럭 나올때 좌표 

int y = 100;

int w = 200;

int h = 120;

int test = 0;



UINT htimer;  // 타이머 

int gap = 20; // 간격

int xy[7][10]; //  테트리스 칸 

int mvblock[7][10]; //움직이는 블럭

int copyblock[7][10]; // 블럭 복사하기, 블럭 칸 완성되면 위에칸이 아래칸이 내려오게 보이기 




int mbblockX=3; // 최초 블록 위치 지정 

int mbblockY=0;


bool m_bNewblock = 0; 


bool bMoveLeft=1; // 왼쪽 움직임 가능여부 1이면 가능 0이면 불가

bool bMoveRight=1; // 오른쪽 움직임 가능여부

bool bMoveDown=1;  //아래쪽 움직임 가능여부


int gamePoint = 0; // 게임 포인트 - 몇줄 삭제한지 기록 








// CSDrawingView


IMPLEMENT_DYNCREATE(CSDrawingView, CView)


BEGIN_MESSAGE_MAP(CSDrawingView, CView)

ON_WM_CONTEXTMENU()


ON_WM_KEYDOWN()

ON_WM_TIMER()

END_MESSAGE_MAP()


// CSDrawingView construction/destruction


CSDrawingView::CSDrawingView()

: m_ptX(0)

, m_ptY(0)

, m_crColor(0)

,m_reRect(0,0,3000,3000)

{

// TODO: add construction code here

m_crColor = BLACK_BRUSH;

}


CSDrawingView::~CSDrawingView()

{

}


BOOL CSDrawingView::PreCreateWindow(CREATESTRUCT& cs)

{

// TODO: Modify the Window class or styles here by modifying

//  the CREATESTRUCT cs


return CView::PreCreateWindow(cs);

}


// CSDrawingView drawing



void CSDrawingView::OnDraw(CDC* pDC)

{

CSDrawingDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

if (!pDoc)

return;


// TODO: add draw code for native data here


int i, j;

int tempi, tempj;



//htimer = SetTimer(1, 500, NULL);//0.5초마다 블록이 떨어진다. 



CPen redpen(PS_SOLID, 1, RGB(255, 0, 0)); // 벽 그리기 

pDC->SelectObject(&redpen);



for (i = 0; i < 10; i++) //좌,우 벽 =3

{

xy[0][i] = 3; 

pDC->Rectangle(100, 100 + (gap*i), 120, 120 + (gap*i)); //좌측 벽 

xy[6][i] = 3;

pDC->Rectangle(220, 100 + (gap*i), 240, 120 + (gap*i)); //우측 벽 

}

for (j = 0; j < 7; j++) //하단 벽 =3

{

xy[j][9] = 3; 

pDC->Rectangle(100 + (gap*j), 280, 120 + (gap*j), 300); //하단 벽


}


if (m_bNewblock == 0)// 최초 빈공간 초기화 

{

for (i = 1; i < 9; i++) //빈공간 

{

for (j = 1; j < 6; j++)

{

xy[j][i] = 0;  //빈공간 = 0 


}

}

m_bNewblock = 1;

}




CPen greenpen(PS_SOLID, 1, RGB(0, 255, 0)); // 쌓인 벽돌 그리기 

pDC->SelectObject(&greenpen);


for (i = 0; i < 9; i++) 

{

for (j = 0; j < 6; j++)

{

if (xy[j][i] == 2)

{

pDC->Rectangle(100 + (gap*j), 100 + (gap*i), 120 + (gap*j), 120 + (gap*i));

}


}

}



// 배열 값으로 보여주기 


CClientDC dc(this);

CString strPoint;

for (i = 0; i < 7; i++)

{

for (j = 0; j < 10; j++)

{

strPoint.Format(_T("%d"), xy[i][j]);

dc.TextOutW(280 + (gap * i), 100 + (gap * j),strPoint);


}


}


tempi = mbblockX;

tempj = mbblockY;


CString strPoint2, strPoint3, strPoint4, strgamePoint, strmovePoint;

strPoint2.Format(_T("좌표 [%d][%d]=%d test=%d"),tempi,tempj, xy[tempi][tempj],test);

dc.TextOutW(0, 0, strPoint2);


strgamePoint.Format(_T("게임 포인트:  %d"), gamePoint);

dc.TextOutW(400, 0, strgamePoint);


strmovePoint.Format(_T("bmoveLeft = %d, bmoveRigh = %d, bmoveDown = %d"), bMoveLeft, bMoveRight, bMoveDown);

dc.TextOutW(600, 0, strmovePoint);



NewBlock(); // 새로운 블록 생성




}




void CSDrawingView::OnContextMenu(CWnd* /* pWnd */, CPoint point)

{

#ifndef SHARED_HANDLERS

theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);

#endif

}


// CSDrawingView diagnostics


#ifdef _DEBUG

void CSDrawingView::AssertValid() const

{

CView::AssertValid();

}


void CSDrawingView::Dump(CDumpContext& dc) const

{

CView::Dump(dc);

}


CSDrawingDoc* CSDrawingView::GetDocument() const // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSDrawingDoc)));

return (CSDrawingDoc*)m_pDocument;

}

#endif //_DEBUG



// CSDrawingView message handlers








void CSDrawingView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{

// TODO: Add your message handwler code here and/or call default

int tempi, tempj, tempk;


switch (nChar)


{


case VK_LEFT:   //방향키 왼쪽이 눌러지면..


tempi = mbblockX;

tempj = mbblockY;

SerchAround();

if ((bMoveLeft == 0 || bMoveRight ==0) && bMoveDown==0)

{

xy[tempi][tempj] = 2;


x = 160, y = 100;

mbblockX = 3, mbblockY = 0;

LineCheck();

NewBlock();

}

else if (bMoveLeft == 1)

{

mbblockX -= 1;

mvblock[mbblockX][mbblockY] = 1;

xy[tempi][tempj] = 0;

xy[mbblockX][mbblockY] = mvblock[mbblockX][mbblockY];

x -= gap;

w -= gap;

}



Invalidate();

break;


case VK_RIGHT:  // 방향키 오른쪽이 눌러지면


tempi = mbblockX;

tempj = mbblockY;

SerchAround();


if ((bMoveLeft == 0 || bMoveRight == 0) && bMoveDown == 0)

{

xy[tempi][tempj] = 2;


x = 160, y = 100;

mbblockX = 3, mbblockY = 0;

LineCheck();

NewBlock();

}

else if (bMoveRight == 1)

{

mbblockX += 1;

mvblock[mbblockX][mbblockY] = 1;

xy[tempi][tempj] = 0;

xy[mbblockX][mbblockY] = mvblock[mbblockX][mbblockY];

x += gap;

w += gap;

}



Invalidate();


break;


case VK_DOWN: //방향키 아래 누르면

tempi = mbblockX;

tempj = mbblockY;


gameOver(); // 게임오버 검사 


SerchAround();

if (bMoveDown == 0)

{

xy[tempi][tempj] = 2;


x = 160, y = 100;

mbblockX = 3, mbblockY = 0;

LineCheck();

NewBlock();

}

else if (bMoveDown == 1)

{

mbblockY += 1;

mvblock[mbblockX][mbblockY] = 1;

xy[tempi][tempj] = 0;

xy[mbblockX][mbblockY] = mvblock[mbblockX][mbblockY];

y += gap;

h += gap;

}

  



Invalidate();


break;



}



CView::OnKeyDown(nChar, nRepCnt, nFlags);

}



void CSDrawingView::OnTimer(UINT_PTR nIDEvent)

{

// TODO: Add your message handler code here and/or call default


// 타이머는 VK_DOWM  복사 


int tempi, tempj, tempk;


tempi = mbblockX;

tempj = mbblockY;



SerchAround();

if (bMoveDown == 0)

{

xy[tempi][tempj] = 2;


x = 160, y = 100;

mbblockX = 3, mbblockY = 0;

LineCheck();

NewBlock();

}

else if (bMoveDown == 1)

{

mbblockY += 1;

mvblock[mbblockX][mbblockY] = 1;

xy[tempi][tempj] = 0;

xy[mbblockX][mbblockY] = mvblock[mbblockX][mbblockY];

y += gap;

h += gap;

}



Invalidate();


CView::OnTimer(nIDEvent);

}



void CSDrawingView::NewBlock() // 새로운 블록 생성

{


CClientDC dc(this);


CPen blackpen(PS_SOLID, 1, RGB(0, 0, 0));  // 블록 그림 

dc.SelectObject(&blackpen);


dc.Rectangle(x, y, x + gap, y + gap);

mvblock[mbblockX][mbblockY] = 1;  // 최초 위치 [3][0]

htimer = SetTimer(1, 500, NULL);//0.5초마다 블록이 떨어진다. 

}



void CSDrawingView::Game(int xPos, int yPos, int wPos, int hPos) //게임판에 쌓인 벽돌 그리기 갱신

{

int i, j;

CClientDC dc(this);

CPen bluepen(PS_SOLID, 1, RGB(0, 0, 255)); // 벽 그리기 

dc.SelectObject(&bluepen);


for (i = 0; i < 9; i++)

{

for (j = 0; j < 6; j++)

{

if (xy[j][i] == 2)

{

dc.Rectangle(xPos, yPos, wPos, hPos);


}

}

}


}



void CSDrawingView::SerchAround()//주변을 탐색한다. 벽인지 쌓인 벽돌인지 탐색.

{

int tempLeft, tempRight, tempDown; //임시 저장 장소 

int serchLeft, serchRight, serchDown; // 주변 검색 값 저장 



tempLeft = mbblockX - 1; //왼쪽검색

tempRight = mbblockX + 1; //오른쪽검색

tempDown = mbblockY + 1; //아래 검색


serchLeft = xy[tempLeft][mbblockY]; //왼쪽 검색값

serchRight = xy[tempRight][mbblockY]; //오른쪽 검색값

serchDown = xy[mbblockX][tempDown];  //아래 검색값


if (serchLeft == 3 || (serchDown == 3|| serchDown == 2)) //왼쪽 검색값이 3이면 못가 3은 벽

{

bMoveLeft = 0;

}

else if (serchLeft == 2 || (serchDown == 3 || serchDown == 2)) //왼쪽검색값이 2여도 못가  2는 쌓인벽돌

{

bMoveLeft = 0;

}

else if (serchLeft == 0) // 왼쪽 검색값이 0이면 갈수 있다.

{

bMoveLeft = 1;

}


// 오른쪽 검색값 움직임 여부

if (serchRight == 3 || (serchDown == 3 || serchDown == 2))

{

bMoveRight = 0;


}

else if (serchRight == 2 || (serchDown == 3 || serchDown == 2))

{

bMoveRight = 0;

}

else if (serchRight == 0)

{

bMoveRight = 1;

}


// 아래쪽 검색값 움직임 여부


if (serchDown == 3)

{

bMoveDown = 0;

}

else if (serchDown == 2)

{

bMoveDown = 0;

}

else if (serchDown == 0)

{

bMoveDown = 1;

}


}



void CSDrawingView::LineCheck() // 블록이 5개가 차면 없어지고 위에칸이 아래칸으로 값을 복사한다. 

{

// 라인체크 구성하기

int count[9],i,j;


for (j = 8; j > 0; j--)

{

count[j] = 0;

for (i = 1; i < 6; i++)

{

if (xy[i][j] == 2)

{

count[j]++;

if (count[j] == 5)

{

gamePoint++; // 게임 포인트 올리기 


for (j = 8; j > 0; j--)

{

for (i = 1; i < 6; i++)

{

copyblock[i][j] = xy[i][j - 1];

xy[i][j] = copyblock[i][j];

}

}


}

}


}




}

}



void CSDrawingView::gameOver()

{

if (xy[3][0]) //시작점에서 움직일수 없다면 게임 오버처리

{

if (bMoveDown == 0 && bMoveLeft == 0 && bMoveRight == 0)

{

AfxMessageBox(_T("게임 오버"), (MB_YESNO | MB_ICONEXCLAMATION));

KillTimer(htimer);


}

}

}

// 즉흥적으로 만들어본 한칸짜리 테트리스