본문 바로가기

무언가 만들기 위한 지식/ARM Processor

Application_PuzzleGame on Embedded Board


시스템 관련 프로그래밍은 워낙 Visual 하지 않은지라 결과를 한눈에 볼 수도 없고, 은근히 답답하고 지루하다.
그래서 전에 사용하던 실습보드를 이용하여 하나의 간단한 Application을 만들어 보았다.
(그런데 또 그렇게 생각보다 간단하지 만은 않다^_^)
돌아가는 기반은 이전에 System Call을 기반하여 함수들의 동작을 확인하기 위한 목적이었다.

이름하여 퍼즐 맞추기 게임! 두둥
Application은 노가다의 연장선이라는 말을 절실히 느낀 게임이었다. -.,-; 

i. 개발동기 및 개요

교육용 보드인 WT-2440L에는 4선 저항식 터치패널이 장착되어 LCD에 터치(Touch) 순간(Pressed)의 좌표와 LCD에서 손을 떼는 순간(Released)의 좌표를, 인터럽트(Interrupt) 이용하여 그 좌표를 알아낼 수 있었다. 이에 이를 응용하여 Drag&Drop을 구현하였고, 더불어 이 기술을 적용할 수 있는 게임을 만들기로 결심하였다.

그리하여 퍼즐 맞추기 게임을 만들기로 하였는 바,

바닥에 흐트러져 있는 조각들을 손으로 실제 옮기는 것처럼, 게임상에서 원하는 조각을 LCD 터치패널에 1)클릭하고, 2)클릭한 채로 끌어당기고, 3)원하는 위치에서 손을 놓음으로서 조각의 이동을 구현하였다.

또한 그래픽 적인 요소에서 스크린상 이동하는 조각들의 움직임을 최대한 부드럽게 하기 위하여 이중버퍼를 이용하여 부드러운 애니메이션(Animation)을 구현 하였고, 이동시 어떤 면을 더 상위에 출력할 것인지 고려하여 구현하였다.


전체적인 게임상의 흐름보다는 애니메이션의 구현, 또는 디바이스 드라이버상(Device Driver)의 사용할 함수 구현에 중점을 두어 프로그래밍을 진행하였다. 또한 각 과정에서 좀 더 정교한 LCD상의 움직임을 구현하기 위해서 보정작업과 여러 테스트를 병행 하였다. (대충 한 4~5일 정도 걸린 듯하다.)


 

ii. 프로그램 흐름도

      가) 게임 상태 변화도

 

게임이 시작되면 처음 Easy ModeHard Mode 둘 중에 한 가지를 선택할 수 있다. 이 때 둘 중의 하나의 모드가 선택되면 각 모드상에서 사용될 이미지를 선택할 수 있다. 이 두가지의 기본 설정을 마치고 나면 본격적인 게임이 시작된다.

그 후 게임을 클리어 하게 되면 다시 처음 Mode 선택단계로 이동하여 다른 게임을 즐길 수 있다.
Easy 또는 Hard 게임 진행동안에는 다른 루트로 빠져나갈 수 없으며, Clear해야 다른 모드로 이동할 수 있다.

 

      나) Main.c 코드 흐름

   void Main(void){

    while(1){

        if(Touch_x>=121&&Touch_x<=198&&Touch_y>=185&&Touch_y<=217) break;

        // 시작화면

    }

    while(1){ // Mode 선택부분

        if(Touch_x>=85&&Touch_x<=225&&Touch_y>=70&&Touch_y<=104){  // Easy Mode 선택

            while(1){ // 그림 선택 부분      

                if(Touch_x>=74&&Touch_x<=108&&Touch_y>=70&&Touch_y<=102) break;

                if(Touch_x>=215&&Touch_x<=250&&Touch_y>=68&&Touch_y<=104) break;

                if(Touch_x>=74&&Touch_x<=105&&Touch_y>=137&&Touch_y<=169) break;

                if(Touch_x>=218&&Touch_x<=253&&Touch_y>=142&&Touch_y<=173) break;

            }

            // Easy Mode Game Start 함수

        }

        if(Touch_x>=85&&Touch_x<=225&&Touch_y>=130&&Touch_y<=162){  // Hard Mode 선택

            while(1){ // 그림 선택 부분

                if(Touch_x>=74&&Touch_x<=108&&Touch_y>=70&&Touch_y<=102) break;}

                if(Touch_x>=215&&Touch_x<=250&&Touch_y>=68&&Touch_y<=104) break;}

                if(Touch_x>=74&&Touch_x<=105&&Touch_y>=137&&Touch_y<=169) break;}

                if(Touch_x>=218&&Touch_x<=253&&Touch_y>=142&&Touch_y<=173) break;}

          }

            // Hard Mode Game Start 함수                            

        }              

    }

}     


