본문 바로가기
코스웨어/15년 스마트컨트롤러

20151119 - 권오민 - WinAPI 6일차

by 알 수 없는 사용자 2015. 11. 19.
728x90
반응형

API

◉Game

●mapping 기법

- 길을 보여줄 비트맵을 추가로 등록한다.

        - static HBITMAP HbmLoad;

- On_Paint에서 2중 for문을 사용하여 전체적인 맵을 출력한다.

        - 내부에 if문을 사용하여 미리 만들어둔 Map에서 길과 배경을 분리하여 출력한다.

- 소스<Game.c => On_Paint>

LRESULT On_Paint(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  
int iXCnt;
  
int iYCnt;
  
  hdc 
= BeginPaint(hWnd, &ps);
  
for (iYCnt = 0; iYCnt < YFRAME; ++iYCnt)
  {
    
for (iXCnt = 0; iXCnt < XFRAME; ++iXCnt)
    {
      
if ('#' == ucMap[iYCnt][iXCnt])
      {
        SelectObject(MemDC, 
HbmGround);
      }
      
else if (' ' == ucMap[iYCnt][iXCnt])
      {
        SelectObject(MemDC, 
HbmLoad);
      }
      BitBlt(hdc, iXCnt*XTILE, iYCnt*YTILE, XTILE, YTILE, MemDC, 
00, SRCCOPY);
    }
  }
  SelectObject(MemDC, HbmHero);
  BitBlt(hdc, iXPos, iYPos, XTILE, YTILE, MemDC, 
00, SRCCOPY);
  EndPaint(hWnd, 
&ps);

  
return 0;
}

- 결과

●LoadMap() 함수

- 캐릭터의 이동에 따라 변하는 맵을 처리하기 위해서 판(Stage) 개념을 추가한다.

        - #define STAGE      2

- 이중 for문을 사용하여 ucMap을 만든다.

        - memcpy로도 사용이 가능하다.

                - @도 같이 복사한다.

                        - @의 위치를 알 수 없다.

                - 이중 for문을 사용하면 @의 위치를 알 수 있다.

        - ucMap을 만드는 도중에 캐릭터를 뜻하는 ‘@’를 만나면 그 좌표를 저장해둔다.

- 소스

void LoadMap(void)
{
  
int iXCnt;
  
int iYCnt;

  
for (iYCnt = 0; iYCnt < YFRAME; ++iYCnt)
  {
    
for (iXCnt = 0; iXCnt < XFRAME; ++iXCnt)
    {
      
ucMap[iYCnt][iXCnt] = ucStageMap[uiStage][iYCnt][iXCnt];
      
if ('@' == ucMap[iYCnt][iXCnt])
      {
        iXPos 
= iXCnt;
        iYPos 
= iYCnt;
      }
    }
  }

  
return;
}

●캐릭터 이동

- 캐릭터가 제자리에서는 움직이지만, 이동은 하지 않는다.

- 캐릭터를 이동할 수 있도록 다음과 같이 수정한다.

case VK_RIGHT:
 
     ++iXPos;
      ucMap[iYPos][iXPos] 
= '@';
      HbmHero 
= HbmRight;
      
break;

        - 결과 : 캐릭터가 움직인다.

        - 문제점 : 캐릭터는 움직이지만, 지나간 자리에 캐릭터가 잔상으로 남는다.

- 지나간 자리에 캐릭터를 지워야 한다.

        - 화면에 ‘@’는 이동하지만, ucMap에 ‘@’는 그대로 있다.

                - 화면에 보이는 캐릭터가 아니라 ucMap에 존재하는 캐릭터가 움직여야한다.

     case VK_RIGHT:
      
ucMap[iYPos][iXPos] = ' ';
      
++iXPos;
      ucMap[iYPos][iXPos] = '@';

      HbmHero 
= HbmRight;
      
break;

        - 결과 : 캐릭터가 이동한 지점만 캐릭터가 존재한다.

                - 캐릭터가 지나간 길을 전부 Load로 채운다.

        - 문제점 : 맵이 지워진다.

                - 캐릭터가 지나간 길을 전부 Load로 채운다.

- 캐릭터가 지나간 자리를 원본의 Stage에서 들고 온다.

        - 다음과 같이 수정한다.

     case VK_RIGHT:
     
 ucMap[iYPos][iXPos] = ucStageMap[uiStage][iYPos][iXPos];
      ++iXPos;
      ucMap[iYPos][iXPos] 
= '@';
      HbmHero 
= HbmRight;
      
break;

        - 결과 : 캐릭터가 지나가도 맵은 그대로 존재한다.

        - 문제점 : 처음에 캐릭터가 나타난 자리는 캐릭터로 고정된다.

- 우선 ucMap에 캐릭터를 지우고, 좌표만 저장해서 따로 그린다.

        - '@'가 사라진다.

        - 캐릭터가 이동하여도 좌표 값으로 그리기 때문에 문제가 없다.

