성엽이
KKIMSSI
성엽이
전체 방문자
오늘
어제
  • 분류 전체보기 (454)
    • :) (2)
    • C프로그래밍이론 (9)
    • C++프로그래밍 (64)
      • STL (1)
    • C# (2)
    • Visual studio 10.0 (9)
    • AT91SAM7S256 (21)
    • 논리회로 (14)
    • AVR2560 (11)
    • TCPIP (16)
    • NetWork (4)
      • Ubuntu Linux (2)
    • Assembly (21)
    • UNIX 프로그래밍 (6)
    • RFID 분석 (1)
    • Win32 API (7)
    • Cortex-M3 (4)
    • Unity (91)
    • Flutter (9)
    • OwnProject (11)
      • It's mine (5)
      • 마인드스톰 실습 (1)
      • 보고서 자료 (2)
      • RPi B+ (2)
    • ETC (25)
      • 상식 (3)
    • MFC (40)
    • PostgeSQL (18)
    • 영상제어 (6)
      • VFW_영상처리 (1)
    • Python (0)
    • Java (30)
      • SpringBoot (2)
      • Javascript (1)
      • JSP (13)
      • Spring (8)
    • Oracle (4)
      • SQL (3)
    • HTML (6)
      • Thymeleaf (1)
      • CSS (1)
      • Bootstrap (3)
    • IDE (1)
      • VS Code (1)
    • Android (2)
    • Privacy Policy (0)
    • MYSQL (2)
      • MariaDB (2)
    • AWS (5)
    • 개인공부 (0)

블로그 메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록
  • 관리자
  • 글쓰기

공지사항

인기 글

태그

  • Boot Code 분석
  • MFC
  • ARM Reverse Engineering
  • WINAPI
  • 문자열 나누기

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
성엽이

KKIMSSI

2013.10.23 _ Sokoban 연습
Win32 API

2013.10.23 _ Sokoban 연습

2013. 10. 23. 09:35


 Sokoban.c

#include <Windows.h>

#include "resource.h"

#define X_SIZE    48    /* 출력할 그림의 X 사이즈 */ 
#define Y_SIZE    48    /* 출력할 그림의 Y 사이즈 */ 
#define X_BLOCK    18    /* 행 의 갯수 */
#define Y_BLOCK    13    /* 열 의 갯수 */
#define X_LINE    6    /* 출력할 그림의 X 좌표 보정하기위한 크기 */
#define Y_MENU    32    /* 출력할 그림의 Y 좌표 보정하기위한 크기 */
#define TILE    '#'    /* 벽 */
#define TUTA    '@'    /* 캐릭 */
#define ROAD    ' '    /* 길 */
#define BOX      'B'    /* 박스 */
#define MAXSTAGE  2    /* 총 스테이지 */
#define GOAL    'X'    /* 박스 도착 지점 */

typedef struct _MsgMap              /* 함수 구성 */
{
  UINT iMessage;                /* UINT 선언 : 어떤종류의 메시지인지 확인 가능 */
  LRESULT  (*fp)(HWND , WPARAM , LPARAM );    /* 함수 포인터 선언 : 메시지와 같은 기능의 함수 포인터 */
}MsgMap;

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;                /* 인스턴스 핸들 : 프로그램 자체를 말하는 고유값(프로그램 각각을 모두) */

LPCTSTR lpszClass = TEXT("KKIMSSI's Sokoban2");  // 창 제목 

int iMap_X;            /* 그림위치 X */
int iMap_Y;            /* 그림위치 Y */
unsigned int uiKeyCount;    /* 움직인 횟수 */
unsigned int uiStage;      /* 스테이지 */
unsigned int uiMatch;      /* 다음 스테이지로 넘어가기위한 변수 설정 */
unsigned int uiM_Cnt;      /* 다음 스테이지로 넘어가기위한 변수 설정 : 박스와 골의 갯수가 같으면 클리어하게 변수 설정 */

static HBITMAP SELBitmap;    /* Bitmap 파일의 속성을 선택하기위한 변수 */
static HBITMAP MapDown;      /* MapDown ~ Goal 까지는 Bitmap 파일 */
static HBITMAP MapUp;
static HBITMAP MapLeft;
static HBITMAP MapRight;
static HBITMAP Tile;
static HBITMAP Road;
static HBITMAP Box;
static HBITMAP Goal;

void Init_Game(void);

/* WM_~ : Window Message , 메세지 발생 시 호출되는 함수선언 */
LRESULT  My_Create(HWND , WPARAM , LPARAM );
LRESULT  My_KeyDown(HWND , WPARAM , LPARAM );
LRESULT  My_Paint(HWND , WPARAM , LPARAM );
LRESULT  My_Destroy(HWND , WPARAM , LPARAM );