화면상에 뿌려준 버튼 영역의 정보를 if문에 넣어주어 클릭여부를 확인한 후, 해당 코드로 들어 가게 됨.
(
Touch_x, Touch_y는 터치패널에서 인터럽트 발생시 값을 변경해 줌, extern으로 선언되어 있음)


ⅲ. 게임 동작원리 및 코드설명
      가) Puzzle 조각 관리 게임 내에서는 기본적으로 하단부에 여러 개수의 사각형들이 존재하고, 상단부에는 정답을 맞추는 큰 틀이 존재한다. 플레이어는 하단부에서 사각형을 끌어당겨서, 상단부에는 사각형틀에 모양을 맞추게 된다이 때, 만약 움직이는 사각형이 상단부의 사각형 내부에 존재한다면, 답으로 간주하고 상단부에 그림이 그려지게 된다. 만약 일치하는 정답이 아니라면, 애니메이션 동작에 의하여 원래 위치한 자리로 부드럽게 이동하게 된다.  이 부분을 구현하기 위해서는 두 개의 배열이 사용된다. 두 개의 배열은 상단부와 하단부의 배열을 의미하는데 각 배열의 값들은 다음의 구조체로 이루어져 있다.

 

   typedef struct{

      int x;

      int y;

      int moveOn; //이동중 or 정지, 1이명 이동중, 0이면 정지

      const unsigned short * imgP;

} IMGSTRUCT;

IMGSTRUCT imgUnderBarAry[4];

IMGSTRUCT imgBackGroundAry[4];

IMGSTRUCT imgUBA_Hard[9];

IMGSTRUCT imgBGA_Hard[9];


구조체에서는 그림이 위치하는 중심점의 좌표값
(x,y)와 현재 Drag & Drop으로 이동중임을 확인할 수 있는 moveOn 변수, 또한 뿌려줄 BMP파일(배열상으로 존재함)에 대한 포인터 값이 존재한다. 코드상에서는 총 4개의 배열이 미리 선언되어 있는데 Index가 4인 배열은 Easy Mode로 4칸짜리 배열인 상단부, 하단부 2개가 존재하고, Index가 9인 배열은 Hard Mode 9칸짜리 배열이 존재한다. 다른 함수에서도 접근이 가능하도록 main함수의 외부에서 선언하였다.

      나) 사용되는 BMP파일 관리

소스 내에서 bmp파일은 const unsigned short 타입의 배열로 구성되어 있다. 각 조각들은 이 배열에 대한 포인터를 지니고 있어 언제나 뿌려줄 정보를 가지고 있다. 이 때 조각들이 많아지고, 매번 다른 이미지로 바꿔가며 게임을 하게 될 때 소스가 길어지거나 관리가 힘들 수도 있다.

이를 해결하기 위해서는 배열에 배열의 주소값을 넣는 방식을 이용하였으며 한번의 초기화로 하단부 및 상단부의 조각관리배열에 들어가는 bmp정보를 바꿀 수 있도록 구성하였다.

   const unsigned short *easyImgAry[4]={easy_1, .... ,easy_4};

const unsigned short *easyImgAry1[4]={easy_1_1, .... ,easy_1_4};

const unsigned short *easyImgAry2[4]={easy_2_1, .... ,easy_2_4};

const unsigned short *easyImgAry3[4]={easy_3_1, .... ,easy_3_4};

const unsigned short *hardImgAry[9]={hard_1, .... ,hard_9};

const unsigned short *hardImgAry1[9]={hard_1_1, .... ,hard_1_9};

const unsigned short *hardImgAry2[9]={hard_2_1, .... ,hard_2_9};

const unsigned short *hardImgAry3[9]={hard_3_1, .... ,hard_3_9};

const unsigned short **easyImgSet[4]={easyImgAry,easyImgAry1,easyImgAry2,easyImgAry3};

const unsigned short **hardImgSet[4]={hardImgAry,hardImgAry1,hardImgAry2,hardImgAry3};


