
// 2d 슈팅 게임. 16비트. 구조체 사용함. 적군 8명 등장.
// 폭발 그림 연결에 문제는 있음.

/* 읽어주세요!

2003년 5월 11일
안녕하십니까? 초보 권남수입니다. 본 소스는 신용우 교수님의 저서인 "게임 프로그래밍 길잡이" (대림출판사)의 소스 내용을 제가 편집한 것입니다. (제 홈에 안내됨)
http://my.dreamwiz.com/kns3838/html/L2_han/g_theory/2D_API/a_1.htm

원 소스에는 8비트, 적군 4명 출현입니다만 제가 16비트로 그리고 적군 7명 출현, 또 변수명을 제가 이해하기 쉽도록 많이 바꾸었습니다.

상용책이라 소스 공개하기가 부담스럽습니다만, 이미 신용우님의 소스를 출판사 자체에서 공개한 것을 제가 보았고... (소스가 필요하신 분들은 아래 제 홈에 링크를 해 두었습니다.)
http://my.dreamwiz.com/kns3838/html/L2_han/g_theory/2D_API/a_4_0.htm

그냥 복사하기 보다는 90% 가까이는 제가 이해하고 있기에 이제는 큰 부담이 없군요! 그러나, 근본은 상용이라는 점에 유의해 주시기 바랍니다. 

본 소스는 특히 충돌은 분석이 완료된 것은 아니며 특히 완전 초보자를 위한 전반적인 안내 주석을 달아놓지 못했지만, 필요하신 분이 있을 듯 하여 급하게 소스를 올립니다. 본 소스에서는 - 편집 완료가 되지않아 - 아군 폭발 그림 frame에 다소 문제가 있을 것 같습니다. (사실 본 소스는 8비트 부터 (구조체 사용 여부도 구별해가면서) 적군 소수 출현부터 ~ 16비트 적군 다수 출현, 그리고 왕 출현, 점수, 배경 음악 삽입 등으로 대략 10단계별로 시도 중 입니다만 급히 이 부분만을 올리게 되었습니다. (이 부분의 보다 쉬운 소스가 필요하신 분들은 kns3838@dreamwiz.com 권남수로 따로 연락을 바랍니다. )

본 소스외에도 슈팅 분석 소스들이 또 있고 - 편집은 제가 주로 했지만 - 제 힘으로 만든 소스들이 아니기에 공개하기에는 항상 죄송하고, 불안합니다. 그러나, 급한 분이 있다면 연락 바랍니다. 그 동안 많은 게임 고수님들의 헌신적인 지도 덕분에 2년이 지난 오늘 - 한국 게임 개발자 협의회 - 라는 무시 무시한(?) 사이트에 나름대로 저의 편집 소스라도 up하게 되어 참으로 영광입니다. 시작하시는 분들에게 다소나마 도움이 되기를 바랍니다. 아울러 고수님들의 오류 수정과 분석 내용에 대한 지도도 부탁드립니다. 감사합니다. 
*/

#include <windows.h>
#include <ddraw.h>
#include <stdio.h>

#define SafeRelease(x) if (x) { x->Release(); x=NULL; } 

// 아군 구조체
typedef struct 
{
  int x, y;  // 모니터의 아군 x, y 좌표         
  int width;  // 아군 넓이. (포토샵 info를 그림 크기 확인) 
  int height;   // 아군 높이.
  int x_frame[5];  // 3차 표면 즉, 그림의 아군 x위치. 아군 그림은 5장임. 
  int y_frame[5];  // 3차 표면 즉, 그림의 아군 y위치. 아군 그림은 5장임. 
  int start;   // 현재의 프레임 번호 (시작은 언제나 0부터~4번까지)
  int akun_die;  // 아군의 죽음 여부. (0과 1로 생사 여부 결정) 
} SPRITE_CHAR; 
SPRITE_CHAR Akun; // 아군 구조체명.

// 아군 총알 구조체
typedef struct 
{
  int x[9];   // 모니터의 아군 총알 x 좌표   
  int y[9];   // 모니터의 아군 총알 y 좌표   
  int width; // 아군 총알의 넓이. (포토샵을 통해 그림 크기 확인)
  int height; // 아군 총알의 높이.
  int x_frame; // 3차 표면 즉, 그림에서의 아군 총알 x위치
  int y_frame; // 3차 표면 즉, 그림에서의 아군 총알 y위치
  int akun_shoot[9];  // 아군 총알 발사 유효 여부. 아군 총알수 9발. (0과 1로 등장 여부 결정) 
 } AKUN_CHAR;
AKUN_CHAR Akun_ChongAL; // 아군 총알 구조체명.

// 적군 구조체
typedef struct 
{    
  int x, y; // 모니터의 적군 x, y 좌표          
  int width; // 적군의 넓이. (포토샵을 통해 그림 크기 확인) 
  int height; // 적군의 높이
  int x_frame[4]; // 3차 표면 즉, 그림에서의 적군 x위치. 적군 그림은 최대 4장. (1장을 쓰는 적도 있음)  
  int y_frame[4]; // 3차 표면 즉, 그림에서의 적군 y위치. 적군 그림은 최대 4장. (1장을 쓰는 적도 있음)  
  int start;   // 현재 프레임 번호 (시작은 언제나 0번부터~3번까지)
  int geok_show;	 // 적군의 모니터에 등장 여부. (0과 1로 등장 결정) 아군은 자동으로 등장함.
  int geok_die; // 적군의 사망 여부 결정. (0과 1로 사망 여부 결정) 
} Geok_CHAR;
Geok_CHAR Geok[33]; // 적군 구조체명. (33마리이므로 배열로)

// 적군 총알 구조체
typedef struct 
{
  int x[3];  // 모니터의 적군 총알 x 좌표. (3발임)
  int y[3];  // 모니터의 적군 총알 y 좌표. (3발임)
  int width; // 적군 총알 넓이
  int height; // 적군 총알 높이
  int x_frame; // 3차 표면 즉, 그림에서의 x좌표. 
  int y_frame; // 3차 표면 즉, 그림에서의 y좌표. 
  int geok_shoot[3]; // 적군 총알 발사 여부 결정. (3발) (0과 1로 발사 여부 결정)
} GeokBULLET_CHAR;
GeokBULLET_CHAR Geok_ChongAL[33]; // 적군 총알 구조체명. (적군 33명과 연관되기에 배열)

// 폭발 구조체
typedef struct 
{
  int x[6]; // 모니터의 폭발 그림의 x 좌표. (6장 그림임)
  int y[6]; // 모니터의 폭발 그림의 x 좌표. (6장 그림임)
  int width; // 폭발 그림 넓이.
  int height; // 폭발 그림 높이.
  int x_frame[6]; // 3차 표면 즉, 그림에서의 x좌표. (6장 그림임)
  int y_frame[6]; // 3차 표면 즉, 그림에서의 y좌표. (6장 그림임)
  int agun_explode; // 아군의 폭발 여부. (0과 1로 결정)
  int geok_explode[33]; // 적군의 폭발 여부. (0과 1로 결정) (적군 33마리에 적용)
} POKBAL_CHAR;
POKBAL_CHAR Pokbal; // 폭발 구조체명.

// 적군 등장표 아래는 (3가지 속성) 즉, 출현시간, 적군 종류, 패턴     
/*
본 소스에서는 적군이 순차적으로 출현하도록 순서를 바꾸었다. 즉, 0번 적군부터 그리고 0번 패턴부터.
*/

int GEOK_TABLE[33][3] = { 
                           20, 0, 0, // 첫번째 적군
                           10, 0, 0, 
                           20, 0, 0, 
                           30, 0, 1,
                           20, 0, 1, 
                           50, 0, 3,

                           30, 1, 0, // 두번째 적군
                           40, 1, 0, 
                           30, 1, 1, 
                           50, 1, 1,
                           50, 1, 1,

                           50, 2, 0, // 세번째 적군
                           20, 2, 0,
                           40, 2, 1,
                           50, 2, 1,

                           10, 3, 0, // 네번째 적군
                           50, 3, 1,
                           20, 3, 2,
                           30, 3, 2,
                           50, 3, 3,

// 이하 13개 적군을 추가시켰다.

                           50, 4, 0, // 다섯번째 적군
                           50, 4, 0,
                           50, 4, 1,

                           50, 5, 0, // 여섯번째 적군 
                           50, 5, 0,
                           50, 5, 1,
                           50, 5, 2,

                           50, 6, 0, // 일곱번째 적군
                           50, 6, 0,
                           50, 6, 1,

                           50, 7, 0, // 여덟번째 적군
                           50, 7, 1,
                           50, 7, 2
                           }; // 적이 많으면 계속 길게 적게된다. (모두 33줄 즉, 적군 33명) 

/*
이제 위의 도표를 계산하여 아래와 같이 정리할 수 있다. 


위 도표를 통해서 "패턴합계"가 결정되면 이것이 결국 아래 int GPATTERN에 있는 첫번째 배열인 [ ]의 숫자로 결정되는 것이다. 그래서 [21]이 된다.

*/

// 아래는 적군의 패턴인데 - 과거 11개 패턴에서 - 이번에는 21개로 늘어나게 되었다. [14]의 수치는 그대로 사용하겠음. 위의 도표를 통해 실제로 사용된 패턴이 - 순서적으로 세로로 - 적용된다.

int GPATTERN[21][14] = {
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200, // 0번 적군 0번 패턴임 (3회 사용됨) 
640, 300, -10, 0,  220, 400,  0, -10,  220, 300,  -10, 0, -200, 300, // 0번 적군 1번 패턴임 (2회 사용됨) 
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,   10, 0,  640, 200, // 0번 적군 3번 패턴임 (1회 사용됨) 
640, 400, -10, 0,  220, 400,  0, -10,  220, 300,   10, 0,  640, 300, // 1번 적군 0번 패턴임 (2회 사용됨) 
640, 200, -10, 0,  300, 200,  0,  10,  300, 300,  -10, 0, -200, 300, // 1번 적군 1번 패턴임 (3회 사용됨) 
640, 300, -10, 0,  300, 300,  0, -10,  300, 200,  -10, 0, -200, 200, // 2번 적군 0번 패턴임 (2회 사용됨)  
640,  50, -10, 0,  200,  50,  0,  10,  200, 350,   10, 0,  640, 350, // 2번 적군 1번 패턴임 (2회 사용됨)  
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,   10, 0,  640, 200, // 3번 적군 0번 패턴임 (1회 사용됨)  
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200, // 3번 적군 1번 패턴임 (1회 사용됨)  
640, 300, -10, 0,  300, 300,  0, -10,  300, 200,  -10, 0, -200, 200, // 3번 적군 2번 패턴임 (2회 사용됨)  
640, 450, -10, 0,  250, 450,  0, -10,  250, 150,   10, 0,  640, 150, // 3번 적군 3번 패턴임 (1회 사용됨)  

// 이번에 추가함. 앞의 것을 일단 그대로 사용했음. 
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200, // 4번 적군 0번 패턴임 (2회 사용됨) 
640, 400, -10, 0,  220, 400,  0, -10,  220, 300,  -10, 0, -200, 300, // 4번 적군 1번 패턴임 (1회 사용됨) 
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,   10, 0,  640, 200, // 5번 적군 0번 패턴임 (2회 사용됨) 
640, 400, -10, 0,  220, 400,  0, -10,  220, 300,   10, 0,  640, 300, // 5번 적군 1번 패턴임 (1회 사용됨) 
640, 200, -10, 0,  300, 200,  0,  10,  300, 300,  -10, 0, -200, 300, // 5번 적군 2번 패턴임 (1회 사용됨) 
640, 300, -10, 0,  300, 300,  0, -10,  300, 200,  -10, 0, -200, 200, // 6번 적군 0번 패턴임 (2회 사용됨)  
640,  50, -10, 0,  200,  50,  0,  10,  200, 350,   10, 0,  640, 350, // 6번 적군 1번 패턴임 (1회 사용됨)  
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,   10, 0,  640, 200, // 7번 적군 0번 패턴임 (1회 사용됨)  
640, 100, -10, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200, // 7번 적군 1번 패턴임 (1회 사용됨)  
640, 300, -10, 0,  300, 300,  0, -10,  300, 200,  -10, 0, -200, 200 // 7번 적군 2번 패턴임 (1회 사용됨)  
}; // 21번째까지 마지막 적군이 적용된다.

