Android에서 손가락보다 작은 대상물의 터치 판정을하는 방법

Android 게임에서는 자신의 손가락보다 작은 대상의 터치가 어렵다.



AndEngine에는 기본적으로 터치 판정 기능이 탑재되어 있습니다만, 16x16 사이즈의 작은 대상에 터치 판정 처리를 실장하려고 했는데 잘 판정할 수 없었습니다.
그 때문에, 작은 대상의 터치 조작을 실시하는 경우는 자력으로 터치 판정을 실장할 필요가 있습니다.
일반적인 터치 판정은 다음과 같습니다.
private boolean isTouch(Rect rect , int x , int y)
{
    if(rect.left < x  && x <rect.right && rect.top < y && y < rect.bottom)
    {
        return true;
    }
    else
    {
        return false;
    }
}

데스크탑 PC에서는 마우스 커서를 사용해 세세한 클릭 위치를 지정할 수 있으므로 문제 없습니다.
하지만 android 단말기처럼 손가락을 사용하여 대상을 터치하는 경우 마우스만큼 세세한 위치 지정을 할 수 없습니다.
아래와 같이 탭 대상이 손가락보다 큰 경우에는 이 방법으로도 문제 없습니다.


아래와 같이 터치 대상이 손가락보다 작은 경우라면 터치 포인트가 잘 터치 대상의 범위 내에 들어가지 않고 터치 판정을 할 수 없습니다.


작은 대상을 데리러 가면서 안이하게 터치 범위를 넓히면, 이하와 같이 터치 대상이 복수로 늘어났을 경우의 오검지가 많아져 버립니다.


해결 방법



터치 포인트와 터치 대상과의 거리를 바탕으로 터치 판정을 하는 방법을 사용합니다.
final int DISTANCE_TOUCH=32;


private boolean isTouch(Rect rect , int x , int y)
{
    //タッチポイント(x,y)とタッチ対象の中心点(rect.centerX(),rect.centerY())との距離(distance)を取得
    double distance =
Math.sqrt( Math.pow(x-rect.centerX(),2) + Math.pow(y-rect.centerY(),2) );

    //距離(distance)がDISTANCE_TOUCHよりも小さければタッチ認定
    if(distance <= DISTANCE_TOUCH)
    {
        return true;
    }
    else
    {
        return false;
    }
}



위의 코드에서는 터치 포인트와의 거리가 32 이내이면 그 대상을 터치한 것으로 간주합니다.
이 DISTANCE_TOUCH의 값을 늘리면 터치 범위를 넓힐 수 있습니다.
거리라고 하는 단일의 값을 사용해 터치 판정을 실시하고 있으므로, 복수의 터치 대상이 근처에 있는 경우에, 어느 것이 가장 가까운 거리에 있는지를 간단하게 비교할 수 있습니다.
이렇게하면 작은 터치 대상을 선택하기 위해 터치 범위를 넓혔습니다 (DISTANCE_TOUCH의 값을 48로 변경). 오탐지를 방지할 수 있습니다.

다음은 Rect의 배열 rects 중에서 터치 포인트와 가장 가까운 위치에 있는 대상을 찾는 예입니다.
int min = 100000;
int select = -1;

final int length=rects.length;
for(int i = 0 ; i < length ; i++)
{
    //タッチ範囲外の場合は次のループへ
    if( isTouch(rects[i],x,y) == false )
    {
        continue;
    }

    //タッチポイントとタッチ対象の中心点との距離を取得
    double distance =
Math.sqrt( Math.pow(x-rects[i].centerX(),2) + Math.pow(y-rects[i].centerY(),2) );

    //距離がこれまでのタッチ対象の最小距離(min)より小さければタッチ認定
    if(min > distance )
    {
        min = distance ;
        select = i;
    }

}

if(select != -1)
{
    //タッチ対象rects[select]をタッチした時の処理
}

기타 접근법



가장 가까운 위치에 있는 대상을 찾는 것이 아니라 RANGE_TOUCH의 범위 내에 있는 경우 처음 발견한 것을 터치한 것으로 간주하는 방법도 있습니다.
final int length=rects.length;
for(int i = 0 ; i < length ; i++)
{
    if( isTouch(rects[i],x,y) == true )
    {
        select = i;
        break;
    }
}

if(select != -1)
{
    //タッチ対象rects[select]をタッチした時の処理
}

방금 전의 방법보다 정밀도는 떨어집니다만, 최소값을 구하기 위한 변수나 조건식을 줄였기 때문에 코드가 깔끔하고, for 루프를 끝까지 돌리지 않기 때문에 조금입니다만 처리도 빨리 끝납니다.
터치 대상이 그렇게 밀집되어 있지 않은 경우는 이쪽이 좋을지도 모릅니다.

내 경우에는 다음과 같은 작은 물체가 대량으로 돌아다니는 앱



대상물이 떨어져 있고 위치 고정의 경우 은 간단한 후자의 방법을 사용하고 있습니다.


참고로 한 페이지
AndEngine Tutorials
위의 일본어 번역 사이트 (비공식)

기사내의 화상에는 이하 사이트의 소재를 사용하고 있습니다.
소재Good

좋은 웹페이지 즐겨찾기