for(i=0;i<4;i++){ 

      ary1[i].imgP=easyImgSet[usedImg][i];

}

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

      ary1[i].imgP=hardImgSet[usedImg][i];

}


먼저 각 조각들의 bmp 배열의 주소(배열명, 엄밀히 배열 첫 번째 요소 값)를 하나의 배열에 담는다. 이때의 담는 배열에는 조각들이 완성되었을때의 모든 순차적으로 입력된 조각의 정보가 담겨있다. 즉 각 조각들이 하나로 뭉쳐있는 것이다.

그리고 이 뭉쳐진 조각들의 배열을 다시 Mode별로 두 개의 배열로 나누어 담는다. 위에서 easyImgSet 배열은 easy Mode에서 사용되는 모든 배열(BMP 배열의 집합)의 정보를 가지고 있다. 또한 hardImgSet 배열은 hard Mode에서 사용되는 모든 배열(BMP 배열의 집합)의 정보를 가지고 있다.

하단부의 for문은 이렇게 중첩으로 사용된 포인터가 사용되는 모습이다. usedImg 변수는 함수에서 인자로 들어오는 값으로 몇 번 그림을 사용하는지 판단하는 변수이다. 들어오는 값에 따라서 Index상의 배열주소를 가져오고 다시 for문상의 제어변수로 값을 불러와 현재 배열에 값을 저장한다. for 문상의 코드대로 수행하면 각 조각들이 순서대로 하단부 조각관리 배열에 보관되게 된다.


       다) Puzzle 조각 이동구현(Drag & Drop)  


조각의 이동 원리는 기본적으로 Drag&Drop을 통해 수행된다. 손으로 LCD 패널을 누르는 행동을 Pressed라고 하며, LCD 패널에서 손을 떼는 행동을 Released라고 하자. Pressed의 동작은 irq 인터럽트에 의하여 발생한다. irq 해당 인터럽트가 발생하면, 현재 터치한 좌표값을 Touch_xTouch_y를 통해 전달해주고 Touch_pressed를 통해 눌렸는지 아닌지 현재 상태를 알려준다.(외부에 선언된 변수이다.) 만약 눌린상태이고, 손을 떼지 않는 다면 특정 루프상태에서 무한루프를 돌면 손을 떼는 순간 다시 인터럽트가 발생하여 루트에서 빠져나온다.

위 도표는 이 과정에서 터치를 하고 손을 떼는 순간 바로 직전의 루프이다.

표에서처럼 눌린 상태에서 손을 떼지 않았다면, 이전에 그린 그림을 지우고, 다시 그리는 과정을 반복한다.

   do{

      for(;;){

              if(Touch_pressed == 1) break;

      }

      for(;;){

       getTouchLocationI();

        //수동으로 현재 클릭되고 있는 부분의 좌표를 읽어 들임. (Polling 방식이용)

        //Drag & Drop 수행 부분. (이 부분에서 계속 지우고 그리기를 반복한다.)

                if(Touch_pressed == 0) break; 

      }

}while(1);


 C 코드 상에는 위부분이 PressedReleased를 수행하는 부분이다. 이 루프상에서 프로그램이 돌게 되고, 각 위치에 있는 함수에 의하여 해당 동작이 수행된다.

getTouchLocation함수는 수동으로 폴링방식으로 현재 위치한 값을 읽어오는 방식이다. Touch_pressed==1인 상태에서는 자동으로 인터럽트에 의에 현재 클릭한 위치를 얻어 올 수 없고, 오직 손을 떼었을 때의 정보만을 얻어올 수 있다. 그렇기 때문에 수동으로 현재 위치 값을 얻어오기 위해서는 deviceDriver내부 상태레지스터 값을 변경하여 값을 얻어오도록 수정해야 한다.


   extern volatile unsigned int ADC_x, ADC_y;

extern volatile int Touch_x, Touch_y;

extern volatile int Touch_pressed;