int mov_x[33]; // 적군 33마리가 패턴으로 이동할 때의 "이동" x축 수치값. 
int mov_y[33]; // 적군 33마리가 패턴으로 이동할 때의 "이동" y축 수치값. 
int pos_x[33]; // 적군 33명이 패턴으로 이동할 때의 "위치" x축 수치값.
int pos_y[33]; // 적군 33명이 패턴으로 이동할 때의 "위치" y축 수치값.
int end_x[33]; // 적군 33명이 패턴으로 이동할 때의 "끝" x축 수치값. 
int end_y[33]; // 적군 33명이 패턴으로 이동할 때의 "끝" y축 수치값. 

int mov_pos2[33]; // (0~13개 중 2번째의) "이동"과 "위치"에 대한 변수. 

// 아래 변수들은 적군 출현과 관계되어 필요
int Geok_total = 0; // 적군 33명 등장 여부 조절.
int time_begin = 0; // 적군 "출현 시간". 처음 나올 때(time_begin)와 
int time_end; // 마지막(time_end)으로 나올 때를 계산하여 등장 시간을 조절.
int pattern_add; // 적군이 등장할 패턴들을 조절하기 위한 변수.

// 객체 등의 변수들. 
LPDIRECTDRAW7          lpDD = NULL;        // DirectDraw 객체
LPDIRECTDRAWSURFACE7 lpPrimary = NULL;   // 1차표면
LPDIRECTDRAWSURFACE7 lpSecondary = NULL;  // 2차표면
LPDIRECTDRAWSURFACE7 lp_OffOne = NULL;    // 3차 표면1. 배경그림.
LPDIRECTDRAWSURFACE7 lp_OffTwo = NULL;   // 3차 표면2. 아군과 적군.
LPDIRECTDRAWSURFACE7 lp_OffThree = NULL;   // 3차 표면3. 추가한 적군
LPDIRECTDRAWCLIPPER   lp_Clipper = NULL;   // 클리퍼

HWND      hwnd = NULL; // 핸들값
int Akun_ChaongAL_su = 0; // 아군 총알수 9개. (초기값은 0)
int Geok_ChaongAL_su[33]; // 적군 총알수 33개. 

// 함수
int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow);
int Init();
int Init_sprite();
IDirectDrawSurface7 *DDLoadBitmap(IDirectDraw7 *pdd, LPCTSTR bmpfilename, int dx, int dy );
HRESULT DDCopyBitmap(IDirectDrawSurface7 *pdds, HBITMAP hbm, int x, int y, int dx, int dy);
HRESULT DDSetColorKey(IDirectDrawSurface7 *pdds, COLORREF rgb);
DWORD DDColorMatch(IDirectDrawSurface7 *pdds, COLORREF rgb);

int GameProc();
void Keyboard();
int Scroll(int speed, int left,  int top, int right, int bottom);

int Akun_appear(void);
void Akun_ChongAL_Appear(void); 
int Akun_killed(void);

int Geok_appear1(void);
int Geok_killed(int no);
int Geok_appear23(int no); 
int Geok_ChongAL_Appear(int num); // 추가됨. 
void Collide(int no);
int Collide_range(int ax1, int ax2, int ay1, int ay2,int bx1, int bx2, int by1, int by2);
long FAR PASCAL WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static void CleanUp(void);

// 시작
int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
   WNDCLASSEX wc; 	
   MSG		  msg;	

   wc.cbSize           = sizeof(WNDCLASSEX);
   wc.style	       = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc     = WindowProc; 
   wc.cbClsExtra       = 0; 
   wc.cbWndExtra    = 0;
   wc.hInstance	    = hInstance;
   wc.hIcon	    = LoadIcon(NULL, IDI_APPLICATION);
   wc.hCursor	    = LoadCursor(NULL, IDC_ARROW);
   wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
   wc.lpszMenuName  = NULL;
   wc.lpszClassName  = "kns";
   wc.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);

   RegisterClassEx(&wc);

   hwnd = CreateWindowEx(NULL, "kns",NULL,WS_POPUP,0,0,GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);

   Init();		// DirectDraw 초기화
   Init_sprite();	// 캐릭터 초기화

lp_OffOne = DDLoadBitmap( lpDD, "pic_ba.bmp", 0, 0 );
lp_OffTwo = DDLoadBitmap( lpDD, "pic_sp.bmp", 0, 0 );
lp_OffThree = DDLoadBitmap( lpDD, "pic_sp2.bmp", 0, 0 );

DDSetColorKey( lp_OffOne, RGB(0,0,0) ); // 배경인데 필요한 이유는?
DDSetColorKey( lp_OffTwo, RGB(0,0,0) ); // 캐릭터는 칼러키를 사용하기에 필요.
DDSetColorKey( lp_OffThree, RGB(0,0,0) ); // 추가 적군 캐릭터.

   while (TRUE)
   {
        if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
        {
            if (!GetMessage(&msg, NULL, 0, 0))
                return msg.wParam;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
	else
	{
       	    GameProc(); // 메인 루틴 
	}
   }   
} 

int Init()
{
    DDSURFACEDESC2    ddsd;
    DDSCAPS2            ddscaps;
    LPRGNDATA         rgn_data;   // 클리퍼에 대한 내용을 담고있는 구조체. (2가지가 나옴)

    ShowCursor( FALSE ); // 삭제하면 커서가 나타남  
    DirectDrawCreateEx(NULL, (VOID**)&lpDD,IID_IDirectDraw7, NULL);
    lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
    lpDD->SetDisplayMode(640, 480, 16, 0, 0);

        // 1차 표면
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |DDSCAPS_FLIP |DDSCAPS_COMPLEX;
    ddsd.dwBackBufferCount = 1;
    lpDD->CreateSurface(&ddsd, &lpPrimary, NULL);

        // 2차 표면
    ZeroMemory(&ddscaps, sizeof(ddscaps));
    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
    lpPrimary->GetAttachedSurface(&ddscaps, &lpSecondary);
    
        // 3차 표면 
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    ddsd.dwWidth  = 640; 
    ddsd.dwHeight = 480;

    lpDD->CreateSurface(&ddsd, &lp_OffOne, NULL); // 배경화면에 대한 3차 표면을 생성.
    lpDD->CreateSurface(&ddsd, &lp_OffTwo, NULL); // 아군, 적군 캐릭터의 3차 표면 생성.
    lpDD->CreateSurface(&ddsd, &lp_OffThree, NULL); // 추가 적군의 3차 표면 생성.

// 이하의 클리핑 처리를 생략하면 역시 화면 끝의 그림들이 어색하게 등장, 사라짐.
   lpDD->CreateClipper(0, &lp_Clipper, NULL); //클리퍼를 생성하고.
   rgn_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER) +sizeof(RECT)); // 구조체 필드 2개를 더하기
			  
       // RGNDATAHEADER의 필드 채우기
   rgn_data->rdh.dwSize       = sizeof(RGNDATAHEADER);
   rgn_data->rdh.iType        = RDH_RECTANGLES; // 사각형임을 전달함.
   rgn_data->rdh.nCount       = 1; // 전체 모니터으로 클리핑 처리를 하기에 
   rgn_data->rdh.nRgnSize     = sizeof(RECT); // 버퍼 필드가 RECT와 연관되기에 

   SetRect(&(rgn_data->rdh.rcBound), -640, -480, 640*2, 480*2); // rcBound ("경계영역") 필드를 채우기. 내 맘대로 크기를?
   SetRect((RECT*)(rgn_data->Buffer), 0, 0, 640, 480); // 경계영역과 상대되는 "모니터" 크기 설정. buffer 필드와 연관됨.

   lp_Clipper->SetClipList(rgn_data, 0); // 위 절차를 거쳤다면 전체 크기인 rgn_data로 "클리퍼 내용"을 설치.
   lpSecondary->SetClipper(lp_Clipper); // "클리퍼 객체"를 이제는 2차 표면으로 연결시키 준다.
   free(rgn_data); // 해제 여부는? 클리핑 처리 끝.
   return 1;
}