/*On_Paint 함수 마지막에 추가한다.*/
  SelectObject(MemDC, HbmHero);
  BitBlt(hdc, 
iXPos*XTILE, iYPos*YTILE, XTILE, YTILE, MemDC, 00, SRCCOPY);

/*LoadMap 함수*/
void LoadMap(void)
{
  
int iXCnt;
  
int iYCnt;
  
  
for (iYCnt = 0; iYCnt < YFRAME; ++iYCnt)
  {
    
for (iXCnt = 0; iXCnt < XFRAME; ++iXCnt)
    {
      
if ('@' == ucStageMap[uiStage][iYCnt][iXCnt])
      {
        iXPos 
= iXCnt;
        iYPos 
= iYCnt;
        
ucMap[iYCnt][iXCnt] = ' ';
        
continue;
      }
      ucMap[iYCnt][iXCnt] 
= ucStageMap[uiStage][iYCnt][iXCnt];
    }
  }

  
return;
}

- 결과

●경계 검사

- 갈 수 있는 조건은 다음과 같다.

        - O : 길, 닷, 박스(+길, 닷)

                - if문이 6가지이다.

        - X : 벽, 박스(+벽, 박스)

                - if문이 5가지이다.

- 소스

case VK_RIGHT:
      HbmHero 
= HbmRight;
      
if (' ' == ucMap[iYPos][iXPos + 1])        //길 일 때
      {
        ++iXPos;
      }
      
else if ('.' == ucMap[iYPos][iXPos + 1])   //Dot일 때
      {
        ++iXPos;
      }
      