int getTouchLocation(){

                      rADCTSC=(1<<8)|(1<<7)|(1<<6)|(0<<5)|(1<<4)|(1<<3)|(1<<2)|(3);

                      rADCCON|=0x1;   

                      while(!(0x8000&rADCCON));  

                      ADC_x=(0x3ff&rADCDAT0);

                      ADC_y=(0x3ff&rADCDAT1);

                      if(Touch_Get_Output_Mode() == TOUCH_XY_MODE){

                              Touch_y=(ADC_y-YP)*(240-10)/(YM-YP)+5;

                              Touch_x=(ADC_x-XM)*(320-10)/(XP-XM)+5;

                              Touch_y=240-Touch_y;

                              if(Touch_x<0) Touch_x=0;

                              if(Touch_x>=320) Touch_x=320-1;

                              if(Touch_y<0) Touch_y=0;

                              if(Touch_y>=240) Touch_y=240-1;

                      }

                      else {

                              Touch_x = Touch_y = 0;

                      }         

                      rADCTSC=(1<<8)|(1<<7)|(1<<6)|(0<<5)|(1<<4)|(0<<3)|(0<<2)|(3);

                      return 0;

}                     


getTouchLocation함수는 물리적인 레지스터의 값을 변경하여 정보를 얻어온다.
 
 

      라) 부드러운 Puzzle 조각의 이동

실제로 구상한 방식으로 인터럽트에 의한 for문 제어를 통해 이동을 한다면, 이동모습 구현이 가능하기는 하지만 지나친 깜빡거리기 때문에 실제 모니터에서와 같이 이동시키는 부드러운 모습을 구현할 수 없었다.

퍼즐 조각이 이동한다는 개념자체가 실제로는 전체화면을 지우고 다시 그린다는 발상 이다. 이 경우 지우고 반복하는 과정에서 반응의 차이가 보일 수 있다. 그린다는 의미는 전체 보드의 해상도인 320x240의 각 픽셀을 각 값으로 다시 쓴다는 의미이다. 지운다는 의미도 각 픽셀값을 다시 일정한 색으로 쓴다는 의미이다. 즉 둘다 같은 동작으로 이러한 동작이 계속해서 반복된다면, 각 메모리 영역에 값을 넣고 출력되는 과정과 지우는 사이에 Term이 발생할 수 있다. 그러한 증상에 의하여 부드러운 움직임이 연출되는 것이 아니라 깜빡꺼림 현상이 발생되게 된다.

이 깜빡꺼림 현상은 크게 두가지 방법에 의하여 보정되었다. 첫 번째는 이중버퍼를 사용한 것이고 두 번째는 화면을 지울때 이전에 움직였던 부분만 지우는 것이다. 

- 이중버퍼(Double Buffering) :

 

이중버퍼란 말 그대로 화면상에서 두 개의 Buffer를 사용하여 화면에 출력하는 개념이다. 특히 애니메이션의 효과를 낼때 두 개의 버퍼를 사용하여 하나의 버퍼에서 출력하는 동안 다음에 출력될 내용을 입력받고, 입력 받은후 입력받았던 버퍼는 출력하고 그동안에는 이전에 출력했던 버퍼가 입력을 받는다. 이러한 동작이 서로 교대로 이루어져 이미지 출력시 깜빡꺼림 없이 출력이 가능하다. 또한 조각이 이동하거나 제자리로 돌아올때도 부드럽게 작동한다.

기본적으로 출력할 때 사용하는 Buffer는 0번 버퍼이고, 추가로 1번 버퍼가 사용된다.

제공되는 버퍼 관련 함수는 다음과 같다.
(보드 개발업체에서 제공하는 함수이다.-더블버퍼 사용하는 개념은 같다. 내부적으로 메모리 영역을 두개 잡아서 그려줌)


  Lcd_Select_Draw_Frame_Buffer(bufferNum);  ------- ①

  Lcd_Select_Display_Frame_Buffer(bufferNum); ------- ②


① 에 의해 버퍼가 선택된다. bufferNum에는 0과 1 둘 중에 하나로 사용되는데, 영역을 설정하는 경우 2개 이상의 버퍼도 사용이 가능하지만 시스템 상 무리가 갈 뿐만 아니라, 실제로 2개의 버퍼만 사용해도 충분이 부드럽고 자연스러운 동작 연출이 가능하다. ①을 사용후 그려주면 bufferNum에 해당하는 buffer상에 그림이 그려진다.

② 을 통해 그려놓았던 버퍼를 출력한다.