// 5개 구조체의 기본적인 부분의 값을 채우는 단계 즉, 초기화이다.
int Init_sprite() //단순한 내용임.
{
  // ① 아군 구조체의 기본 사항 초기화
  int i; // 아군 총알, 적군 등등을 위한 변수.

  // 아군의 모니터의 위치
  Akun.x = 291; // 시작할 때 아군이 모니터의 중앙에 나타나게 하기 위한 계산. 640* 480임을 감안하고 아래 캐릭터의 넓이, 높이를 따져서 대충(?) 계산한다. (아래의 넓이, 높이를 계산한 후에 결정하기)
  Akun.y = 194; // 아군이 모니터의 중앙에서 시작하게 함. 

  // 아군의 크기 
  Akun.width  = 89; // 아군의 넓이를 저장한다.
  Akun.height = 38; // 아군의 높이를 저장한다.

  // 아군의 3차 표면 위치
  Akun.x_frame[0] =  10; // 아군 캐릭터의 첫 번째(0) 그림 ("아1")의 글씨의 x의 왼쪽 모서리.
  Akun.y_frame[0] =  19; // 아군 캐릭터의 첫 번째(0) 그림 ("아1")의 글씨의 y의 왼쪽 모서리.
  Akun.x_frame[1] =  117; // 아군 캐릭터의 두번째(1) 그림 ("아2")의 글씨의 x의 왼쪽 모서리.
  Akun.y_frame[1] =  19;  // 아군 캐릭터의 두번째(1) 그림 ("아2")의 글씨의 y의 왼쪽 모서리.
  Akun.x_frame[2] =  225; // 아군 캐릭터의 세번째(2) 그림 ("아3")의 글씨의 x의 왼쪽 모서리. 
  Akun.y_frame[2] =  19; // 아군 캐릭터의 세번째(2) 그림 ("아3")의 글씨의 y의 왼쪽 모서리. 
  Akun.x_frame[3] =  337; // 아군 캐릭터의 네번째(3) 그림 ("아4")의 글씨의 x의 왼쪽 모서리. 
  Akun.y_frame[3] =  19; // 아군 캐릭터의 네번째(3) 그림 ("아4")의 글씨의 y의 왼쪽 모서리. 
  Akun.x_frame[4] =  444; // 아군 캐릭터의 다섯번째(4) 그림 ("아5")의 글씨의 x의 왼쪽 모서리. 
  Akun.y_frame[4] =  19; // 아군 캐릭터의 다섯번째(4) 그림 ("아5")의 글씨의 y의 왼쪽 모서리. 

  
  // 아군을 죽지 않게 함.
  Akun.start = 0; // 아군 5장 그림 frame 중 맨 처음(0) 그림을 나오게 함.
  Akun.akun_die = 0; // 아군의 죽음 여부 0.



  // ② 아군 총알 구조체의 초기화 (위와 같은 구조체 기본 내용을 초기화시킨다.)
 // 아군 총알 크기 
    Akun_ChongAL.width  =  26; // 아군 총알의 넓이.
    Akun_ChongAL.height =   9; //  아군 총알의 높이.

 // 아군 총알의 3차 표면 위치
    Akun_ChongAL.x_frame = 543; // 아군 총알의 3차 표면 즉, 그림에서의 x위치. 
    Akun_ChongAL.y_frame = 44; // 아군 총알의 3차 표면 즉, 그림에서의 y위치. 
  
 // 아군 총알을 등장하기 않기
    for (i=0; i<9; i++) // 아군 총알 수 9개 
    {
       Akun_ChongAL.akun_shoot[i] =  0; // 처음에는 아군 총알이 나타나지 않게 해둔다. (0)
    }

  // ③ 적군 구조체 초기화 
  // 적군은 4종류이기에 각각 따로 처리한다. 
  for (i=0; i<33; i++) // 적군은 모두 33 마리임. 
    {
      if (GEOK_TABLE[i][1] == 0) // 첫번째 적군. [i]는 적군 33마리. 이때 0이란 첫번째 적군임. 즉, 첫번째 적군의 1번 패턴을 적용시킴. [1]는 패턴 즉, 1번 패턴.
       {
        // 첫번째 적군 크기.
        Geok[i].width  = 81; 
        Geok[i].height =  22; 

       // 첫번째 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] =  24; // (4장 그림 중 이 적군은 1장만 사용함.)
	Geok[i].y_frame[0] =  81;

        // 첫번째 적군의 총알 크기
        Geok_ChongAL[i].width  =  27; 
        Geok_ChongAL[i].height =  12;

        // 첫번째 적군의 3차 표면의 총알 위치.
       Geok_ChongAL[i].x_frame  = 121;
       Geok_ChongAL[i].y_frame  = 90;
       }

      else
      if (GEOK_TABLE[i][1] == 1) // 두번째 적군. [i]는 적군 33마리. 이때 1이란 두번째 적군임. 즉, 두번째 적군의 1번 패턴을 적용시킴. [1]는 패턴 즉, 1번 패턴.
       {
        // 2번 적군의 크기.
	Geok[i].width  = 81; 
	Geok[i].height =  21;

        // 2번 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] = 24; // (4장 그림 중 2번 적군은 2장만 사용함.)
	Geok[i].y_frame[0] = 123;
	Geok[i].x_frame[1] =  116;
	Geok[i].y_frame[1] =  123;

        // 2번 적군의 총알 크기
	Geok_ChongAL[i].width  =  29; 
	Geok_ChongAL[i].height =  11;

        // 2번 적군의 3차 표면의 총알 위치.
	Geok_ChongAL[i].x_frame  = 214; 
	Geok_ChongAL[i].y_frame  = 131;
      }

      else
      if (GEOK_TABLE[i][1] == 2) // 세번째 적군. [i]는 적군 33마리. 이때 2란 세번째 적군임. 즉, 세번째 적군의 1번 패턴을 적용시킴. [1]는 패턴 즉, 1번 패턴.
		{
        // 3번 적군의 크기.
	Geok[i].width  = 77; 
	Geok[i].height =  25;

        // 3번 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] =  23; // (4장 그림 중 3번 적군은 3장만 사용함.)
	Geok[i].y_frame[0] =  169;
	Geok[i].x_frame[1] =  116;
	Geok[i].y_frame[1] =  169;
	Geok[i].x_frame[2] =  220;
	Geok[i].y_frame[2] =  169;

        // 3번 적군의 총알 크기
	Geok_ChongAL[i].width  =  31; 
	Geok_ChongAL[i].height =  13;

        // 3번 적군의 3차 표면의 총알 위치.
	Geok_ChongAL[i].x_frame  = 317; 
	Geok_ChongAL[i].y_frame  = 176;
      }

      else
      if (GEOK_TABLE[i][1] == 3) // 네번째 적군. [i]는 적군 33마리. 이때 3이란 네번째 적군임. 즉, 네번째 적군의 1번 패턴을 적용시킴. [1]는 패턴 즉, 패턴을 적용시킨다.
      {
        // 4번 적군의 크기.
	Geok[i].width  = 77; 
	Geok[i].height =  30;

        // 4번 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] =  20; // (4장 그림 중 4번 적군은 4장 모두 사용함.)
	Geok[i].y_frame[0] =  212;
	Geok[i].x_frame[1] =  119;
	Geok[i].y_frame[1] =  212;
	Geok[i].x_frame[2] =  222;
	Geok[i].y_frame[2] =  212;
	Geok[i].x_frame[3] =  317;
	Geok[i].y_frame[3] =  212;

        // 4번 적군의 총알 크기
	Geok_ChongAL[i].width  =  27; 
	Geok_ChongAL[i].height =  12;

        // 4번 적군의 3차 표면의 총알 위치.
	Geok_ChongAL[i].x_frame  = 412; 
	Geok_ChongAL[i].y_frame  = 223;
      }

      else
      if (GEOK_TABLE[i][1] == 4) // 다섯번째 적군. [i]는 적군 33마리. 이때 4란 다섯번째 적군임. 즉, 다섯번째 적군의 1번 패턴을 적용시킴. [1]는 패턴 즉, 1번 패턴.
      {
        // 5번 적군의 크기.
	Geok[i].width  = 40; 
	Geok[i].height =  77;

        // 5번 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] = 18; // (4장 그림 중 4번 적군은 4장 모두 사용함.)
	Geok[i].y_frame[0] = 12;
	Geok[i].x_frame[1] = 112;
	Geok[i].y_frame[1] =  15;
	Geok[i].x_frame[2] =  202;
	Geok[i].y_frame[2] =  12;
	Geok[i].x_frame[3] =  291;
	Geok[i].y_frame[3] =  13;

        // 5번 적군의 총알 크기
	Geok_ChongAL[i].width  =  38; 
	Geok_ChongAL[i].height =  25;

        // 5번 적군의 3차 표면의 총알 위치.
	Geok_ChongAL[i].x_frame  = 432; 
	Geok_ChongAL[i].y_frame  = 46;
      }

      else
      if (GEOK_TABLE[i][1] == 5) // 여섯번째 적군. [i]는 적군 33마리. 이때 5란 여섯번째 적군임. 즉, 여섯번째 적군의 패턴을 적용시킴. [1]는 패턴을 뜻함.
      {
        // 6번 적군의 크기.
	Geok[i].width  = 55; 
	Geok[i].height =  73;

        // 6번 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] =  16; // (4장 그림 중 4번 적군은 4장 모두 사용함.)
	Geok[i].y_frame[0] =  116;
	Geok[i].x_frame[1] =  119;
	Geok[i].y_frame[1] =  110;
	Geok[i].x_frame[2] =  217;
	Geok[i].y_frame[2] =  108;
	Geok[i].x_frame[3] =  275;
	Geok[i].y_frame[3] =  117;

        // 6번 적군의 총알 크기
	Geok_ChongAL[i].width  =  40; 
	Geok_ChongAL[i].height =  29;

        // 6번 적군의 3차 표면의 총알 위치.
	Geok_ChongAL[i].x_frame  = 432; 
	Geok_ChongAL[i].y_frame  = 130;
      }

      if (GEOK_TABLE[i][1] == 6) // 일곱번째 적군. [i]는 적군 33마리. 이때 6란 일곱번째 적군임. 즉, 일곱번째 적군의 패턴을 적용시킴. [1]는 패턴을 뜻함.
      {
        // 7번 적군의 크기.
	Geok[i].width  = 60; 
	Geok[i].height =  89;

        // 7번 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] =  26; // (4장 그림 중 4번 적군은 4장 모두 사용함.)
	Geok[i].y_frame[0] =  210;
	Geok[i].x_frame[1] =  116;
	Geok[i].y_frame[1] =  202;
	Geok[i].x_frame[2] =  210;
	Geok[i].y_frame[2] =  207;
	Geok[i].x_frame[3] =  305;
	Geok[i].y_frame[3] =  207;

        // 7번 적군의 총알 크기
	Geok_ChongAL[i].width  =  47; 
	Geok_ChongAL[i].height =  34;

        // 7번 적군의 3차 표면의 총알 위치.
	Geok_ChongAL[i].x_frame  = 427; 
	Geok_ChongAL[i].y_frame  = 228;
      }

      if (GEOK_TABLE[i][1] == 7) // 여덟번째 적군. [i]는 적군 33마리. 이때 7이란 여덟번째 적군임. 즉, 여덟번째 적군의 패턴을 적용시킴. [1]는 패턴을 뜻함.
      {
        // 8번 적군의 크기.
	Geok[i].width  = 46; 
	Geok[i].height =  84;

        // 8번 적군의 "3차 표면" 위치
	Geok[i].x_frame[0] =  19; // (4장 그림 중 4번 적군은 4장 모두 사용함.)
	Geok[i].y_frame[0] =  312;
	Geok[i].x_frame[1] =  115;
	Geok[i].y_frame[1] =  314;
	Geok[i].x_frame[2] =  226;
	Geok[i].y_frame[2] =  314;
	Geok[i].x_frame[3] =  321;
	Geok[i].y_frame[3] =  318;

        // 8번 적군의 총알 크기
	Geok_ChongAL[i].width  =  41; 
	Geok_ChongAL[i].height =  39;

        // 8번 적군의 3차 표면의 총알 위치.
	Geok_ChongAL[i].x_frame  = 428; 
	Geok_ChongAL[i].y_frame  = 324;
      }

        // 적군에 대한 사항. (앞의 아군과 비교)
        Geok[i].start = 0; // 적군의 첫번째 그림 frame이 나오게 설정한다.
        Geok[i].geok_die = 0; // 적군의 죽음 여부 0.
	Geok[i].geok_show =  0; // 적군 등장(geok_show) 여부 0.
	mov_pos2[i] = 2; // 증감 현상은 (가로) 패턴 "14단계" 중 2번째 (배열이므로 결국 3번째의 것이지만)를 가리키는 뜻의 표현. (꼭 필요하지는 않음.) 

  // ④ 적군 총알 초기화 
// Geok_ChongAL은 33발, geok_shoot는 3발.
  Geok_ChongAL[i].geok_shoot[0] =  0; // 0 즉, 첫번째 적군 총알 발사를 안 시킴())
  Geok_ChongAL[i].geok_shoot[1] =  0; // 1 즉, 두번째 적군 총알 발사를 안 시킴())
  Geok_ChongAL[i].geok_shoot[2] =  0; // 2 즉, 세번째 적군 총알 발사를 안 시킴())
  Geok_ChaongAL_su[i] = 0; // 적군 총알은 - 아군 총알의 경우와 달리 - 저절로 알아서 발사되므로 이 부분에 대한 등장 여부도 필요함.
  }

// ⑤ 폭발 구조체의 초기화 
  // 폭발 그림의 크기
  Pokbal.width  = 97; 
  Pokbal.height = 86;

  // 폭발 그림의 3차 표면 위치
  Pokbal.x_frame[0] =  30; // "3차 표면"에서의 위치. 그림 6장.
  Pokbal.y_frame[0] =  302;
  Pokbal.x_frame[1] =  105;
  Pokbal.y_frame[1] =  292;
  Pokbal.x_frame[2] =  205;
  Pokbal.y_frame[2] =  281;
  Pokbal.x_frame[3] =  313;
  Pokbal.y_frame[3] =  262;
  Pokbal.x_frame[4] =  448;
  Pokbal.y_frame[4] =  286;
  Pokbal.x_frame[5] =  547;
  Pokbal.y_frame[5] =  303;

  // 이하 아군과 적군의 폭발 여부
  Pokbal.agun_explode = 0; // 아군은 폭발되지 않게한다. 0

  for (i=0; i < 33; i++) // 적군 33마리에 대해서.
    {
      Pokbal.geok_explode[i] = 0; // 적군도 폭발되지 않게한다. 0
    }

  time_end = GEOK_TABLE[Geok_total][0]; // 적군 33마리에 대한 [0] 즉, '지연 시간'을 time_end 변수에 넣어 적군 출현을 지연시킨다.
  return 1;
}

