티스토리 뷰

- Tile based games (http://www.tonypa.pri.ee/tbw/start.html)
위 튜토리얼을 기본으로 하여 Android에 사용될 수 있게끔 공부한 포스트 입니다.




버전관리를 꾸준히 모니터링 하시는 분이시라면 요번에 이놈의 멀티터치에 골머리좀 썩었다는 사실을 알것이다. 정말이지 머리가 돌인거 같았는데 다행히도 잘 마무리 질 수 있었다.

물론 소스는 지저분해졌지만 소스의 최적화는 슬슬 해가기로 하고 이번에 해결한 사항에 대해 정리를 해보는 시간을 가져보도록 하겠다.

참고로 이전소스와의 비교는 없다. 

1. 이론


가) 모션 이벤트(Motion Event) 동작 처리
안드로이드 자체에서는 멀티 터치 포인터를 모션 이벤트를 통해 얻을 수 있다. 이것을 이용하면 이벤트 처리가 용이하다. 현재 확인한 사항으로는 총 4개의 터치점을 읽어 올 수 있다.

터치 동작은 다음 3가지로 나눌 수 있다.

ACTION_DOWN : 손으로 스크린 터치
ACTION_MOVE : 스크린 터치 후 이동
ACTION_UP : 스크린에서 손을 땜

또한 터치시 입력되는 점을 각각 POINTER_1,2,3으로 지정하고 있으므로 이벤트가 들어올때를 각각 처리해주면 된다.

나) 터치 포인터 ID
각각 멀티 터치 이벤트가 들어왔을 때 처리 방법에 대해서 알아보았다면 이제 지금 들어온 터치점이 어떠한 건지를 알아야 한다. 딸리는 영어와 씨름하면서 이것저것 테스트 해본 결과 이 포인터 ID를 알아내면 되는 간단한 것이었다.

이 포인터 ID는 우리가 이벤트로 들어오는 경우를 보다 확실하게 보장 해준다.
이를 이용하면 현재 버튼에 어떠한 이벤트 ID가 들어왔는지를 체크하여 이벤트를 처리 해 줄수 있다.

다) 예제 소스
void printSamples(MotionEvent ev) { 
     final int historySize = ev.getHistorySize(); 
     final int pointerCount = ev.getPointerCount(); 
     for (int h = 0; h < historySize; h++) { 
         System.out.printf("At time %d:", ev.getHistoricalEventTime(h)); 
         for (int p = 0; p < pointerCount; p++) { 
             System.out.printf("  pointer %d: (%f,%f)", 
                 ev.getPointerId(p), ev.getHistoricalX(p, h), ev.getHistoricalY(p, h)); 
         } 
     } 
     System.out.printf("At time %d:", ev.getEventTime()); 
     for (int p = 0; p < pointerCount; p++) { 
         System.out.printf("  pointer %d: (%f,%f)", 
             ev.getPointerId(p), ev.getX(p), ev.getY(p)); 
    } 
} 

이는 안드로이드 레퍼런스에서 제공해주는 기본 예제인데 이를 이용하면 이벤트에 대한 조그마한 감을 잡을 수 있다.

2. 소스


 정말 오래 걸리긴 했지만 정작 중요한 포인트는 딱 두부분이다.
public boolean onTouchListener(MotionEvent e) {
		
	boolean bIsBounding = false;
		
	final int KeyAction = e.getAction();
	final int pointerCount = e.getPointerCount();
		
	int x = 0;
	int y = 0;
	int p = 0;
		
	for (p = 0; p < pointerCount; p++) {
			
		x = (int)e.getX(p);
		y = (int)e.getY(p);
			
		if(isBounding(x,y)) {
			bIsBounding = true;
			mPointerID = e.getPointerId(p);
		}
	}
		
	if(bIsBounding) {
		PointerAction(mPointerID, KeyAction);
		return true;
	}else {
		setState(Box_State.STATE_UP);
		return false;
	}
}

터치 리스너에서 MotionEvent를 받아 안드로이드 예제 소스를 참고하여 Pointer ID를 얻어낸다. 이때 Pointer ID는 현재 체크하고 있는 버튼이 눌린 경우에만 이를 할당해준다. 이렇게 함으로써 현재 눌리고 있는 컴포넌트를 체크 할 수 있게 된다.

 
private void PointerAction(int pointerID, int KeyAction) {
		
	if(pointerID == 0) {
		
		switch(KeyAction) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_POINTER_1_DOWN:
			setState(Box_State.STATE_DOWN);
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_1_UP:
			setState(Box_State.STATE_UP);
			break;
		case MotionEvent.ACTION_MOVE:
			setState(Box_State.STATE_DOWN);
			break;
		}
			
	}else if(pointerID == 1) {
			
		switch(KeyAction) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_POINTER_2_DOWN:
			setState(Box_State.STATE_DOWN);
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_2_UP:
			setState(Box_State.STATE_UP);
			break;
		case MotionEvent.ACTION_MOVE:
			setState(Box_State.STATE_DOWN);
			break;
		}
		
	}
		
}

이 메소드를 만들면서 많이 고민을 했는데 일단 다른 뾰족한 방법이 생각안나서 일단 이렇게 처리해두었다. PointerID가 들어온 경우를 체크하여 해당 이벤트를 처리해주고 있다.

여기서 자세히 살펴볼점은 ACTION_DOWN, ACTION_UP, ACTION_MOVE는 공통적으로 두 부분에 다 들어있다는 점이다. PointerID가 0일지 1일지는 모르지만 터치 점이 1일때에는 무조건 공통적으로 이벤트가 날라가기 때문이다. 이것을 체크해주지 않아서 좀 고생이 많았다.

오늘은 이것으로 끝~ 
댓글
댓글쓰기 폼