/* 함수 포인터를 이용해서 윈도우 메세지와 대응되는 함수는 호출 */
MsgMap MESSAGEMAP[] = {
          {WM_CREATE, My_Create},
          {WM_KEYDOWN, My_KeyDown},
          {WM_PAINT, My_Paint},
          {WM_DESTROY, My_Destroy},
};

/* 바뀌는 위치정보를 저장하는 맵 */
unsigned char ucMap[Y_BLOCK][X_BLOCK+1];

/* 스테이지 전체를 항상 저장 */
unsigned char ucStageMap[MAXSTAGE][Y_BLOCK][X_BLOCK+1] = { 
  {
    "##################",
    "##################",
    "##################",
    "#####   ##########",
    "#####B  ##########",
    "#####  B##########",
    "###  B B #########",
    "### # ## #########",
    "#   # ## ####  XX#",
    "# B  B   @     XX#",
    "##### ### # #  XX#",
    "#####     ########",
    "##################",
  },
  {
    "##################",
    "##################",
    "##################",
    "##################",
    "##################",
    "##################",
    "##  ##############",
    "#  B#########   @#",
    "#   # ## ####    #",
    "#       B       X#",
    "##### ### # #   X#",
    "#####     ########",
    "##################",
  }
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)  // WinMain , API Main 함수
{                                                    // nCmdShow 인자의 갯수가 온다
  HWND hWnd;    // Window Handler                                  // LPSTR 는 char * 배열 C의 main 의 2번째 인자
  MSG Message;    
  WNDCLASS WndClass;  /* 1. 윈도우 구조체 생성 ( Class ) */
  g_hInst = hInstance;  

  /* 2.1 구조체에 값을 넣어 스타일을 변화시켜준다 */
  WndClass.cbClsExtra     = 0;
  WndClass.cbWndExtra     = 0;
  WndClass.hbrBackground   = (HBRUSH)GetStockObject(WHITE_BRUSH);    // 바탕색
  WndClass.hCursor     = LoadCursor(NULL, IDC_ARROW);        // 마우스 모양
  WndClass.hIcon       = LoadIcon(NULL, IDI_APPLICATION);
  WndClass.hInstance     = hInstance;
  WndClass.lpfnWndProc   = WndProc;
  WndClass.lpszClassName   = lpszClass;
  WndClass.lpszMenuName   = NULL;
  WndClass.style       = CS_HREDRAW|CS_VREDRAW;
  /* 2.2 앞에 모든 Class 값을 등록시켜주는 함수 */
  RegisterClass(&WndClass);  

  /* 3. 창 만들기, 인자 dwStyle과 좌표값 초기화 */
  hWnd=CreateWindow(lpszClass,lpszClass,WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,
    X_SIZE*X_BLOCK+X_LINE , Y_SIZE*Y_BLOCK+Y_MENU , NULL , (HMENU)NULL , hInstance , NULL);
  /* 4. 창을 화면에 출력 하는 함수 */
  ShowWindow(hWnd,nCmdShow);

  /* 5. 창에서 일어나는 메세지 처리 (클릭, 닫기 등등..) */
  while(GetMessage(&Message,NULL,0,0))
  {
    TranslateMessage(&Message);
    DispatchMessage(&Message);
  }
  return (int)Message.wParam;
}

/* 마우스나 키보드를 움직이면 OS 에서 자동으로 호출 */
/* 메세지 처리는 여기서 처리된다 */
LRESULT  CALLBACK  WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  unsigned int uiCnt;

  /*  */
  for(uiCnt = 0;uiCnt< (sizeof(MESSAGEMAP)/sizeof(MESSAGEMAP[0])) ; ++uiCnt)
  {
    if(iMessage == MESSAGEMAP[uiCnt].iMessage)
    {

      return ( (MESSAGEMAP[uiCnt].fp)(hWnd,wParam,lParam) );
    }
  }

  return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

void Init_Game(void)
{
  unsigned int ui_XCnt;
  unsigned int ui_YCnt;

  uiKeyCount = 0;

  uiMatch = 0;
  SELBitmap = MapDown;
  
  /* 캐릭 좌표 입력 */
  for(ui_YCnt = 0 ; ui_YCnt < Y_BLOCK ; ui_YCnt++)
  {
    for(ui_XCnt = 0 ; ui_XCnt < X_BLOCK ; ui_XCnt++ )
    {
      if( TUTA == ucStageMap[uiStage][ui_YCnt][ui_XCnt] )
      {
        iMap_X = ui_XCnt;
        iMap_Y = ui_YCnt;
      }        
      
      ucMap[ui_YCnt][ui_XCnt] = ucStageMap[uiStage][ui_YCnt][ui_XCnt];
      
      if( GOAL == ucStageMap[uiStage][ui_YCnt][ui_XCnt] )
      {
        ucMap[ui_YCnt][ui_XCnt] = ROAD;
        ++uiMatch;
      }
    }
  }
  
  return;
}

