안녕하세요
테트리스 강의 잘봤습니다.
거의 따라서 해보고 몇개 명칭만 좀 바꿔보고 했는데요.
첫판은 잘됩니다.
한판이 무사히 끝나고 다시 시작했을때
블록을 2개째 깰때부터 실행이 이상하게 안되는데요
혹시 이유를 알수 없을까요?.
블록도 이상하게 깨지는것같긴 합니다만... 도와주세요. ㅠ
밑에는 소스입니다.
// Tetris84View.cpp : implementation of the CTetris84View class
//
#include "stdafx.h"
#include "Tetris84.h"
#include "Tetris84Doc.h"
#include "Tetris84View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
int timer=1000;
int g_BoardInfo[BOARD_Y_SIZE+1][BOARD_X_SIZE+2];//Board정보 선언
int g_NowBlockInfo[7][4][4][4]={//1번째 열은 모양 담당[7가지],2번째열은 [4가지] 회전 담당이므로 4(90도씩 회전)
{//아래로 첫번째 블록
{
{0,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,1,0,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},
{1,1,1,1},
{0,0,0,0},
{0,0,0,0}
}
},
{ //아래로 2번째 벽돌
{
{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,0},
{0,0,0,0}
}
},
{//아래로 3번째 블록
{
{1,0,0,0},
{1,1,0,0},
{1,0,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},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{0,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{//아래로 4번째 블록
{
{1,1,0,0},
{1,0,0,0},
{1,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{0,1,0,0},
{0,1,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{0,0,1,0},
{0,0,0,0},
{0,0,0,0}
}
},
{//아래로 5번째 블록
{
{1,0,0,0},
{1,0,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{//아래로 6번째 블록
{
{0,1,0,0},
{1,1,0,0},
{1,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{0,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{0,1,0,0},
{1,1,0,0},
{1,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{0,1,1,0},
{0,0,0,0},
{0,0,0,0}
}
},
{//아래로 7번째 블록
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
}
};
/////////////////////////////////////////////////////////////////////////////
// CTetris84View
IMPLEMENT_DYNCREATE(CTetris84View, CFormView)
BEGIN_MESSAGE_MAP(CTetris84View, CFormView)
//{{AFX_MSG_MAP(CTetris84View)
// ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_WM_PAINT()//PAINT함수 가동
ON_WM_TIMER()//TIMER함수 가동
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTetris84View construction/destruction
CTetris84View::CTetris84View()//기존 x좌표 값, y좌표,Block 값 초기화
: CFormView(CTetris84View::IDD)
{
//{{AFX_DATA_INIT(CTetris84View)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// TODO: add construction code here
m_iNowBlockTurn = 0;//블록회전 하는 모양을 나타내는 변수를 초기화
m_iNowBlockShape = 0; //블록모양을 나타내는 변수를 초기화
m_iNowBlockX=5;
m_iNowBlockY=4; //Block의 기존 위치 X,Y좌표 값들
m_iOneBlockSize=30;//Block의 크기
int i;
for(i=0;i<BOARD_Y_SIZE;i++)
{
g_BoardInfo[i][0]=50;
}//보드의 좌측벽
for(i=0;i<BOARD_Y_SIZE;i++)
{
g_BoardInfo[i][BOARD_X_SIZE+1]=50;
}//보드의 우측벽
for(i=0;i<BOARD_X_SIZE;i++)
{
g_BoardInfo[BOARD_Y_SIZE][i]=50;
}//보드의 3하단벽
}
CTetris84View::~CTetris84View()
{
}
void CTetris84View::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTetris84View)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BOOL CTetris84View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CFormView::PreCreateWindow(cs);
}
void CTetris84View::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
GameStart();//게임 시작
}
/////////////////////////////////////////////////////////////////////////////
// CTetris84View printing
BOOL CTetris84View::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CTetris84View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CTetris84View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
void CTetris84View::OnPrint(CDC* pDC, CPrintInfo* /*pInfo*/)
{
// TODO: add customized printing code here
}
/////////////////////////////////////////////////////////////////////////////
// CTetris84View diagnostics
#ifdef _DEBUG
void CTetris84View::AssertValid() const
{
CFormView::AssertValid();
}
void CTetris84View::Dump(CDumpContext& dc) const
{
CFormView::Dump(dc);
}
CTetris84Doc* CTetris84View::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTetris84Doc)));
return (CTetris84Doc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CTetris84View message handlers
/*void CTetris84View::OnButton1()
{
// TODO: Add your control notification handler code here
MessageBox("메시지 Test.","보입니까");
}
*/
void CTetris84View::DrawOneBlock(int y,int x,int iSize, CClientDC *pDC, COLORREF crRGB)//CClientDC 현재 윈도우에 대한 클라이언트 영역의 dc를 얻어오는 기능
{
pDC->FillSolidRect((x)*iSize,(y)*iSize, iSize,iSize,crRGB);//m_iOneBlockSize=>iSize,
pDC->Draw3dRect((x)*iSize,(y)*iSize, iSize,iSize,RGB(255,255,255),RGB(255,255,255));
}//차후 복잡도를 고려하여 블록 그리는 기능을 담당할 DrawOneBlock함수 생성
void CTetris84View::OnPaint()
{
CPaintDC dc(this); // device context for painting
CClientDC pDC(this); // 현재 화면의 정보를 얻음
CPen penLine; // 사용할 pen 의 셋팅
CPen *OldPen; // 기존에 사용하던 설정으로 복구할 변수
penLine.CreatePen(0,3,RGB(0,0,0));
OldPen = pDC.SelectObject((&penLine));
//pDC.FillSolidRect(m_iNowBlockX*m_iOneBlockSize,m_iNowBlockY*m_iOneBlockSize,m_iOneBlockSize,m_iOneBlockSize,RGB(150,150,150));
for(int tempY=0;tempY<4;tempY++)
{
for(int tempX=0;tempX<4;tempX++)
{
if(0!=g_NowBlockInfo[m_iNowBlockShape][m_iNowBlockTurn][tempY][tempX])
{
DrawOneBlock(BOARD_Y_POS + m_iNowBlockY+tempY, BOARD_X_POS + m_iNowBlockX+tempX,m_iOneBlockSize,&pDC,RGB(50,0,250));
//pDC.FillSolidRect((m_iNowBlockX+tempX)*m_iOneBlockSize,(m_iNowBlockY+tempY)*m_iOneBlockSize,m_iOneBlockSize,m_iOneBlockSize,RGB(250,250,250));
}//Block 부분 그릴때( 흰색음영 으로 표시 )
//BOARD_Y_POS 전체 Y좌표 위치,BOARD_X_POS 전체 X좌표 위치
else
{
//DrawOneBlock(BOARD_Y_POS + m_iNowBlockY+tempY,BOARD_X_POS + m_iNowBlockX+tempX,m_iOneBlockSize,&pDC,RGB(200,200,200));//여기 수정해야할것
//pDC.FillSolidRect((m_iNowBlockX+tempX)*m_iOneBlockSize,(m_iNowBlockY+tempY)*m_iOneBlockSize,m_iOneBlockSize,m_iOneBlockSize,RGB(200,200,200));
}//Block이 아닌 공백 부분 그릴때( 회색음영 으로 표시 )
}
}
for(tempY=0;tempY<BOARD_Y_SIZE+1;tempY++)
{
for(int tempX=0;tempX<BOARD_X_SIZE+2;tempX++)
{
if(0!=g_BoardInfo[tempY][tempX])
{
DrawOneBlock((BOARD_Y_POS+tempY),BOARD_X_POS+tempX,m_iOneBlockSize,&pDC,RGB(0,0,0));
}
}
}
//BOARD도 표시를 해줘야 하기때문에 기존의 1==을 0!=으로 수정함
//////////////////////////////////////////////////////////////////////////
// 실제 출력될 내용
//pDC.TextOut(10,10,"화면에 글씨 출력");//좌 위치, RGB=>색상정보
//pDC.Rectangle(100,100,150,150);
//pDC.FillSolidRect(200,100,50,50,RGB(255,0,0));
//pDC.FillSolidRect(280,100,50,50,RGB(0,255,0));
/////////////////////////////////////////////////////////////////////////
CString str;
CString str1;
CString str2;
str.Format("%d",score);
str1.Format("%d",level);
str2.Format("%d",dItem);
pDC.TextOut(400,20,"미리보기");
pDC.TextOut(400,150,"점수 ");
pDC.TextOut(400,200,str);
pDC.TextOut(400,300,"레벨");
pDC.TextOut(400,350,str1);
pDC.TextOut(400,400,"싹쓸이 아이템");
pDC.TextOut(400,450,str2);
DrawNextBlock(&pDC);
pDC.SelectObject(OldPen); // 기존의 상태로 복구
}
BOOL CTetris84View::PreTranslateMessage(MSG* pMsg) //키보드,메시지 처리 함수.
{
// TODO: Add your specialized code here and/or call the base class
if(WM_KEYDOWN ==pMsg->message)
{
if(VK_LEFT ==pMsg->wParam)//왼쪽키를 눌렀을시
{
MoveLeft();//함수 호출
/*
m_iNowBlockX--;//x좌표 값 1씩 감소
Invalidate();//Invalidate함수 호출->WM_PAINT메시지 발생->OnDraw()함수 호출
*/
//MessageBox("VK_LEFT");//출력
}
else if(VK_RIGHT ==pMsg->wParam)//오른쪽 키를 눌렀을 시
{
MoveRight();//함수 호출
/*
m_iNowBlockX++;//x좌표 값 1씩 증가
Invalidate();
*/
//MessageBox("VK_RIGHT");//출력
}
else if(VK_UP ==pMsg->wParam)//위쪽 키를 눌렀을 시
{
MoveUp();//함수 호출
/*
m_iNowBlockY--;
Invalidate();
*/
//MessageBox("VK_UP");//출력
}
else if(VK_DOWN == pMsg->wParam)//아래쪽 키를 눌렀을 시
{
MoveDown();
/*
m_iNowBlockY++;
Invalidate();
*/
//MessageBox("VK_DOWN");//출력
}
else if(VK_SPACE == pMsg->wParam)//Space Bar를 눌렀을 시
{
while(CanMove(m_iNowBlockTurn,m_iNowBlockY+1,m_iNowBlockX))//조건 설정
MoveDown();//MoveDown함수 호출
OneLineRemove();//OneLineRemove함수 호출(삭제 기능)
}
else if(VK_SHIFT == pMsg->wParam)
{
//조건 설정
if(dItem>0)
{
DeleteRemove();//OneLineRemove함수 호출(삭제 기능)
dItem--;
}
}
}
return CFormView::PreTranslateMessage(pMsg);
}
void CTetris84View::OnTimer(UINT nIDEvent)// protected(다른 클래스 사용 없이 자신의 클래스에서 사용하여야 하기때문에)
// 초가 흘러감에 따라 바꿔줄수 있는 설정들
{
if(CanMove(m_iNowBlockTurn,m_iNowBlockY+1,m_iNowBlockX))//Block이 밑으로 나가는것을 방지
{
m_iNowBlockY += 1;//일정시간마다 실행될 부분
}
//if(m_iNowBlockY>=20)
else
{
OneLineRemove();//OneLineRemove함수 호출
m_iNowBlockX=5;//벽돌을 가운데로
m_iNowBlockY=0;//벽돌이 바닥에 닿을때 가장위로 돌려줌
m_iNowBlockShape=m_iNextBlockShape;
//m_iNowBlockShape = (++m_iNowBlockShape)%7;//7가지 모양을 재현
m_iNextBlockShape=rand()%7;
}
Invalidate();//Invalidate함수 호출->WM_TIMER메시지 발생->OnTimer()함수 호출
CFormView::OnTimer(nIDEvent);
}
BOOL CTetris84View::MoveLeft()//public(모든 클래스에서 사용 가능)
{
if(CanMove(m_iNowBlockTurn,m_iNowBlockY,m_iNowBlockX-1))
{
m_iNowBlockX -= 1;
Invalidate();
}
return TRUE;//함수 리턴
}
BOOL CTetris84View::MoveRight()//public
{
if(CanMove(m_iNowBlockTurn,m_iNowBlockY,m_iNowBlockX+1))
{
m_iNowBlockX += 1;
Invalidate();
}
return TRUE;//함수 리턴
}
BOOL CTetris84View::MoveUp()//public (회전을 위한 함수)
{
if(CanMove((m_iNowBlockTurn+1)%4,m_iNowBlockY,m_iNowBlockX))
{
m_iNowBlockTurn=(++m_iNowBlockTurn)%4; //4가지 배열중 하나를 택한 모양으로 나타냄,여기서 ++는 수를 하나씩 증가시키는 연산자로써 누락시킬 경우 변동이 되지를 않음.
Invalidate();
}
return TRUE;//함수 리턴
}
BOOL CTetris84View::MoveDown()//public
{
m_iNowBlockY += 1;
Invalidate();
return TRUE;//함수 리턴
}
BOOL CTetris84View::CanMove(int iDir,int iCheckY,int iCheckX)//블록이 나갈수 없는 범위 조건문
{
for(int iTempBlockY=0; iTempBlockY<4;iTempBlockY++)// Block을 기억해주는 iTempBlockX,iTempBlockY 변수 생성
{
for(int iTempBlockX=0;iTempBlockX<4;iTempBlockX++)
{
if(0!=g_BoardInfo[iCheckY+iTempBlockY][iCheckX+iTempBlockX] && 0!=g_NowBlockInfo[m_iNowBlockShape][iDir][iTempBlockY][iTempBlockX])
{
return FALSE;
}
}
}
return TRUE;
}
void CTetris84View::OneLineRemove()
{
for(int iTempBlockY=0;iTempBlockY<4 && (m_iNowBlockY+iTempBlockY<BOARD_Y_SIZE+1);iTempBlockY++)// Block을 Board에 기억해주는 iTempBlockX,iTempBlockY 변수 생성
{
for(int iTempBlockX=0;iTempBlockX<4;iTempBlockX++)
{
if( 0 == g_BoardInfo[m_iNowBlockY+iTempBlockY][m_iNowBlockX+iTempBlockX])
{
if( 0!=g_NowBlockInfo[m_iNowBlockShape][m_iNowBlockTurn][iTempBlockY][iTempBlockX])
{
g_BoardInfo[m_iNowBlockY+iTempBlockY][m_iNowBlockX+iTempBlockX]=g_NowBlockInfo[m_iNowBlockShape][m_iNowBlockTurn][iTempBlockY][iTempBlockX];
}
}
}
}
//한줄 없애기
BOOL rOneLine=TRUE;
for (iTempBlockY=0;iTempBlockY<4 && (m_iNowBlockY+iTempBlockY<BOARD_Y_SIZE);iTempBlockY++)
{
rOneLine=TRUE;
{
for(int iTempBlockX=0;iTempBlockX<BOARD_X_SIZE;iTempBlockX++)
{
if(0== g_BoardInfo[m_iNowBlockY+iTempBlockY][iTempBlockX])//빈칸이 있을 경우
{
rOneLine=FALSE;//실패
iTempBlockX=BOARD_X_SIZE;
}
}
if(TRUE==rOneLine)//성공했을 경우
{
int iRemoveLine=m_iNowBlockY+iTempBlockY;//제거할 변수를 Y축으로 설정(y축을 삭제해야하기 때문에)
DrawScore();
DrawItem();
for(int i=iRemoveLine;i>0;i--)
{
for(int j=1;j<BOARD_X_SIZE;j++)
{
g_BoardInfo[i][j]=g_BoardInfo[i-1][j];//y축 제거
}
}
}
}
if(IsGameEnd())//게임이 끝났을 경우
{
KillTimer(1);//timer종료 함수:timer를 중단시킨다.
if(IDYES == MessageBox(" 한판 더?","게임이 끝났습니다. ",MB_YESNOCANCEL))
{
GameStart();//게임 재 시작
level=1;
score=0;
dItem=0;
}
}
}
}
BOOL CTetris84View::IsGameEnd()
{
//X,Y축이 Block이 한줄당 적어도 하나의 빈공간이 생겨서 Block이 쌓여서 BOARD에 꽉 찰 때
for(int tempY= 0; tempY<2;tempY++)
{
for(int tempX=3; tempX<7; tempX++)
{
if(0 !=g_BoardInfo[tempY][tempX])
{
return TRUE;
}
}
}
return FALSE;
}
void CTetris84View::GameStart()
{
SetTimer(1,1000,NULL);//1번 타이머를 1000mS(1초마다 동작),(타이머 초기화)
srand((unsigned)time(NULL));
m_iNowBlockShape = rand()%7;
m_iNextBlockShape = rand()%7;
m_iNowBlockTurn=0;
m_iNowBlockX=5;
m_iNowBlockY=0;
m_iOneBlockSize=25;
//Block의 시작위치,크기 초기화
for(int tempY=0;tempY<BOARD_Y_SIZE+1;tempY++)
{
for(int tempX=0; tempX<BOARD_X_SIZE+2;tempX++)
{
g_BoardInfo[tempY][tempX]=0;
}
}
//BOARD범위를 기억
int i;
for(i=0;i<BOARD_Y_SIZE;i++)
{
g_BoardInfo[i][0]=50;
}//보드의 좌측벽
for(i=0;i<BOARD_Y_SIZE;i++)
{
g_BoardInfo[i][BOARD_X_SIZE+1]=50;
}//보드의 우측벽
for(i=0;i<BOARD_X_SIZE+2;i++)
{
g_BoardInfo[BOARD_Y_SIZE][i]=50;
}//보드의 하단벽
}
void CTetris84View::DrawNextBlock(CClientDC *pDC)//다음에 나올 Block을 그려줌
{
for(int tempY=0;tempY<4;tempY++)
{
for(int tempX=0;tempX<4;tempX++)
{
if(0!=g_NowBlockInfo[m_iNextBlockShape][0][tempY][tempX])
{
DrawOneBlock((BOARD_Y_POS+tempY),BOARD_X_POS+BOARD_X_SIZE+3+tempX,m_iOneBlockSize,pDC,RGB(50,200,200));
}
}
}
}
int CTetris84View::score=0;
int CTetris84View::level=1;
int CTetris84View::dItem=0;
void CTetris84View::DrawScore()
{
score++;
if(score%2==0)
{
level++;
timer-=200;
SetTimer(1,timer,NULL);
}
/* if(level%5==0)
{
*/
}
//자료구조,알고리즘
void CTetris84View::DrawItem()
{
if(level%3==0)
{
dItem++;
}
}
void CTetris84View::DeleteRemove()
{
//g_BoardInfo[BOARD_Y_SIZE+1][BOARD_X_SIZE+2];
for(int tempY=0;tempY<BOARD_Y_SIZE+1;tempY++)
{
for(int tempX=0; tempX<BOARD_X_SIZE+2;tempX++)
{
g_BoardInfo[tempY][tempX]=0;
}
}
//BOARD범위를 기억
int i;
for(i=0;i<BOARD_Y_SIZE;i++)
{
g_BoardInfo[i][0]=50;
}//보드의 좌측벽
for(i=0;i<BOARD_Y_SIZE;i++)
{
g_BoardInfo[i][BOARD_X_SIZE+1]=50;
}//보드의 우측벽
for(i=0;i<BOARD_X_SIZE+2;i++)
{
g_BoardInfo[BOARD_Y_SIZE][i]=50;
}//보드의 하단벽
}
전제 파일을 올려 주세요.~~
실행하면서 디버깅해야 찾을수 있고, 소스를 눈으로면 봐서 알수가 없습니다..
여기에 소스 올리기 좀 곤란하시면, kkjk1@네 이 버 로 보내 주세요.~~