코드상에서는 ①, ②를 이용하여 교대로 for문 내에서 사용되게 된다.

 

   for(;;){

      //Using Frame Buffer_0

      Lcd_Select_Draw_Frame_Buffer(0);

      Lcd_Clr_Screen(WHITE);

      if(abs(Touch_x-picX)>1.5&&abs(Touch_y-picY)>1.5){       

             Lcd_Draw_BMP((Touch_x-(xtmp/2)), (Touch_y-(ytmp/2)),imgUBA_Hard[index].imgP);

      }

      else{

           Lcd_Draw_BMP((picX-(xtmp/2)), (picY-(ytmp/2)),imgUBA_Hard[index].imgP); 

      }                                               

      drawLineHard(); 

      drawIMG(1,imgBGA_Hard);

      drawIMG(1,imgUBA_Hard);                //배열에 입력된 자료 출력.                  

      Lcd_Select_Display_Frame_Buffer(0);                            

      getTouchLocation_SWI();//SWI-인터럽트에 의해 Touch_y와 Touch_x가 변한다.                  
     
if(Touch_pressed == 0){ //하드웨어 인터럽트에 의한 모드 변경 

           break;

      }

      //Using Frame Buffer_1

      Lcd_Select_Draw_Frame_Buffer(1);

      Lcd_Clr_Screen(WHITE);

      if(abs(Touch_x-picX)>1.5&&abs(Touch_y-picY)>1.5){       

           Lcd_Draw_BMP((Touch_x-(xtmp/2)), (Touch_y-(ytmp/2)),imgUBA_Hard[index].imgP);

            picX=Touch_x;

           picY=Touch_y; 

      }

      else{

           Lcd_Draw_BMP((picX-(xtmp/2)), (picY-(ytmp/2)),imgUBA_Hard[index].imgP);  

      }

      drawLineHard(); 

      drawIMG(1,imgBGA_Hard);

      drawIMG(1,imgUBA_Hard); //배열에 입력된 자료 출력.                              

      Lcd_Select_Display_Frame_Buffer(1);            

      }

}while(1);


 

위 소스는 2개의 버퍼를 이용하여 교대로 읽어 들이고, 뿌리는 부분이다.

개념만 알고 있다면 쉽게 사용할 수 있으나, 실제 코딩시 ①, ②의 위치가 애매하여 여러 시도를 하였다. 뿌려줄때는 마지막에 반드시 이전 값을 저장해 놓는다. 위 코드에서는 picX와 picY라는 변수에 항상 그려준 후 해당 값을 저장하고 다음 코드로 넘어간다. 넘어간 위치에서는 이 picX, picY를 통해 그려주거나 지워주고 Released 발생시 그 값(이전값)을 이용하게 된다.

- 영역 지우기 :

   영역을 지울때 사용하는 함수

 

Lcd_Clr_Screen(color) ------- ①

Lcd_Draw_Bar(x1,y1,x2,y2,color); ------- ②


①을 사용하면 전체 화면을 color로 칠하게 된다. 즉 color를 배경색으로 하게되면 마치 지워지는 듯한 효과를 줄 수 있다. 코드에 있어서 인자가 없이 전체를 지우기 때문에 간결해서 코딩 초기에 많이 사용된다.

②는 (x1,x2)와 (y1,y2)사이의 사각형 공간을 color로 칠하는 것이다. 이를 사용하기 위해서는 인자를 정확히 입력해주어야 한다.

①을 사용한 후 배경 및 움직이는 대상을 다시 그려주는 방식도 가능하나 ②의 방식으로 지울 영역만 지우면 코드는 조금 복잡해지지만 훨씬 나아진 효과를 볼 수 있다. 비교적 작은 부분이 움직이는 것을 구현할 때는 이 방식을 사용하면 이동하는 물체를 효과적으로 표현이 가능하다.

      마) 물체의 특정 좌표로의 이동

클릭 후 드래그(Drag)하여 잘못된 영역에서 드랍(Drop)을 하였을 경우 제자리로 움직이는 모션(Motion)을 주기로 하였다. 이 때 인자로는 Moving이 될 대상의 구조체, 그리고 움직일 위치로의 좌표가 필요하다.

물체를 이동하는 과정의 애니메이션은 “라)부드러운 Puzzle 조각 이동”에서처럼 이중버퍼를 이용하여 해결하였지만 현재 좌표에서 특정좌표로 이동하기 위해서는 이동공식이 필요하다.

같은 속도가 아닌 감속도에 의해 물체가 이동할 때 사용되는 공식은 다음과 같다.


startX+=(destination.x-startX)*0.5;


startX는 시작 위치이며, destination.x는 목적지의 좌표값이다.

위의 식은 startX=startX+(destination.x-startX)*0.5; 로 해석된다.