LRESULT  My_Create(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  MapDown = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));  /* bitmap1 */
  MapUp = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP2));    /* bitmap2 */
  MapLeft = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP3));  /* bitmap3 */
  MapRight = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP4));  /* bitmap4 */
  Tile = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP5));    /* bitmap5 */
  Road = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP6));    /* bitmap6 */
  Box = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP7));    /* bitmap7 */
  Goal = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP8));    /* bitmap8 */

  /* 맵, 캐릭터 초기화 함수 */
  Init_Game();

  return 0;
}

LRESULT  My_KeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  RECT rc;

  /* 무효화영역 지정, 현재위치의 사각형 */
  rc.left = iMap_X*X_SIZE;
  rc.top = iMap_Y*Y_SIZE;
  rc.right = rc.left + X_SIZE;
  rc.bottom = rc.top + Y_SIZE;

  switch(wParam)
  {
    /* 왼쪽 키 입력 */
  case VK_LEFT:
    SELBitmap = MapLeft;
    if( TILE != ucMap[iMap_Y][iMap_X-1] )
    {
      /* 선택영역만 다시 그리기 */
      rc.left = rc.left - X_SIZE;

      if( BOX == ucMap[iMap_Y][iMap_X-1] )
      {
        if( ROAD == ucMap[iMap_Y][iMap_X-2] )
        {
          /* 선택영역만 다시 그리기 */
          rc.left = rc.left - X_SIZE;

          ucMap[iMap_Y][iMap_X-2] = BOX;
        }  
        else
        {
          break;
        }
      }

      ucMap[iMap_Y][iMap_X] = ROAD;
      --iMap_X;
      ucMap[iMap_Y][iMap_X] = TUTA;
      //iMan_X = iMan_X-X_SIZE;
      ++uiKeyCount;
    }

    break;
  case VK_RIGHT:
    SELBitmap = MapRight;
    if( TILE != ucMap[iMap_Y][iMap_X+1] )
    {
      rc.right = rc.right + X_SIZE;

      if( BOX == ucMap[iMap_Y][iMap_X+1] )
      {
        if( ROAD == ucMap[iMap_Y][iMap_X+2] )
        {
          rc.right = rc.right + X_SIZE;

          ucMap[iMap_Y][iMap_X+2] = BOX;
        }  
        else
        {
          break;
        }
      }

      ucMap[iMap_Y][iMap_X] = ROAD;
      ++iMap_X;
      ucMap[iMap_Y][iMap_X] = TUTA;
      //iMan_X = iMan_X-X_SIZE;
      ++uiKeyCount;
    }

    break;
  case VK_UP:
    SELBitmap = MapUp;
    if( TILE != ucMap[iMap_Y-1][iMap_X] )
    {
      rc.top = rc.top - Y_SIZE;

      if( BOX == ucMap[iMap_Y-1][iMap_X] )
      {
        if( ROAD == ucMap[iMap_Y-2][iMap_X] )
        {
          rc.top = rc.top - Y_SIZE;

          ucMap[iMap_Y-2][iMap_X] = BOX;
        }  
        else
        {
          break;
        }
      }

      ucMap[iMap_Y][iMap_X] = ROAD;
      --iMap_Y;
      ucMap[iMap_Y][iMap_X] = TUTA;
      //iMan_X = iMan_X-X_SIZE;
      ++uiKeyCount;
    }

    break;
  case VK_DOWN:
    SELBitmap = MapDown;
    if( TILE != ucMap[iMap_Y+1][iMap_X] )
    {
      rc.bottom = rc.bottom + Y_SIZE;
      if( BOX == ucMap[iMap_Y+1][iMap_X] )
      {
        if( ROAD == ucMap[iMap_Y+2][iMap_X] )
        {
          rc.bottom = rc.bottom + Y_SIZE;
          ucMap[iMap_Y+2][iMap_X] = BOX;
        }  
        else
        {
          break;
        }
      }

      ucMap[iMap_Y][iMap_X] = ROAD;
      ++iMap_Y;
      ucMap[iMap_Y][iMap_X] = TUTA;
      //iMan_X = iMan_X-X_SIZE;
      ++uiKeyCount;
    }
    break;
   /* 페이지 업 */
  case VK_PRIOR:

    rc.left = 0;
    rc.top = 0;
    rc.right = X_SIZE*X_BLOCK;
    rc.bottom = Y_SIZE*Y_SIZE;

    if( uiStage > 0 )
    {
      --uiStage;
    }
    Init_Game();
    break;
 /* 페이지 다운 */
  case VK_NEXT:

    rc.left = 0;
    rc.top = 0;
    rc.right = X_SIZE*X_BLOCK;
    rc.bottom = Y_SIZE*Y_SIZE;

    if( MAXSTAGE - 1 > uiStage )
    {
      ++uiStage;
    }
    Init_Game();
    break;
  }
  InvalidateRect(hWnd,&rc,TRUE);
  return 0;
}