// 이하는 MS사의 ddutil.cpp을 풀어서 사용한 것임. 여기서 3차 표면을 만든다.
IDirectDrawSurface7 *DDLoadBitmap(IDirectDraw7 *pdd, LPCTSTR bmpfilename, int dx, int dy )
{
BITMAP bm; // BITMAP 구조체의 변수.
HBITMAP hbm; // 그림의 핸들값.
DDSURFACEDESC2 ddsd; // 3차 표면을 만들기 위해 DDSURFACEDESC2 구조체의변수.
IDirectDrawSurface7 *pdds; // (내부에서 사용할) 3차 표면의 객체임.

hbm = (HBITMAP) LoadImage(NULL, bmpfilename, IMAGE_BITMAP, dx, dy, LR_LOADFROMFILE | LR_CREATEDIBSECTION); // LoadImage 함수를 이용하여 그림 화일을 본 함수에서 사용되는 그림의 핸들값(hbm)으로 전달한다.

GetObject(hbm, sizeof(bm), &bm); // 그리고, 그림 크기(bm)와 그림의 주소를 핸들값(hbm)으로 전달한다. 이렇게 하여 hbm에 그림이 들어가게 된다. (hbm는 뒤에서 사용될 것임.)

// 그리고, 이제 3차 표면을 다음과 같이 생성한다. (그림의 크기와 똑 같은 것을)
memset( &ddsd, 0, sizeof(ddsd) ); // 대신 ZeroMemory를 사용 가능. 메모리 안에있는 것은 우선 몽땅 비우고
ddsd.dwSize = sizeof(ddsd); // ddsd 구조체 변수의 크기는 dwSize 멤버변수에 넣는다.
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; // 가로, 세로 크기를 사용하겠다는 뜻으로 dwFlags 멤버변수에 직접 넣어준다.
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; // 3차 표면을 사용하겠다는 뜻을 dwCaps 멤버변수로 전달한다.

ddsd.dwWidth = bm.bmWidth; // 그림 크기의 넓이를 3차 표면에 넣기 위해 ddsd의 dwWidth 멤버변수로 전달한다. 이렇게 하여 3차 표면에 그림의 가로 크기가 실제로 들어가고

ddsd.dwHeight = bm.bmHeight; // 그림 크기의 높이를 3차 표면에 넣기 위해 ddsd의 dwHeight 멤버변수로 전달한다. 이렇게 하여 3차 표면에 그림이 세로 크기가 실제로 들어가게 된다. 이렇게 하여 3차 표면에 그림이 실제로 들어가게 된다.

pdd->CreateSurface(&ddsd, &pdds, NULL); // 이제 드디어 3차 표면을 생성한다. 즉, lpDD에서 pdd로 전달하고, 이를 통해 (내부에서 사용될) 3차 표면 객체인 pdds를 생성한다.

DDCopyBitmap(pdds, hbm, 0, 0, 0, 0); // 그림이 들어가 있는 핸들값인 hbm을 (내부의) 3차 객체인 pdds로 복사해 준다. 즉, 만들어둔 3차 표면으로 그림을 복사해 주는 내용임.
DeleteObject(hbm); // 사용자 함수처럼(?) 사용된 hbm은 이제 삭제해 준다.
return pdds; // 그림이 들어가 있는 (내부의) 3차 객체를 리턴시킨다.
}

// 3차 표면으로 그림을 복사해 주는 과정임. 그림이 들어가 있는 핸들값(hbm)의 내용을 (내부의) 3차 객체인 pdds로 복사하는 내용이다.
HRESULT DDCopyBitmap(IDirectDrawSurface7 *pdds, HBITMAP hbm, int x, int y, int dx, int dy)
{
HDC hdc; // 일반 DC의 핸들.
HDC memDC; // 메모리 DC의 핸들.
BITMAP bm; // BITMAP 구조체의 변수.
DDSURFACEDESC2 ddsd; // 표면을 만드는 DDSURFACEDESC2 구조체의 변수.

// 원래 그림과 같은 3차 표면에 복사를 해 준기 위한 사전에 해 줄 일인 듯.
pdds->GetDC(&hdc); // 화면 DC 얻기.
memDC = CreateCompatibleDC(HDC (hdc)); // 메모리DC 얻기.
SelectObject(memDC, hbm); // hbm안에 있는 그림이 memDC 즉, 메모리DC로 들어간다.
GetObject(hbm, sizeof(bm), &bm); // bm 즉 그림 변수를 통해서 그림의 크기와, 그림의 주소를 찾아 그림의 핸들값인 hbm으로 전달해 준다. 이렇게하여 오브젝트의 성격(=그림)이 무엇인지를 컴퓨터에서 인식케 한다. 그림임을 알려준다.
dx = dx == 0 ? bm.bmWidth : dx; // 그림의 넓이를 dx에 넣어준다. 그림의 크기도 알려주어야 한다.
dy = dy == 0 ? bm.bmHeight : dy; // 그림의 높이를 dy에 넣어준다.

// 3차 표면을 만들기 위해 아래 내용까지도 필요한 듯.
ddsd.dwSize = sizeof(ddsd); // ddsd 구조체의 크기를 멤버변수인 dwSize로 전달함.
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; // 가로. 세로 크기도 dwFlags 멤버변수로 전달함.
pdds->GetSurfaceDesc(&ddsd); // 그리고 ddsd의 주소로 3차 표면을 채우는 듯.
StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, memDC, x, y, dx, dy, SRCCOPY); // Blt는 복사하는 기능임. 즉, memDC에 있는 자료를 hdc로 복사한다. 0, 0의 위치에다가. 그림의 넓이, 높이에 대한 정보를 가지고.
pdds->ReleaseDC(hdc); // GetDC를 사용후 다시 제거해 주어야 한다.
DeleteDC(memDC); // 사용한 memDC 즉, 메모리DC도 같이 제거함.
return 0;
} // 이하 배경그림만 있지 캐릭터가 없으므로 투명색 등은 사용할 필요가 없음.

HRESULT DDSetColorKey(IDirectDrawSurface7 *pdds, COLORREF rgb) // 캐릭터의 바탕색을 깨끗하게 처리하기 위해 이러한 칼러키를 적용시킨다. pdds는 캐릭터 객체인 lpThird2을 받게되며, rgb는 RGB 매크로를 받아 색상을 처리한다.
{
    DDCOLORKEY ddck; // 칼라키 설정을 위해 DDCOLORKEY 구조체가 사용된다.

    ddck.dwColorSpaceLowValue  = DDColorMatch(pdds, rgb); // 다시 DDColorMatch 함수를 통해 계산된 색상 처리의 결과를 dwColorSpaceLowValue 멤버변수로 넣어준다.
    ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue; // 앞에서 받은 Low의 값을 이처럼 High에 넣어준다. 결국 High에서 처리가 됨. 
    return pdds->SetColorKey(DDCKEY_SRCBLT, &ddck);
}

DWORD DDColorMatch(IDirectDrawSurface7 *pdds, COLORREF rgb) // pdds 즉, 캐릭터 객체인 lpThird2와 그 RGB 색상을 받아 처리하게 된다. 이하 내용은 분석을 포기함. 꼭 필요한 내용도 아님.
{
    HDC hdc;
    DWORD dw = CLR_INVALID;
    DDSURFACEDESC2 ddsd;
    COLORREF rgbT;

    CLR_INVALID && pdds->GetDC(&hdc);
    rgbT = GetPixel(hdc, 0, 0); // rgbT를 초기화시키는 듯.
    SetPixel(hdc, 0, 0, rgb); 
    pdds->ReleaseDC(hdc); // 따로 이렇게 제거를 시켜 주어야 함.

    ddsd.dwSize = sizeof(ddsd);
    while ((pdds->Lock(NULL, &ddsd, 0, NULL)));
		dw  = *(DWORD *)ddsd.lpSurface;
		dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1;
		pdds->Unlock(NULL);

    CLR_INVALID && pdds->GetDC(&hdc);
    SetPixel(hdc, 0, 0, rgbT);
    pdds->ReleaseDC(hdc);
    return dw;
}

int GameProc()
{
    DWORD         thisTickCount;
    static DWORD    lastTickCount = 0;
    DWORD          delay = 70; // 스크롤과 캐릭터의 속도에 모두 영향. 크면 느림.
    static int speedy1 = 8; // (이증 스크롤의) 화면 위쪽 스크롤 속도. (짤라내는 화면 크기임.) 
    static int speedy2 = 1; // (이증 스크롤의) 화면 아래쪽 스크롤 속도. (짤라내는 화면 크기임.) 
    int i; // 추가시킴.

     // 아군 그림 frame을 이용하여 애니메이션이 되는 시간 조절.
    thisTickCount = GetTickCount(); // 클럭틱을 얻어온다

    if ((thisTickCount - lastTickCount) > delay) // 클럭틱의 횟수를 비교한다
    {
       lastTickCount = thisTickCount;  // 정해진 횟수의 틱카운트이면 초기화한다 
   }
    else
	return 0;

   Keyboard(); // 키보드 설정.

    // 이하 모니터 화면에서 이중 스크롤을 시킨다.
    // 모니터 위부분 스크롤.
    if (speedy1 > 640) // (가로 스크롤이므로) 가로 화면 전체 크기 이상을 범위로 잡고.
      speedy1 = 1; // 스크롤 초기값은 1의 속도.
    Scroll(speedy1, 0, 0, 640, 400); // 화면 윗 부분의 영역 설정.
    speedy1+=6; // 실제 스크롤되는 속도임.

    // 모니터 아래부분 스크롤.
    if (speedy2 > 640) // (가로 스크롤이므로) 가로 화면 전체 크기 이상을 범위로 잡고 (아래쪽 영역)
	speedy2 = 1; // 스크롤 초기값은 1의 속도.
    Scroll(speedy2, 0, 388, 640, 480); // 화면 아래 부분의 영역 설정.
    speedy2 +=2; // 실제 스크롤되는 속도임.

    Akun_appear(); // 아군 등장의 함수.
    Akun_ChongAL_Appear(); // 아군 총알 출력 함수. 

    // 아군이 폭발할 경우
    if (Akun.akun_die==1) // 아군이 폭발할(1) 경우
       Akun_killed(); // 아군 사망 함수
    else
       {
        Akun_appear(); // 앞
        Akun_ChongAL_Appear(); // 앞
       }

    Geok_appear1(); // 적군출력 1단계

    // 적군이 폭발할 경우
    for (i=0; i < 33; i++)
      {
	if (Geok[i].geok_die==1) // 적군이 폭발할(1) 경우
	   Geok_killed(i); // 적군 사망 함수
	else
	  {
	    Geok_appear23(i); // 적군출력 2단계	
            Geok_ChongAL_Appear(i);
	    Collide(i);	
	  }
      }
    lpPrimary->Flip(NULL, 0);
    time_begin++;
    return 1;
}