식에 의하면 startX는 시작위치로 그 위치값이 점점 destination에 가까워진다. 0.5라는 상수가 감속 가속도를 판단하는데 이 상수는 0<speed<1 사이의 값을 갖을 수 있다. startX변수는 destination에 매우 근접해지지만 일치하지는 않는다. 해당 cpu 또는 fpu가 해당하는 지점까지 부동소수점 연산이 계속 수행될 것이다. 그렇기 때문에


if((abs(startX-destination.x)<10)&&(abs(startY-destination.y)<10)) break;


위와 같이 종료조건을 절대값을 이용하여 특정 값 이하라면 종료하도록 조건을 주어야 한다. 단, 특정 범위내에 종료한다면 최종적으로 이동을 멈춘 값을 지우고 목적지의 영역을 그려주어야 이동이 완료된 것처럼 나타난다.


아래의 movePositionToPosition()함수는 목적지와 현재 위치 움직일 대상의 정보가 들어있는 구조체를 인자로 받는다. 이중 버퍼와 특정 공식을 사용하여 부드러운 움직임으로 특정 좌표로 이동하여 그 공간에 뿌려지게 된다.

 

   void movePositionToPosition(int mode,int startX,int startY,IMGSTRUCT destination,){

      int beforeX,beforeY, startbeforeX=0,startbeforeY=0,beforebeforeX=0,beforebeforeY=0;

      while(1){ 

          beforeX=startX;

          beforeY=startY;         

          startX+=(destination.x-startX)*0.5;

          startY+=(destination.y-startY)*0.5;

          Lcd_Select_Draw_Frame_Buffer(0);

          if(beforebeforeX>0&&beforebeforeY>0){

              Lcd_Draw_Bar((beforebeforeX,Y Area Delete),WHITE);                         

          }

          Lcd_Draw_BMP((beforeX-(xtmp/2)),(beforeY-(ytmp/2)),destination.imgP);

          drawIMG(mode,backAry);

          if(mode==0)drawLine();           

           else drawLineHard();

          beforebeforeX=beforeX;

          beforebeforeY=beforeY;

          drawIMG(mode,underAry);                 

          Lcd_Select_Display_Frame_Buffer(0);                                 

          Lcd_Select_Draw_Frame_Buffer(1);

          if(startbeforeX>0&&startbeforeY>0){                                  

              Lcd_Draw_Bar((startbeforeX,Y Area Delete,WHITE);                  

          }                                    

          Lcd_Draw_BMP((startX-(xtmp/2)),(startY-(ytmp/2)),destination.imgP);         

          drawIMG(mode,backAry);                         

          if(mode==0)drawLine();           

          else drawLineHard();             

          startbeforeX=startX;

          startbeforeY=startY;

          drawIMG(mode,underAry); 

          Lcd_Select_Display_Frame_Buffer(1);                         

          if((abs(startX-destination.x)<10)&&(abs(startY-destination.y)<10)) break;     

      }

}     


      바) 그 외 사용된 함수 목록(게임구현시 필요에 의한 작성)

void initAryMode(int usedImg, IMGSTRUCT *ary1, IMGSTRUCT *ary2)

- 게임에 사용되는 상단과 하단부의 조각 관리 배열을 초기화 한다. 이부분에서 게임에 사용되는 이미지 정보 및 초기 좌표값들이 내부적인 for문에 의해 설정됨.

int checkIndex(int mode, IMGSTRUCT *ary)

- 만약 터치가 그림 안에 있다면 배열의 Index를 return, 그렇지 않다면 -1 return함. ary는 체크할 대상이다.

void drawLine()

- 배경 라인을 그려준다.

int checkGameEnd(int mode,IMGSTRUCT *ary)

- 현재 게임상태를 확인한다. (상위 배열에 조각들의 정보들이 다 모여있으면 게임이 끝난 것으로 간주한다.)

void GameDo(int imgIndex)

- hard 또는 easy 게임 둘중에 하나를 시작한다. imgIndex는 게임에 사용되는 이미지의 index번호이다.



어플리케이션을 돌려본 화면, 감압식 방식의 LCD 패널이다. 손으로 해도 잘 돌아가나,
펜으로 할 경우 정확한 포지션을 얻어올 수 있다. 살짝 값이 싼 부품임, 이는 손으로 눌렀을 경우 떨리지 않도록 보정을 해주어야 한다.



<다행히 찍어 두었던 테스트 영상, 원래는 어플리케이션이 아니라 SystemCall이 주 구현대상이라 좀 허접하다.>