LRESULT  My_Paint(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  HDC MemDC;
  PAINTSTRUCT ps;
  wchar_t wcGameCnt[100];  /* 타이틀에 시간 표시 */
  unsigned int ui_XCnt;
  unsigned int ui_YCnt;
  
  hdc = BeginPaint(hWnd,&ps);

  /* 인수로 받는 핸들러와 같은 특성의 DC를 메모리에 만들어 핸들을 리턴 */
  MemDC = CreateCompatibleDC(hdc);

  uiM_Cnt = 0;

  for(ui_YCnt = 0 ; ui_YCnt < Y_BLOCK ; ui_YCnt++)
  {
    for(ui_XCnt = 0 ; ui_XCnt < X_BLOCK ; ui_XCnt++ )
    {
      if( TILE == ucMap[ui_YCnt][ui_XCnt] )
      {
        /* MemDC 에 WM_CREATE 에서 저장한 Tile 그림을 저장 */

        SelectObject(MemDC,Tile);
      }
      else if( TUTA == ucMap[ui_YCnt][ui_XCnt] )
      {

            /* MemDC 에 WM_CREATE 에서 저장한 SELBitmap(움직이기 전 상태) 그림을 저장 */ 

        SelectObject(MemDC,SELBitmap);
      }
      else if( BOX == ucMap[ui_YCnt][ui_XCnt] )
      {
        SelectObject(MemDC,Box);

        /* BOX와 GOAL의 위치가 같으면 */
        if( GOAL == ucStageMap[uiStage][ui_YCnt][ui_XCnt] )
        {
          ++uiM_Cnt;
        }

        /* 다음 스테이지로 이동 */
        if( uiM_Cnt == uiMatch )
        {
          if( MAXSTAGE - 1 > uiStage )
          {
            ++uiStage;
          }

          /* 스테이지 넘어가기전 메세지 출력 */
          MessageBox(hWnd,TEXT("다음 스테이지로 넘어갑니다!"), TEXT("메세지"), MB_OK);
          Init_Game();
          InvalidateRect(hWnd,NULL,TRUE);
          break;
        }
      }
      else if( GOAL == ucStageMap[uiStage][ui_YCnt][ui_XCnt] )
      {
        SelectObject(MemDC,Goal);
      }
      else
      {
        SelectObject(MemDC,Road);
      }

      /* 메모리에 저장되어있는 그림을 크기를 변경하지않고 비트맵DC -> 화면DC 로 복사해서 출력 */
      BitBlt(hdc, ui_XCnt*48 , ui_YCnt*48 , 48, 48 , MemDC , 0 , 0 , SRCCOPY);

    }
  }

  //    SelectObject(MemDC,SELBitmap);
  //    BitBlt(hdc, iMan_X , iMan_Y , 48, 48 , MemDC , 0 , 0 , SRCCOPY);

  DeleteDC(MemDC);
  EndPaint(hWnd,&ps);
  wsprintf(wcGameCnt,TEXT("Tristana Couter : [%d]"), uiKeyCount);
  //wsprintf(wcGameCnt,TEXT("Tristana Couter : [%d]"), uiM_Cnt);
  SetWindowText(hWnd,wcGameCnt);
  return 0;
  return 0;
}

LRESULT  My_Destroy(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  DeleteObject(MapUp);
  DeleteObject(MapDown);
  DeleteObject(MapLeft);
  DeleteObject(MapRight);
  DeleteObject(Tile);
  PostQuitMessage(0);

  return 0;
}


------- 소스 -------------------------------------------------------------------------------------










resource.h


Sokoban2.c


131017_Sokoban2.rc


131017_Sokoban2.exe


131017_Sokoban2.zip


--------------------------------------------------------------------------------------------------

저작자표시

'Win32 API' 카테고리의 다른 글

2013.10.30 _ 충돌체크하기 _ Galag 에서 _  (0) 2013.10.30
2013.10.23_ API _ Bitmap 분석해보기  (0) 2013.10.23
2013.10.14_API_Control(체크박스/라디오박스)  (0) 2013.10.14
2013.10.04 _ API 정리 자료 ( 입력/출력 부분 )  (0) 2013.10.08
2013.10.07 _ API 정리 자료 ( SendMessage , CallBack 함수 )  (0) 2013.10.08
    'Win32 API' 카테고리의 다른 글
    • 2013.10.30 _ 충돌체크하기 _ Galag 에서 _
    • 2013.10.23_ API _ Bitmap 분석해보기
    • 2013.10.14_API_Control(체크박스/라디오박스)
    • 2013.10.04 _ API 정리 자료 ( 입력/출력 부분 )
    성엽이
    성엽이

    티스토리툴바