void Keyboard() // 독립적 API 함수인 GetAsyncKeyState을 사용했다. 
{
    if(GetAsyncKeyState(VK_RIGHT)) // 오른쪽 방향키
    {
	if (Akun.x >= 600) // 오른쪽 범위 한계 조건
	   Akun.x =  600; // 오른쪽 범위 한계 설정
	else
	   Akun.x+=30;	// 아군 이동 속도
    }

    if(GetAsyncKeyState(VK_LEFT)) // 왼쪽 방향키
    {
	if (Akun.x <= -25) // 왼쪽
	   Akun.x =  -25;
	else
	   Akun.x-=30; 
    }

    if(GetAsyncKeyState(VK_UP)) // 위쪽 방향키
    {
	if (Akun.y <=  -19) // 위쪽
	   Akun.y =   -19;
	else
	   Akun.y-=30;	
    }

    if(GetAsyncKeyState(VK_DOWN)) // 아래쪽 방향키
    {
	if (Akun.y >= 450) // 아래쪽
	   Akun.y  = 450;
	else
	   Akun.y+=30;
    } // 동시에 키를 누르면 8개 방향으로 움직인다.

    if(GetAsyncKeyState(VK_CONTROL)) //  ctrl키는 총알 출력.
    {
	if (Akun_ChaongAL_su >= 9) // 아군 총알수가 9개를 넘으면
	   Akun_ChaongAL_su=0; //  다시 처음부터 시작하게 함.
	else // 아군 총알이 1~ 9개 경우라면 
	   if (Akun_ChongAL.akun_shoot[Akun_ChaongAL_su]==0) // 아군 총알 발사를 하지 않게 설정하고 
	      {					
		Akun_ChongAL.x[Akun_ChaongAL_su] = Akun.x + Akun.width - 29; // 아군 총알이 발사되는 x위치 설정.
    		Akun_ChongAL.y[Akun_ChaongAL_su] = Akun.y + Akun.height - 8; // 아군 총알이 발사되는 y위치 설정.
		Akun_ChongAL.akun_shoot[Akun_ChaongAL_su] = 1; // 아군 총알을 등장(1) 시켜주고.
		Akun_ChaongAL_su++; // 아군 총알은 9발까지 증가시켜 준다. 	
	      }
    }		
}