else if ('B' == ucMap[iYPos][iXPos + 1])   //박스 일 때,
      {
        
if (' ' == ucMap[iYPos][iXPos + 2])      //박스이고, 길 일 때
        {
          ++iXPos;
        }
        
else if ('.' == ucMap[iYPos][iXPos + 2]//박스이고, Dot 일 때
        {
          ++iXPos;
        }
      }
      
break;

- 결과는 생략한다.


●박스 이동

- 박스를 이동한 후에 박스가 지나간 자리는 이전 상황에 맞게 다시 채워 주어야 한다.

        - 원본에 ucStageMap에서 정보를 들고 온다.

                - 원래 Dot였다면 Dot, 길이나 박스였다면 길을 채워주면 된다.

    case VK_RIGHT:
      HbmHero 
= HbmRight;
      
if (' ' == ucMap[iYPos][iXPos + 1])
      {
        ++iXPos;
      }
      
else if ('.' == ucMap[iYPos][iXPos + 1])
      {
        ++iXPos;
      }
      
else if ('B' == ucMap[iYPos][iXPos + 1])
      {
        
if (' ' == ucMap[iYPos][iXPos + 2])
        {
          ucMap[iYPos][iXPos+
2= ucMap[iYPos][iXPos+1];
          
if ('.' != ucStageMap[uiStage][iYPos][iXPos+1])
          {
            ucMap[iYPos][iXPos + 
1= ' ';
          }
          
else
          {
            ucMap[iYPos][iXPos + 
1= '.';
          }

          ++iXPos;
        }
        
else if ('.' == ucMap[iYPos][iXPos + 2])
        {
          ucMap[iYPos][iXPos + 
2= ucMap[iYPos][iXPos + 1];
          
if ('.' != ucStageMap[uiStage][iYPos][iXPos + 1])
          {
            ucMap[iYPos][iXPos + 
1= ' ';
          }
          
else
          {
            ucMap[iYPos][iXPos + 
1= '.';
          }
          ++iXPos;
        }
      }
      
break;

- 결과

- 최적화는 알아서 하도록 하자.

●클리어 조건

- ucMap에 dot위에 올라간 박스 개수와 ucStageMap에 dot의 개수가 같으면 클리어 된다.

        - ucStageMap에 dot 개수는 LoadMap에서 확인할 수 있다.

        - ucMap에 dot위에 올라간 박스 개수는 키보드 입력이 끝날 때마다 if문을 통해 체크한다.

- 소스

/*On_KeyDown 함수*/
  InvalidateRect(hWnd, &stArea, FALSE);

 
 uiDotCnt = 0;
  for (iYCnt = 0; iYCnt < YFRAME; ++iYCnt)
  {
    for (iXCnt = 0; iXCnt < XFRAME; ++iXCnt)
    {
      if ('B' == ucMap[iYCnt][iXCnt])
      {
        if ('.' == ucStageMap[uiStage][iYCnt][iXCnt])
        {
          ++uiDotCnt;
        }
      }
    }
  }


/*LoadMap 함수*/
void LoadMap(void)
{
  
int iXCnt;
  
int iYCnt;
  
  uiDotNum 
= 0;

  
for (iYCnt = 0; iYCnt < YFRAME; ++iYCnt)
  {
    
for (iXCnt = 0; iXCnt < XFRAME; ++iXCnt)
    {
     
 if ('.' == ucStageMap[uiStage][iYCnt][iXCnt])
      {
        ++uiDotNum;
      }

      
if ('@' == ucStageMap[uiStage][iYCnt][iXCnt])
      {
        iXPos 
= iXCnt;
        iYPos 
= iYCnt;
        ucMap[iYCnt][iXCnt] 
= ' ';
        
continue;
      }
      ucMap[iYCnt][iXCnt] 
= ucStageMap[uiStage][iYCnt][iXCnt];
    }
  }

  
return;
}

- 결과



InvalidateRect() 함수

- 2번째 인자가 NULL로 되어 있어 On_Paint를 할 때마다 전부 다 그린다.

        - 그릴 부분을 RECT함수를 통해 제한한다.

                - InvalidateRect(hWnd, &stArea, FALSE);

- 소스

/*On_KeyDown*/
  RECT  stArea;

  stArea.left    = iXPos * XTILE;
  stArea.right  = (iXPos + 1) * XTILE - 1;
  stArea.top    = iYPos * YTILE;
  stArea.bottom  = (iYPos + 1) * YTILE - 1;


case VK_RIGHT:
      HbmHero 
= HbmRight;
      
if (' ' == ucMap[iYPos][iXPos + 1])
      {
        ++iXPos;
        stArea.right 
= (iXPos + 1) * XTILE - 1;
      }
      
else if ('.' == ucMap[iYPos][iXPos + 1])
      {
        ++iXPos;
        stArea.right 
= (iXPos + 1) * XTILE - 1;
      }
      
else if ('B' == ucMap[iYPos][iXPos + 1])
      {
        
if (' ' == ucMap[iYPos][iXPos + 2])
        {
          ucMap[iYPos][iXPos+
2= ucMap[iYPos][iXPos+1];
          
if ('.' != ucStageMap[uiStage][iYPos][iXPos+1])
          {
            ucMap[iYPos][iXPos + 
1= ' ';
          }
          
else
          {
            ucMap[iYPos][iXPos + 
1= '.';
          }
          ++iXPos;
          stArea.right 
= (iXPos + 2) * XTILE - 1;
        }
        
else if ('.' == ucMap[iYPos][iXPos + 2])
        {
          ucMap[iYPos][iXPos + 
2= ucMap[iYPos][iXPos + 1];
          
if ('.' != ucStageMap[uiStage][iYPos][iXPos + 1])
          {
            ucMap[iYPos][iXPos + 
1= ' ';
          }
          
else
          {
            ucMap[iYPos][iXPos + 
1= '.';
          }
          ++iXPos;
          stArea.right 
= (iXPos + 2) * XTILE - 1;
        }
      }
      
break;

 
 InvalidateRect(hWnd, &stArea, FALSE);

●Stage 및 Score.

- Push Push 게임의 특성을 활용하여, 움직인 거리가 작을수록, 즉 점수가 낮을수록 잘 한 것이다.

        - 캐릭터가 이동한 거리를 카운팅하여 그것을 점수화 한다.

        - 키보드 입력을 받을 때마다 ++하면 된다.

                - ↑↓←→를 제외한 키의 입력은 배제하기 위해서 모든 case문 안에 입력한다.

        - 출력은 SetWindowText 함수를 사용한다.

                - 원형

                        - BOOL SetWindowText(HWND, hWnd, LPCSTR lpString);

                - hWnd의 이름을 lpString로 바꿔주는 함수이다.


- 소스

/*On_Paint 함수 마지막 부분*/
  wsprintf(cTitle, TEXT("Stage : %d Key Count : %d"), uiStage + 1, uiScore*100);
  SetWindowText(hWnd, cTitle);


/*On_KeyDown 함수*/
    case VK_RIGHT:
      ++uiScore;

- 결과

●Reset.

- 게임이 잘못 되었거나, 다시 하고 싶은 상황을 위해서 만들었다.

        - Score 또한 초기화가 되어야 한다.

        - Home키를 눌렀을 때 Reset 되도록 한다.

- 소스

/*On_KetDown 함수*/
case VK_HOME:
      iRet 
= MessageBox(hWnd, TEXT("다시 하시겠습니까?"), TEXT("알림"), MB_OKCANCEL);
      
if (IDOK == iRet)
      {
        LoadMap();
      }
      InvalidateRect(hWnd, NULL, TRUE);
      
return 0;

- 결과

●최종 결과.

- 전체적인 틀에 의한 결과물이다.







◆제 7장. 차일드.

◉7-1. 버튼.

●7-1-가. 컨트롤의 정의.

- 컨트롤이란?

        - 사용자와의 인터페이스를 이루는 도구이다.

●7-1-나. Button.

- 결과





728x90