int Scroll(int SokDo, int left, int top, int right, int bottom) // SokDo는 앞에서 설정한 6과 또 2가 적용.
{
RECT src_rect, dest_rect; // src_rect는 3차 표면, dest_rect는 "모니터"  
    
// 이 이하에서는 x축의 6의 크기를 짤라 3차 표면에서 "모니터"의 반대 방향으로 복사시키고 또, 그 나머지의 큰 영역인(640-6)을 또 3차 표면에서 짤라 "모니터"의 반대 방향으로 복사시키는 과정이 나온다. (아래 영역은 2가 적용됨.)

// (우선 3차 표면의 왼쪽의 작은 영역을 짤라서 "모니터"의 오른쪽에다 붙여놓는 작업. 8크기의 개념)
// 3차 표면상에서의 위치를 계산한다 (3차 표면의 - 0, 0, 6, 480의 좌측부분의 작은 크기 영역 -을 짤라서)
    src_rect.left   =  left;
    src_rect.top    =   top;
    src_rect.right  = SokDo;  // 위의 speedy1 즉, 6을 받는다. 3차 표면의 왼쪽 6의 크기 부분
    src_rect.bottom =  bottom;

// 모니터상의 좌표를 계산한다   (모니터의 우측부분 - 즉, 634, 0, 640, 480의 오른쪽 위치에 - 불여놓는다.)
    dest_rect.left   = right-SokDo; // 640- 6 = 634의 크기. 위에서 6의 크기를 복사한 내용이 이 "모니터"에서는 오른쪽에 붙여진다.
    dest_rect.top    =   top;
    dest_rect.right  = right;
    dest_rect.bottom =  bottom;
    lpSecondary->Blt(&dest_rect, lp_OffOne, &src_rect, DDBLT_WAIT| DDBLT_KEYSRC, NULL);

// 640에서 위에서 짤라낸 크기(=6)을 뺀 나머지 큰 부분 즉, 634의 큰 영역을 처리한다.) 
//  3차 표면상에서의 위치를 계산한다 (3차 표면의 - 6, 0, 640, 480의 큰 영역 - 즉, 우측부분을 짤라서) 
    src_rect.left   = SokDo; // 6의 크기.    
    src_rect.top    =   top;
    src_rect.right  = right;
    src_rect.bottom = bottom;

//  모니터상의 좌표를 계산한다 (모니터의 - 0, 0, 634, 480의 큰 영역 - 즉, 모니터의 좌측부분에 붙여 놓는다.) 
    dest_rect.left   =   left;
    dest_rect.top    =   top;
    dest_rect.right  = right-SokDo; // 640- 6의 큰 영역.
    dest_rect.bottom = bottom;
    lpSecondary->Blt(&dest_rect, lp_OffOne, &src_rect, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
    return 1;
}

int Akun_appear(void) // 아군의 등장
{
    if (Akun.start > 4) // 아군 그림 5장이 계속 순환되도록 
       Akun.start = 0; // 다시 0번 그림부터 나타나게 함.

    RECT src_rect, dest_rect; // "3차 표면"과 "모니터"를 위한 사각형 설정.

// (아군이 모니터에서 나오는 x, y 위치는 앞에서 설정했었다. 여기서는 사각형의 크기를 적용시킨다)
//  "3차 표면"으로부터 사각형 크기를 얻어 rect에 넣어둔다.
    src_rect.left    = Akun.x_frame[Akun.start];
    src_rect.top     = Akun.y_frame[Akun.start];
    src_rect.right   = Akun.x_frame[Akun.start] +Akun.width;
    src_rect.bottom = Akun.y_frame[Akun.start] +Akun.height;

//  "모니터"에서의 사각형 크기를 얻어 rect에 넣어둔다.
    dest_rect.left   = Akun.x;
    dest_rect.top    = Akun.y;
    dest_rect.right  = Akun.x + Akun.width;
    dest_rect.bottom = Akun.y + Akun.height;

    lpSecondary->Blt(&dest_rect, lp_OffTwo,&src_rect, DDBLT_WAIT| DDBLT_KEYSRC, NULL); // "3차 표면"의 크기를 "모니터"으로 이동시키고, 그 결과를 2차 표면으로 복사시켜 준다. 
    Akun.start++; // 아군의 다음 그림이 나오도록 5장 그림을 모두 증가 시켜준다.
    return 1; 
}

void Akun_ChongAL_Appear(void) // 아군 총알 발사
{
    int i; // 아군 총알 최대 9발을 위한 변수.  
    RECT src_rect, dest_rect; // "3차 표면"과 "모니터"를 위한 사각형 설정.

    for (i=0; i<9; i++) // 아군의 총알 갯수
    {
	  if (Akun_ChongAL.akun_shoot[i]==1) // 아군 총알 발사가 유효(1)한 경우일 때
	  { 
           //  "3차 표면"으로부터 아군 총알 사각형 크기를 얻어 rect에 넣어둔다.
	   src_rect.left   = Akun_ChongAL.x_frame;
	   src_rect.top    = Akun_ChongAL.y_frame;
	   src_rect.right  = Akun_ChongAL.x_frame + Akun_ChongAL.width;
	   src_rect.bottom = Akun_ChongAL.y_frame + Akun_ChongAL.height;

           //  "모니터"에 나올 아군 총알 사각형 크기를 rect에 넣어둔다. (모니터에서는 총알이 9개 나오므로 배열로 처리.)
	   dest_rect.left   = Akun_ChongAL.x[i];
	   dest_rect.top    = Akun_ChongAL.y[i];
	   dest_rect.right  = Akun_ChongAL.x[i] + Akun_ChongAL.width;
	   dest_rect.bottom = Akun_ChongAL.y[i] + Akun_ChongAL.height;

  	   lpSecondary->Blt(&dest_rect, lp_OffTwo, &src_rect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); // 아군 총알의 "3차 표면" 크기를 "모니터"로 복사하고 그 결과를 "2차 표면"으로 복사해 준다.

// 이하 실제로 아군 총알 발사
 	   if (Akun_ChongAL.x[i] > 640 ) // 총알의 x위치가 640 모니터 밖으로 나가면
		Akun_ChongAL.akun_shoot[i] = 0; // 총알은 보이지 않게한다. (0)
	   else // 모니터 안쪽에 있을 경우라면 
		Akun_ChongAL.x[i] += 10; // 아군 총알 x의 발사 속도. (10)
	  }
    }
}

int Akun_killed(void) // 아군 사망
{
RECT src_rect, dest_rect; // src_rect는 3차 표면, dest_rect는 "모니터"

if (Pokbal.agun_explode > 6) // 폭발그림 6개임. 
  {
    Pokbal.agun_explode = 0; // 다시 아군이 폭발되는 첫 그림으로 보여준다.
    Akun.akun_die=0; // 다시 아군이 폭발되지 않는 상태(0)로 만들어 줌.
  }
else // 이하는 폭발이 진행되는 과정
  {
    // "3차 표면"의 폭발 그림 크기를 rect에 넣어둔다.
    src_rect.left   = Pokbal.x_frame[Pokbal.agun_explode];
    src_rect.top    = Pokbal.y_frame[Pokbal.agun_explode];
    src_rect.right  = Pokbal.x_frame[Pokbal.agun_explode]+Pokbal.width;
    src_rect.bottom = Pokbal.y_frame[Pokbal.agun_explode]+Pokbal.height;

  // "모니터"의 폭발 그림 크기를 rect에 넣어둔다.
  dest_rect.left   = Akun.x;
  dest_rect.top    = Akun.y;
  dest_rect.right  = Akun.x + Pokbal.width;
  dest_rect.bottom = Akun.y + Pokbal.height;

  lpSecondary->Blt(&dest_rect, lp_OffTwo, &src_rect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); // 요령은 앞의 것과 모두 같다.
  Pokbal.agun_explode++; // 아군 폭발 그림을 6장까지 계속 증가시킨다.
  Akun.akun_die=0; // 아군이 폭발되지 않는 상태(0)로 다시 만들어 줌.
  }
  return 1;
}

// 적군 출현은 아군보다 복잡하다.
int Geok_appear1(void)
{
// 조건 2가지. (항상 그렇듯이) 상황 설정부터 한다. 적군 출현은 적군수 33명을 넘지 않도록 해야하고, 4종류 적이 시간차를 두고 등장하도록 적군 처음 등장 시간(time_begin)과 마지막으로 등장하는 시간(time_end)을 비교한다.

  if (Geok_total < 33) // 적군 최대수 33을 체크한다.
  {
    if (time_begin > time_end ) // 적군의 모니터 출현 지연 설정.
    {
      time_begin = 0; // 첫 프레임부터 설정.

      // 적군 출현은 GEOK_TABLE과 "패턴"과 관련된다.

      // 패턴종류 (세로 21가지. 이 말은 GEOK_TABLE[21] 즉, GPATTERN[21]의 세로 21을 의미한다)
      if (GEOK_TABLE[Geok_total][1] == 0) // Geok_total이 0, 즉 첫번째 적군인 경우 ([1]은 "적군 종류")
	 pattern_add = GEOK_TABLE[Geok_total][2]; // ([2]란 "패턴"). 적군 "패턴"을 pattern_add 변수로 전달. (즉, 0번 패턴은 앞에서 받을 자료가 없지만... )

      else
      if (GEOK_TABLE[Geok_total][1] == 1) // Geok_total이 1, 즉 두번째 적군인 경우 ([1]은 "적군 종류")
         // 두번째 적군 이후부터는 적용이 달라지는데....
         pattern_add = GEOK_TABLE[Geok_total][2] + 3; // ([2]란 "패턴"). 적군 "패턴"에다가 3을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

/* 이후 "3"이 어떻게 적용되는지를 알아보자. 3이란 앞쪽의 적군에서 사용되었던 패턴 - 개수가 아니라 - "종류"를 나타내는 숫자이다. 즉, 3종류가 사용되었는데 이제 자세한 내용을 알아보자. 먼저 GEOK_TABLE를 통해 "적군 종류"와 "패턴"을 살펴본다.
int GEOK_TABLE[33][3] = { 20, 0, 1, // (3가지 속성) 즉, 출현시간, 적군 종류, 패턴     
                           30, 1, 0,
                           40, 2, 1,
                           50, 3, 3,
                           50, 2, 0,
                           10, 3, 0, 
                           20, 0, 0, 
                           30, 1, 1, 
                           50, 3, 1,
                           50, 0, 3,
                           40, 0, 0, 
                           50, 1, 1,
                           20, 3, 2,
                           40, 1, 0, 
                           30, 0, 1,
                           50, 2, 1,
                           50, 1, 1,
                           40, 0, 0, 
                           20, 2, 0,
                           10, 3, 2
                           }; 
위의 빨간색의 - "적군 종류"와 "패턴" - 을 정리해 보면 다음과 같다.


위처럼 계산되어 GPATTERN의 [11] 의 패턴이 성립되었다. 위의 내용을 종합하면 다음과 같다. 즉, 0번(첫번째 적군)적군은 3개의 패턴을 사용하고, 1번(두번쨰 적군) 적군은 2개의 패턴을 사용한다. 2번(세번째 적군) 적군은 2개의 패턴만을 사용하고, 3번(네번째 적군) 적군은 패턴 4가지를 모두 사용한다. 이렇게 해서 모두 11개 패턴이 사용되었다. 적군에서 사용되는 패턴은 3개, 2개, 2개, 4개인데 이들이 뒤쪽에서 - 합산되어져 실제로 3, 5, 7 - 이 그 다음 적군에 적용되는 것이다. (5, 7은 아래에서)
*/

      else 
      if (GEOK_TABLE[Geok_total][1] == 2) // Geok_total이 2, 즉 세번째 적군의 경우 ([1]은 "적군 종류")
         pattern_add = GEOK_TABLE[Geok_total][2] + 5; // ([2]란 "패턴".) 적군 "패턴"에 5을 더한 값을 pattern_add에 전달. (즉, 세번째 적군에는 첫 번째~ 두번째 적군의 패턴 종류의 합 - 5 - 가 적용된다.)

      else 
      if(GEOK_TABLE[Geok_total][1] == 3) // Geok_total이 3, 즉 네번째 적군의 경우. )[1]은 "적군 종류")
        pattern_add = GEOK_TABLE[Geok_total][2] + 7; // ([2]란 "패턴".) 적군 "패턴"에 7을 더한 값을 pattern_add에 전달. (즉, 네번째 적군에는 첫 번째~ 세번째 적군의 패턴 종류의 합 - 7 - 이 적용된다.)

      else 
      if(GEOK_TABLE[Geok_total][1] == 4) // Geok_total이 4, 즉 다섯번째 적군의 경우. )[1]은 "적군 종류")
        pattern_add = GEOK_TABLE[Geok_total][2] + 11; // ([2]란 "패턴".) 적군 "패턴"에 11을 더한 값을 pattern_add에 전달. (즉, 다섯번째 적군에는 첫 번째~ 네번째 적군의 패턴 종류의 합 - 11 - 이 적용된다.)

      else 
      if(GEOK_TABLE[Geok_total][1] == 5) // Geok_total이 5, 즉 여섯번째 적군의 경우. )[1]은 "적군 종류")
        pattern_add = GEOK_TABLE[Geok_total][2] + 13; // ([2]란 "패턴".) 적군 "패턴"에 13을 더한 값을 pattern_add에 전달. (즉, 여섯번째 적군에는 첫 번째~ 다섯번째 적군의 패턴 종류의 합 - 13 - 이 적용된다.)

      else 
      if(GEOK_TABLE[Geok_total][1] == 6) // Geok_total이 6, 즉 일곱번째 적군의 경우. )[1]은 "적군 종류")
        pattern_add = GEOK_TABLE[Geok_total][2] + 16; // ([2]란 "패턴".) 적군 "패턴"에 16을 더한 값을 pattern_add에 전달. (즉, 일곱번째 적군에는 첫 번째~ 여섯번째 적군의 패턴 종류의 합 - 16 - 이 적용된다.)

      else 
      if(GEOK_TABLE[Geok_total][1] == 7) // Geok_total이 7, 즉 여덟번째 적군의 경우. )[1]은 "적군 종류")
        pattern_add = GEOK_TABLE[Geok_total][2] + 18; // ([2]란 "패턴".) 적군 "패턴"에 18을 더한 값을 pattern_add에 전달. (즉, 일곱번째 적군에는 첫 번째~ 일곱번째 적군의 패턴 종류의 합 - 18 - 이 적용된다.)

// 위에서는 4종류 적군들의 - 패턴에다가 패턴 종류를 더한 - 출현 정보를 pattern_add 변수에 잠시 저장시켜 두었는데 이제는 그 자료를 - 가로 개념인 - 14단계 "시작, 이동, 위치, 끝"의 과정에 적용시키게 된다.

     // 시작 및 이동, 위치, 끝 (GPATTERN의 가로 14개)
     // "시작"의 대하여 (즉, 14단계 중 배열로 따지면 0, 1번임)
     // 이 "시작" 값을 모니터에 등장할 적군 첫출발점인 x, y 위치에 넣어둔다.
     Geok[Geok_total].x = GPATTERN[pattern_add][0]; // [0]이란 가로 14개 중 첫번째를 말함.
     Geok[Geok_total].y = GPATTERN[pattern_add][1]; // [1]이란 가로 14개 중 두번째를 말함.

     // "끝"에 대하여 (즉, 14단계 중 배열로 따지면 12, 13번임)
     // 이 "끝" 값을 따로 설정한 end_x 배열에 넣어둔다. 별도 변수가 설정됨. 
     end_x[Geok_total]   = GPATTERN[pattern_add][12]; // [12]란 가로 14개 중 13번째.
     end_y[Geok_total]   = GPATTERN[pattern_add][13]; // [13]란 가로 14개 중 14번째.

     // "이동"과 "위치"에 대하여 (1차 증감 상태)
     mov_pos2[Geok_total]  = 2;	// 증감 현상은 "14단계" 중 2번째부터 시작된다는 뜻임. (아래 도표 참고 : 배열이므로 3번째를 뜻하지만. 적군 "이동"은 3회, "위치"는 2회 변화된다. 위와 같은 1차 증감 상태에 적용하기위해 2를 넣었다. (또한, 2차 증감 상태에는 4를 넣게되는데 ....뒤에서 적용시킬 것이다.)
 
/*
int GPATTERN[11][14]= 
{640, 100, -10, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200, // 0번 적군이 0번 패턴을 3번 사용.

*/

     // ("이동1"값.)
     mov_x[Geok_total] = GPATTERN[pattern_add][mov_pos2[Geok_total]]; // (번호 2번)에 적용됨. (+ 0와 같은 효과)
     mov_y[Geok_total] = GPATTERN[pattern_add][mov_pos2[Geok_total]+1]; // 자체의 2에다가 y축이므로 +1을 했으니 (번호 3번)을 가리킨다.

     // ("위치1"값.)
     pos_x[Geok_total] = GPATTERN[pattern_add][mov_pos2[Geok_total]+2]; // 자체의 2에다가 +2을 했으니 (번호 4번)가 되며 "위치1"의 x좌표를 가리키게 된다.
     pos_y[Geok_total] = GPATTERN[pattern_add][mov_pos2[Geok_total]+3]; // 자체의 2에다가 y축이므로 +3을 했으니 (번호 5번)가 되어 "위치1"의 y좌표를 가리키게 된다.
// (번호 6번 이후는 뒤의 2차에서.) "이동"과 "위치"는 이런 계산을 하여 그 결과가 mov_x와 pos_x 등으로 전달된다.

     // 나머지 멤버 변수들도 적절한 값을 넣는다.
     Geok[Geok_total].geok_show = 1; // 적군 출현을 가능(1)하게 하고
     Geok_total++; // 적군 마리수(33명)까지 등장시키기.

     //	(앞과 같다.) 적군 출현 "시간 계산"에 대한 초기화. 적군 33명(Geok_total)이 대해 0번 즉, "시간 프레임"에 대한 설정값을 time_end 변수에 넣는다.
     time_end = GEOK_TABLE[Geok_total][0]; // [0]은 시간 개념임.
	}
    }
  return 1;   
}

int Geok_killed(int num) // 적군 폭발 (아군 폭발과 모두 같다.)
{
RECT src_rect, dest_rect; // src_rect는 3차 표면, dest_rect는 "모니터"

// 적군 폭발 그림의 체크 
if (Pokbal.geok_explode[num] > 6) // 폭발 그림 6개임.
  {
    Geok[num].geok_die = 0; // 적군 폭발도 일어 나지 않게 한다.
    Geok[num].geok_show = 0; // 적군도 나타나지 않게 한다. (0)
  }
else
  {
    // "3차 표면"의 폭발 그림 크기를 rect로 전달해 둔다.
    src_rect.left   = Pokbal.x_frame[Pokbal.geok_explode[num]];
    src_rect.top    = Pokbal.y_frame[Pokbal.geok_explode[num]];
    src_rect.right  = Pokbal.x_frame[Pokbal.geok_explode[num]] + Pokbal.width;
    src_rect.bottom = Pokbal.y_frame[Pokbal.geok_explode[num]] + Pokbal.height;

  // "모니터"에서의 위치를 rect로 전달해 둔다.
  dest_rect.left   = Geok[num].x; // 적의 위치가 곧 폭발의 위치가 된다.
  dest_rect.top    = Geok[num].y;
  dest_rect.right  = Geok[num].x + Pokbal.width;
  dest_rect.bottom = Geok[num].y + Pokbal.height;

  lpSecondary->Blt(&dest_rect, lp_OffTwo, &src_rect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); // 3차 표면의 것을 모니터로 전달시킨다. 

  Geok[num].geok_die = 0; // 적군 폭발은 더 일어나지 않게하며 (0)
  Geok[num].geok_show = 0; // 적군 출현도 더 없게 한다. (0) 그래야 사망이 되므로.
  Pokbal.geok_explode[num]++; // 적군 폭발 그림도 증가시킨다. 즉, 아군 폭발 그림을 증가시켰던
  }
  return 1;
}

// 적군 출력 2, 3단계
int Geok_appear23(int num) // num은 적군 33명 유형.
{
  RECT src_rect, dest_rect; // 3차 표면, 모니터용 사각형. 

  // 기본 상황 점검
  if (Geok[num].geok_show==1) // (즉, Gok_appear1을 통해) 적군 출현이 이미 가능(1)한 상태에서 
  {
    // 적군의 프레임 체크 (앞에서 최대 4개로 설정했었다. 그러나, 실제는 각 적군에 따라 각각 다르게 적용했는데...)

     if (GEOK_TABLE[num][1] == 0) // [1}은 적기 종류의 의미. 또한 0 즉, 1번 적기의 경우라면
	{
	   if (Geok[num].start > 0) // 0번 그림이 나오게 된다면 (이것은 그림을 1장만 준비했었음)
	      Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

	else 
        if (GEOK_TABLE[num][1] == 1) // 1 즉, 2번 적기의 경우라면
	{
	  if (Geok[num].start > 1) // 1번째 그림이 나오면 (이것은 그림을 2장만 준비했었음)
	     Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

	else 
	if (GEOK_TABLE[num][1] == 2) // 2 즉, 3번 적기의 경우라면
	{
	  if (Geok[num].start > 2) // 2번째 그림이 나오면 (이것은 그림을 3장만 준비했었음)
	     Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

	else 
	if (GEOK_TABLE[num][1] == 3) // 3 즉, 4번 적기의 경우라면
	{
	  if (Geok[num].start > 3) // 3번째 그림이 나오면 (이것은 그림을 4장 준비했었음)
	     Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

	else 
	if (GEOK_TABLE[num][1] == 4) // 4 즉, 5번 적기의 경우라면
	{
	  if (Geok[num].start > 3) // 3번째 그림이 나오면 (이것은 그림을 4장 준비했었음)
	     Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

	else 
	if (GEOK_TABLE[num][1] == 5) // 5 즉, 6번 적기의 경우라면
	{
	  if (Geok[num].start > 3) // 3번째 그림이 나오면 (이것은 그림을 4장 준비했었음)
	     Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

	else 
	if (GEOK_TABLE[num][1] == 6) // 6 즉, 7번 적기의 경우라면
	{
	  if (Geok[num].start > 3) // 3번째 그림이 나오면 (이것은 그림을 4장 준비했었음)
	     Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

	else 
	if (GEOK_TABLE[num][1] == 7) // 7 즉, 8번 적기의 경우라면
	{
	  if (Geok[num].start > 3) // 3번째 그림이 나오면 (이것은 그림을 4장 준비했었음)
	     Geok[num].start = 0; // 다시 첫번째 그림이 나오게 한다.
	}

     // 적군의 "위치" 체크 
	if (Geok[num].x==pos_x[num] && Geok[num].y==pos_y[num]) // 적군 33마리의 좌표가 "위치"를 나타내는 곳에 있다면 (이미 1차 이동을 통해서 "위치" - 즉 5번까지 -에 와 있었다)
	{
// 이하는 앞의 패턴종류 (세로 11가지) 의 내용과 결국 같다.
	  if (GEOK_TABLE[num][1] == 0) // num이 0번 즉, 첫번째적 적군이 나오면 ([1]은 "적군 종류")
	    pattern_add = GEOK_TABLE[num][2]; // ([2]란 "패턴"). 적군 "패턴"을 pattern_add 변수로 전달. (즉, 0번 패턴은 앞에서 받을 자료가 없지만... )

	  else
	  if (GEOK_TABLE[num][1] == 1) // num이 1번 즉, 두번째 적군이 나오면 ([1]은 "적군 종류")
         // 두번째 적군 이후부터는 적용이 달라지는데....
	    pattern_add = GEOK_TABLE[num][2] + 3; // ([2]란 "패턴"). 적군 "패턴"에다가 3을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

	  else
	  if (GEOK_TABLE[num][1] == 2) // num이 2번 즉, 세번째 적군이 나오면 ([1]은 "적군 종류")
	    pattern_add = GEOK_TABLE[num][2] + 5; // ([2]란 "패턴"). 적군 "패턴"에다가 5을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

          else
	  if (GEOK_TABLE[num][1] == 3) // num이 3번 즉, 네번째 적군이 나오면 ([1]은 "적군 종류")
	    pattern_add = GEOK_TABLE[num][2] + 7; // ([2]란 "패턴"). 적군 "패턴"에다가 7을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

          else
	  if (GEOK_TABLE[num][1] == 4) // num이 4번 즉, 다섯번째 적군이 나오면 ([1]은 "적군 종류")
	    pattern_add = GEOK_TABLE[num][2] + 11; // ([2]란 "패턴"). 적군 "패턴"에다가 11을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

          else
	  if (GEOK_TABLE[num][1] == 5) // num이 5번 즉, 여섯번째 적군이 나오면 ([1]은 "적군 종류")
	    pattern_add = GEOK_TABLE[num][2] + 13; // ([2]란 "패턴"). 적군 "패턴"에다가 13을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

          else
	  if (GEOK_TABLE[num][1] == 6) // num이 6번 즉, 일곱번째 적군이 나오면 ([1]은 "적군 종류")
	    pattern_add = GEOK_TABLE[num][2] + 16; // ([2]란 "패턴"). 적군 "패턴"에다가 16을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

          else
	  if (GEOK_TABLE[num][1] == 7) // num이 7번 즉, 여덟번째 적군이 나오면 ([1]은 "적군 종류")
	    pattern_add = GEOK_TABLE[num][2] + 18; // ([2]란 "패턴"). 적군 "패턴"에다가 18을 더한 값을 pattern_add에 전달. (뒤에서 이값을 적용시킬 것이다.)

      // "이동"과 "위치"에 대하여 (2차 증감 상태)
    mov_pos2[num] += 4; // 여기서 적용시킬 증감 현상은 "14단계" 중 6번째부터 시작된다는 뜻이 된다. 계산 방법은 아래 도표를 참고할 것. 즉, 1차 증감 상태에서 이미 2를 적용시켰었고, 여기다가 += 4을 더하므로 결국 번호 6부터 시작된다는 뜻이다. 다시 말하면 이렇게하여 2차 증감을 시작하게 된다.

/*
int GPATTERN[11][14]= 
{640, 100, -10, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200, // 0번 적군이 0번 패턴을 3번 사용.

*/

    // ("이동2"값.)
    mov_x[num]   = GPATTERN[pattern_add][mov_pos2[num]]; // (번호 6번)에 적용됨. (+ 0와 같은 효과)
    mov_y[num]   = GPATTERN[pattern_add][mov_pos2[num]+1]; // 자체의 6에다가 y축이므로 +1을 했으니 (번호 7번)을 가리킨다.

      // ("위치2"값.)
    pos_x[num]   = GPATTERN[pattern_add][mov_pos2[num]+2]; // 자체의 6에다가 +2을 했으니 (번호 8번)가 되며 "위치2"의 x좌표를 가리키게 된다.
    pos_y[num]   = GPATTERN[pattern_add][mov_pos2[num]+3]; // 자체의 6에다가 y축이므로 +3을 했으니 (번호 9번)가 되어 "위치2"의 y좌표를 가리키게 된다.

    // 정리 : 이렇게 하여 (저 앞에서는 mov_pos2[i] = 2; 를 통해 1차 이동값과 위치값 처리를 했고 여기서는 이어서 mov_pos2[num] += 4;를 추가하여 2차 이동값과 위치값 처리를 했다.

// 적군의 등장 여부 (위치를 이동시켜보자) 의 원래 위치임.

   //  적기의 총알 처리
    if (Geok_ChaongAL_su[num] >= 3) // 적군이 총알 3발을 다 쏘게 되면
       Geok_ChaongAL_su[num]=0; // 더 이상 적군은 총알 발사를 안함.

    else // 3발의 총알 발사의 경우에는
    if (Geok_ChongAL[num].geok_shoot[ Geok_ChaongAL_su[num] ]==0) // (항상 이런식으로 설정) 적군 총알 발사가 안되는 경우일 때는
       {					
          Geok_ChongAL[num].x[ Geok_ChaongAL_su[num] ] = Geok[num].x; // 적군 x위치를 그대로 적군 총알의 x위치로 잡아주고
	  Geok_ChongAL[num].y[ Geok_ChaongAL_su[num] ] = Geok[num].y + Geok[num].height - 8; // 적군 총알 발사의 y위치는 - 적군의 높이를 감안하며 -적군 y 위치에서 8을 뺀 상태의 좌표로 잡아준다.
          Geok_ChongAL[num].geok_shoot[ Geok_ChaongAL_su[num] ] = 1; // 이제 적군 총알 발사를 가능하게 해 준다.(1)
          Geok_ChaongAL_su[num]++; // 총알 수는 계속 늘려준다.
        }
   }

    // "3차 이동" 처리를 위해. 
// 3차 이동은 아래 도표처럼 "이동3" 밖에 없다. 따라서 "2차 이동"에서 만든 "이동2"의 값만을 그대로 증가시켜 적군 위치로 잡아주면 되는 듯 하다. 

/*
int GPATTERN[11][14]= 
{640, 100, -10, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200, // 0번 적군이 0번 패턴을 3번 사용.

*/

    Geok[num].x += mov_x[num]; // 이동값 만을 증가시켜 적의 모니터 출력 x좌표로 내용을 전달한다.
    Geok[num].y += mov_y[num]; // 이동값 만을 증가시켜 적의 모니터 출력 y좌표로 내용을 전달한다.

/*
// 위 내용을 아래와 같이 하면 출력 자체가 안됨.
   // ("이동3"값.)
    mov_x[num]   = GPATTERN[pattern_add][mov_pos2[num]]; // (번호 10번)에 적용됨. (+ 0와 같은 효과)
    mov_y[num]   = GPATTERN[pattern_add][mov_pos2[num]+1]; // 자체의 6에다가 y축이므로 +1을 했으니 (번호 11번)을 가리킨다.
*/

    // 적군의 등장 여부 (위치를 이쪽으로 이동시켰음) 
    if (end_x[num] < 0 && Geok[num].x <= end_x[num]) // 각 적군이 모니터 밖으로 나가는 경우.
	{
	  Geok[num].geok_show = 0; // 적군을 모니터에 등장시키지 않게한다.
	  return 0;
	}
    else
    if (end_x[num] > 0 && Geok[num].x > end_x[num]) // 각 적군이 모니터 안에 있을 경우?.
	{
	  Geok[num].geok_show = 0; // 역시 모니터에 적군을 등장시키지 않는다.
	  return 0;
	}

	if (GEOK_TABLE[num][1] <= 3)
   {
  // 기본 사항이다 (위 과정을 거친 다음 적군 출력.) 이 위치가 적당함. 
        // "3차 표면"의 크기를 rect에 넣는다.
        src_rect.left  = Geok[num].x_frame[Geok[num].start]; 
	src_rect.top  = Geok[num].y_frame[Geok[num].start];
	src_rect.right = Geok[num].x_frame[Geok[num].start] + Geok[num].width;
	src_rect.bottom = Geok[num].y_frame[Geok[num].start] + Geok[num].height;

        // 모니터의 크기를 rect에 넣는다.
	dest_rect.left    = Geok[num].x; 
	dest_rect.top     = Geok[num].y;
	dest_rect.right   = Geok[num].x + Geok[num].width;
	dest_rect.bottom  = Geok[num].y + Geok[num].height;

   lpSecondary->Blt(&dest_rect, lp_OffTwo, &src_rect, DDBLT_WAIT| DDBLT_KEYSRC, NULL); // 앞의 내용과 같음. 3차 표면의 크기를 모니터에 넣는다.
}
      else
      if (GEOK_TABLE[num][1] >= 4)
{
        // "3차 표면"의 크기를 rect에 넣는다.
        src_rect.left  = Geok[num].x_frame[Geok[num].start]; 
	src_rect.top  = Geok[num].y_frame[Geok[num].start];
	src_rect.right = Geok[num].x_frame[Geok[num].start] + Geok[num].width;
	src_rect.bottom = Geok[num].y_frame[Geok[num].start] + Geok[num].height;

        // 모니터의 크기를 rect에 넣는다.
	dest_rect.left    = Geok[num].x; 
	dest_rect.top     = Geok[num].y;
	dest_rect.right   = Geok[num].x + Geok[num].width;
	dest_rect.bottom  = Geok[num].y + Geok[num].height;

   lpSecondary->Blt(&dest_rect, lp_OffThree, &src_rect, DDBLT_WAIT| DDBLT_KEYSRC, NULL); // 앞의 내용과 같음. 3차 표면의 크기를 모니터에 넣는다.
}
   Geok[num].start++; // 앞과 같음. 적군의 다음 그림이 나오도록 계속 증가시켜 나감.
   }
  return 1;
}

int Geok_ChongAL_Appear(int num)
{
  RECT src_rect, dest_rect;
  int i;

  for (i=0; i < 3; i++) // 적군 총알은 3발.
   {
     if (Geok_ChongAL[num].geok_shoot[i]==1)  // 적군 총알 발사가 가능한 경우
       {
        if (GEOK_TABLE[num][1] <= 3)
         {
        // "3차 표면"에서의 rect 크기 설정
	src_rect.left   = Geok_ChongAL[num].x_frame; 
	src_rect.top    = Geok_ChongAL[num].y_frame;
	src_rect.right  = Geok_ChongAL[num].x_frame + Geok_ChongAL[num].width;
	src_rect.bottom = Geok_ChongAL[num].y_frame + Geok_ChongAL[num].height;

        // "모니터"에서의 rect 크기 설정.
	dest_rect.left   = Geok_ChongAL[num].x[i]; 
	dest_rect.top    = Geok_ChongAL[num].y[i];
	dest_rect.right  = Geok_ChongAL[num].x[i] + Geok_ChongAL[num].width;
	dest_rect.bottom = Geok_ChongAL[num].y[i] + Geok_ChongAL[num].height;

        lpSecondary->Blt(&dest_rect, lp_OffTwo, &src_rect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); // 방법은 모두 같다. 3차 표면에서 모니터로 rect 크기를 복사시킨다.
         }

//      else
      if (GEOK_TABLE[num][1] >= 4)
        {
        // "3차 표면"에서의 rect 크기 설정
	src_rect.left   = Geok_ChongAL[num].x_frame; 
	src_rect.top    = Geok_ChongAL[num].y_frame;
	src_rect.right  = Geok_ChongAL[num].x_frame + Geok_ChongAL[num].width;
	src_rect.bottom = Geok_ChongAL[num].y_frame + Geok_ChongAL[num].height;

        // "모니터"에서의 rect 크기 설정.
	dest_rect.left   = Geok_ChongAL[num].x[i]; 
	dest_rect.top    = Geok_ChongAL[num].y[i];
	dest_rect.right  = Geok_ChongAL[num].x[i] + Geok_ChongAL[num].width;
	dest_rect.bottom = Geok_ChongAL[num].y[i] + Geok_ChongAL[num].height;

        lpSecondary->Blt(&dest_rect, lp_OffThree, &src_rect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); // 방법은 모두 같다. 3차 표면에서 모니터로 rect 크기를 복사시킨다.
        }

        // 적군 총알 실제 발사 
        if (Geok_ChongAL[num].x[i] < 0 ) // 적군 총알이 x축 밖으로 나가면
           Geok_ChongAL[num].geok_shoot[i] = 0; // 총알 발사는 무효화시키고
	else // 적군 총알이 화면 안쪽에 있다면 
	   Geok_ChongAL[num].x[i] -= 30; // 30 픽셀 속도로 적군 총알이 발사된다.
      }
   }
 return 1;
}

void Collide(int num) // 3가지 상황의 충돌이 있다. num는 적군 33명의 의미.
{
  int i, result; // i는 총알수. result는 결과값 따지기용 변수.

  if (Geok[num].geok_show==1) // 적군이 나오는 상황에서
    {
     // ① 아군과 적군의 충돌
     result = Collide_range(
Akun.x, 
Akun.x + Akun.width-1, 

Akun.y, 
Akun.y + Akun.height-1, 

Geok[num].x, 
Geok[num].x + Geok[num].width-1,

Geok[num].y, 
Geok[num].y + Geok[num].height-1
);

// 이 Collide_range 함수는 아군과 적군을 나타내는 사각형의 좌표를 여기서 불러들인다. 그래서 모두 8개의 인자가 된다. (뒤에 설명됨) 충돌 결과를 result로 전달해 두었다가 

/* 위 개념을 재정리하자면 "아군과 적군의 몸통 충돌"인데....
Akun.x,                                1
Akun.x + Akun.width // 아군 넓이      2

Akun.y,                                3
Akun.y + Akun.height // 아군 높이      4

Geok.x,                                 5
Geok.x + Geok.width // 적군 넓이        6

Geok.y,                                 7
Geok.y + Geok.height // 적군 높이       8 

설명을 하자면.....
Akun.x + Akun.width > Geok.x && Geok.x + Geok.width > Akun.x
(해석 : 아군 넓이가 적 위치보다 오른쪽에 있고, 적군 넓이가 아군 위치보다 오른쪽에 있다면(?))

Akun.y + Akun.height > Geok.y && Geok.y + Geok.height > Akun.y
(해석 : 아군 높이가 적 위치보다 아래쪽에 있고, 적군 높이가 아군 위치보다 아래쪽에 있다면(?))

위 4가지를 모두 만족시킬 경우에 충돌됨.

int Collide_range(int ax1, int ax2, int ay1, int ay2, int bx1, int bx2, int by1, int by2)
                     1       2       3       4       5       6       7       8 
                 
  if (ax2 > bx1 && bx2 > ax1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 x축.
  if (ay2 > by1 && by2 > ay1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 y축.
*/

        if (result==1) // 그 반환된 결과가 1이 되면 
	  {   
	    Akun.akun_die = 1; // 아군이 폭발은 가능(1) 하게 되며
            Pokbal.agun_explode = 0; // 아군의 폭발 그림은 초기화시킨다.(0)

            Geok[num].geok_die = 1; // 적군의 폭발도 가능(1)하게 되며
            Pokbal.geok_explode[num] = 0; // 적군의 폭발 그림도 초기화시킨다. (0)
          }
     }

	// ② 아군 총알과 적군의 충돌
     for (i=0; i < 9; i++) // 아군 총알 9발
      {
        if (Geok[num].geok_show==1) // 적군의 등장이 가능한 상태에서 (1)
	  {
	    if (Akun_ChongAL.akun_shoot[i]==1) // 또한 아군 총알 등장도(1) 가능한 상태에서
	      {
	       result = Collide_range(Akun_ChongAL.x[i], Akun_ChongAL.x[i] + Akun_ChongAL.width-1, Akun_ChongAL.y[i], Akun_ChongAL.y[i] + Akun_ChongAL.height-1, Geok[num].x, Geok[num].x + Geok[num].width-1, Geok[num].y, Geok[num].y +Geok[num].height-1);
                 // 앞의 경우와 같다. 다만, 비교 대상이 아군 총알(9개)이라는 점이 다를 뿐. 

/* 위 개념을 재정리하자면 "아군 총알이 적군을 맞출 때"인데....
Akun_ChongAL.x,                                             1
Akun_ChongAL.x + Akun_ChongAL.width // 아군 총알 넓이    2

Akun_ChongAL.y                                             3
Akun_ChongAL.y + Akun_ChongAL.height // 아군 총알 높이    4

Geok.x,                                                      5
Geok.x + Geok.width // 적군 넓이                             6

Geok.y,                                                      7
Geok.y +Geok.height // 적군 높이                             8

설명을 하자면.....
Akun_ChongAL.x + Akun_ChongAL.width > Geok.x && Geok.x + Geok.width > Akun_ChongAL.x
(해석 : 아군 총알 넓이가 적 위치보다 오른쪽에 있고, 적군 넓이가 아군 총알보다 오른쪽에 있다면(?)

Akun_ChongAL.y + Akun_ChongAL.height > Geok.y && Geok.y +Geok.height > Akun_ChongAL.y
(해석 : 아군 총알 높이가 적 위치보다 아래쪽에 있고, 적군 높이가 아군 총알 위치보다 아래쪽에 있다면(?))

위 4가지를 모두 만족시킬 경우에 충돌됨.

int Collide_range(int ax1, int ax2, int ay1, int ay2, int bx1, int bx2, int by1, int by2)
                     1       2       3       4       5       6       7       8 
                 
  if (ax2 > bx1 && bx2 > ax1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 x축.
  if (ay2 > by1 && by2 > ay1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 y축.
*/

              if (result==1) // 반환값이 1의 경우라면 즉, 충돌이 되면
                 {
                  Geok[num].geok_die = 1; // 적의 폭발이 유효(1)하게 되며
                  Pokbal.geok_explode[num] = 0; // 폭발 그림은 다시 초기화되고 
                  Akun_ChongAL.akun_shoot[i] = 0; // 아군 총알은 (다 쏘고 난 후) 발사가 중지(0)
                 }
              }
           }
       }

	// ③ 적군 총알과 아군의 충돌 
	for (i=0; i < 3; i++) 
	{
	   if (Geok_ChongAL[num].geok_shoot[i]==1) // 적군 총알 발사가 가능한 (1) 상태에서
	     {
	 result = Collide_range(Geok_ChongAL[num].x[i], Geok_ChongAL[num].x[i]+ Geok_ChongAL[num].width-1, Geok_ChongAL[num].y[i], Geok_ChongAL[num].y[i] + Geok_ChongAL[num].height-1, Akun.x, Akun.x + Akun.width-1, Akun.y, Akun.y + Akun.height-1);
              // 앞 내용과 같다. 다만, 적군 총알의 경우는 적군 33명과 적 총알 3발에 대한 배열 표현

/* 위 개념을 재정리하자면 "적군 총알이 아군을 맞출 때"인데....
Geok_ChongAL.x,                                         1          
Geok_ChongAL.x]+ Geok_ChongAL.width  적군 총알 넓이   2

Geok_ChongAL.y,                                         3
Geok_ChongAL.y + Geok_ChongAL.height 적군 총알 높이   4

Akun.x,                                                   5
Akun.x + Akun.width   아군 넓이                         6

Akun.y,                                                   7
Akun.y + Akun.height 아군 높이                           8

설명을 하자면.....


Geok_ChongAL.x]+ Geok_ChongAL.width > Akun.x && Akun.x + Akun.width > Geok_ChongAL.x
(해석 : 적군 총알 넓이가 아군 위치보다 오른쪽에 있고, 아군 넓이가 적 총알보다 오른쪽에 있다면(?)

Geok_ChongAL.y + Geok_ChongAL.height > Akun.y && Geok_ChongAL.y + Geok_ChongAL.height > Geok_ChongAL.y
(해석 : 적군 총알 높이가 아군 위치보다 아래쪽에 있고, 적군 총알 높이가 아군 위치보다 아래쪽에 있다면(?))

위 4가지를 모두 만족시킬 경우에 충돌됨.

int Collide_range(int ax1, int ax2, int ay1, int ay2, int bx1, int bx2, int by1, int by2)
                     1       2       3       4       5       6       7       8 
                 
  if (ax2 > bx1 && bx2 > ax1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 x축.
  if (ay2 > by1 && by2 > ay1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 y축.
*/

			if (result==1) // 전달받은 결과가 1이면
			{
	                 Akun.akun_die = 1; // 아군의 폭발이 가능(1)하게 되며
                         Pokbal.agun_explode = 0; // 아군 그림은 초기값 즉, 첫 그림으로 나타나고
                         Geok_ChongAL[num].geok_shoot[i] = 0; // 발사 후 적군 총알은 발사가 중지. (0)
			}
	     }
       }
}

// 사각형 충돌 체크 
int Collide_range(int ax1, int ax2, int ay1, int ay2,int bx1, int bx2, int by1, int by2)
{
  if (ax2 > bx1 && bx2 > ax1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 x축.
  if (ay2 > by1 && by2 > ay1) // 아군과 적군의 - 좌표를 통해 - 사각형 충돌 체크 y축.
    return 1; // 충돌이 되면(1)   
    return 0; // 충돌이 안되면(0)  
}

long FAR PASCAL WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:            
            CleanUp();
            PostQuitMessage(0);
            return 0;

        case WM_KEYDOWN:            
            switch (wParam)
            {
              case VK_ESCAPE: 
                   PostMessage(hwnd, WM_CLOSE, 0, 0);
                   return 0;            
            }
            break;
            // 과거 아군 이동은 여기서 처리했으나 총알 연속 출력은 이 "메시지"에서의 동작은 느리므로 독립적인 함수를 사용하게 되었다.

        case WM_SETCURSOR:          
            SetCursor(NULL);     
            return 1;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

static void CleanUp(void)
{ 
   SafeRelease(lpPrimary); // 2차 객체는 1차 객체에 연결되어 있으므로 1차만 지우면 됨.
   SafeRelease(lp_OffOne);
   SafeRelease(lp_OffTwo);
   SafeRelease(lp_OffThree);
   SafeRelease(lpDD);
} 
// 끝

