Windows Phone 7용 게임 개발의 터치 조작 4부 핀치

페이지 업데이트 :
페이지 생성 날짜 :

프로그래밍! - 4.핀치, 스케일 스프라이트에 맞게 늘이기

이 샘플 정보

이미지 뷰어와 같은 최신 스마트 폰을 사용하면 두 손가락을 사용하여 손가락 사이의 거리를 늘리거나 줄임으로써 이미지를 확대 및 축소 할 수 있습니다. Windows Phone 7의 Internet Explorer에서도 동일한 작업을 수행할 수 있습니다. 이 작업을 Windows Phone 7에서 "손가락 모으기, 늘이기"라고 합니다.

핀치 및 스트레칭 외에도 "탭"과 같은 작업을 사용하여 화면의 한 지점을 짧게 터치(탭)하고 "긋기"를 사용하여 화면을 빠르게 추적할 수 있습니다. 이러한 동작을 집합적으로 제스처라고 합니다.

이 프로그램에서는이 핀치 앤 스트레치 작업으로 화면에 표시되는 스프라이트를 확대 및 축소하고 싶습니다. 또한 지난번까지는 터치 패널의 정보를 직접 가져와 처리했습니다 만, 이번에는 제스처 전용 방법을 사용하여 터치 조작을 처리하고 싶습니다.

이 샘플 프로그램의 목표

핀치 및 스트레치 작업을 수행하여 스프라이트를 확대 및 축소합니다.

図 1 :ストレッチでスプライトを拡大
그림 1: 스프라이트를 확대하기 위해 늘림

프로그램 - 필드 선언

필드 선언에는 새로운 클래스가 없지만 "텍스처의 중심 좌표", "스프라이트의 배율"및 "핀치 할 때 마지막 두 터치 위치 사이의 거리"가 있습니다.

/// <summary>
/// テクスチャー
/// </summary>
Texture2D texture;

/// <summary>
/// テクスチャーの中心座標
/// </summary>
Vector2 textureCenterPos;

/// <summary>
/// スプライトのスケール
/// </summary>
float scale = 1;

/// <summary>
/// 前回の 2 点間の距離
/// </summary>
float previousLength = 0;

프로그램 - 제스처 사용

이번에는 제스처 전용 프로세스를 수행하지만 기본 상태에서는 제스처를 사용할 수 없습니다. 각 제스처 정보를 검색하려면 TouchPanel.EnabledGestures 속성에 사용할 제스처를 설정해야 합니다.

// タッチパネルでピンチのジェスチャーを有効にする
TouchPanel.EnabledGestures = GestureType.Pinch | GestureType.PinchComplete;

모든 제스처를 활성화하면 성능에 영향을 주므로 사용하려는 제스처만 설정해야 합니다. 여기서, 핀치 동작 정보를 얻기 위해 "GestureType.Pinch"를 설정하고, 핀치 프로세스가 완료되었음을 나타내기 위해 "GestureType.PinchComplete"를 설정한다. 설정 위치는 게임 생성자에서 설정합니다.

프로그램 - 텍스처 불러오기

텍스처 로딩은 이전과 동일하지만 이번에는 "텍스처의 중심 좌표"를 계산합니다. 이는 스프라이트의 크기를 조정할 때 중심 좌표를 원점으로 하여 크기가 조정되기 때문입니다.

// テクスチャーをコンテンツパイプラインから読み込む
texture = Content.Load<Texture2D>("Texture");

// テクスチャーの中心座標を求める
textureCenterPos = new Vector2(texture.Width / 2, texture.Height / 2);

프로그램 - 제스처 정보 가져오기

Game.Update 메서드에서 제스처 정보(여기서는 핀치)를 얻습니다. 제스처 처리는 활성화한 만큼의 제스처를 반복하는 형태입니다. 마지막까지 사용되었던 "TouchCollection" 구조는 사용되지 않습니다.

// 次のジェスチャー情報が取得できる場合は true を返し続けます
while (TouchPanel.IsGestureAvailable)
{
  // 次のジェスチャー情報を読み込みます
  GestureSample gs = TouchPanel.ReadGesture();
  
  switch (gs.GestureType)
  {
    case GestureType.Pinch:
      // ここにピンチ処理を記述します
      break;
    case GestureType.PinchComplete:
      // ここにピンチ完了処理を記述します
      break;
  }
}

while 루프에서 TouchPanel.IsGestureAvailable 속성의 상태에서 제스처 정보를 확인하고 다음 제스처 정보가 있는지 확인합니다. 다음과 같은 제스처 정보가 있는 경우 "TouchPanel.ReadGesture" 메서드를 사용하여 제스처 정보를 가져옵니다.

"GestureSample.GestureType"은 포함된 제스처 유형에 대한 정보를 저장하므로 이를 기반으로 하는 switch 문을 사용하여 프로세스를 분기합니다. 이 샘플에서 생성자는 "GestureType.Pinch" 및 "GestureType.PinchComplete" 열거형을 각각 분기되도록 "TouchPanel.EnabledGestures" 속성으로 설정합니다.

프로그램 - 핀치 제스처 처리

우리가 하고 있는 일에 대한 코드의 주석을 보는 것이 더 빠르지만, 우리가 하고 있는 일을 요약하기 위해 이전 두 터치포인트 사이의 거리와 이번에는 두 지점 사이의 터치포인트 거리 간의 차이를 찾고 그 차이를 사용하여 스케일 값을 늘리거나 줄입니다.

case GestureType.Pinch:
  // 現在の2点間の距離を求めます
  float nowLength = (gs.Position - gs.Position2).Length();

  if (previousLength == 0)
  {
    // 前回の2点間の距離が 0 の場合は
    // 現在の2点間の距離を設定します
    // 初回はスケール計算を行いません
    previousLength = nowLength;
  }
  else
  {
    // 前回の2点間の距離との差分を計算します
    float diffLength = nowLength - previousLength;
    
    // ピンチ、ストレッチした距離に応じて
    // スケールを変化させています
    // 補正値は適当に設定します
    scale = MathHelper.Max(scale + diffLength / 150, 0);
    
    // 今回の距離を次の計算のために保持します
    previousLength = nowLength;
  }
  break;

두 터치 위치는 각각 "GestureSample.Position" 및 "GestureSample.Position2"로 얻을 수 있습니다. 얻은 두 벡터 간의 차이를 빼고 "Vector2.Length"메서드를 호출하여 두 점 사이의 거리를 찾을 수 있습니다.

그건 그렇고, 여기서는 핀칭이 수행되지 않을 때 이전 거리를 0으로 정의하므로 핀칭이 시작될 때와 두 번째 및 후속 루프에서 프로세스가 분기됩니다. 처음 꼬집는 경우 이전 거리가 없으므로 확장 할 필요가 없기 때문입니다.

또한 이번에는 "GestureSample.Position" 및 "GestureSample.Position2"라는 두 가지 속성만 사용하지만 이전 터치 위치와의 차이 정보를 가져올 수 있는 "GestureSample.Delta" 및 "GestureSample.Delta2" 속성도 있습니다. 각각 두 개의 속성이 있지만 이것은 멀티 터치를위한 것이며 단일 터치 만 사용하는 제스처의 경우 "2"가없는 속성을 사용합니다.

프로그램 - 핀치 제스처가 완료될 때 처리

손가락 모으기 제스처가 완료되면(터치 패널에서 손가락을 뗄) 이전 두 점 사이의 거리가 다시 0으로 설정됩니다. 원래는 별도의 플래그를 사용하는 것이 더 나을 수 있지만 두 손가락으로 같은 위치를 터치하는 것은 물리적으로 불가능하기 때문에 0의 거리는 꼬집지 않는 것으로 정의됩니다. (해상도가 낮으면 같은 위치를 터치하는 것이 가능할 수 있습니다 ...)

case GestureType.PinchComplete:
  // ピンチが終了した場合は保持している距離を 0 に戻して
  // 完了したことにします
  previousLength = 0;
  break;

프로그램 - 스프라이트 그리기

여기서는 스프라이트를 그리는 것이기 때문에 자세히 설명하지는 않겠지만, 스프라이트를 화면 중앙에 배치하고 스프라이트의 중심을 원점으로 하여 확대 및 축소하여 계산된 스케일 값을 그렸습니다.

// スプライトの描画準備
spriteBatch.Begin();

// スプライトを描画する
spriteBatch.Draw(texture,
                 new Vector2(graphics.PreferredBackBufferWidth / 2,
                             graphics.PreferredBackBufferHeight / 2),
                 null,
                 Color.White,
                 0.0f,
                 textureCenterPos,
                 scale,
                 SpriteEffects.None,
                 0.0f);

// スプライトの一括描画
spriteBatch.End();

이 샘플의 요약

이번에는 제스처 전용 프로세스를 설명했습니다. 샘플에서는 핀치 프로세스만 만들지만 "긋기" 및 "보류"도 있습니다. 사용할 수 있는 제스처를 확인하려면 제스처 유형 열거형에 대한 XNA Game Studio 4.0 도움말을 확인하세요.

제스처별 메서드나 구조체를 사용하지 않고 TouchPanel.GetState 메서드에서 가져온 터치 정보에서 동일한 것을 구현할 수 있지만 이 경우 멀티 터치 ID 관리, 터치 시간, 긋기 등의 속도를 직접 계산해야 합니다. 제스처 특정 방법을 사용함으로써, 이러한 구현이 단순화될 수 있고, 또한 모든 게임 및 어플리케이션이 동일한 방식으로 동작될 수 있다는 장점이 있다.

터치 패널 프로세스를 직접 만들 때 유사한 프로세스를 제스처로 대체할 수 있다면 이를 사용하는 것이 좋습니다.

프로그래밍! - 5.핀치로 스프라이트 회전

이 샘플 정보

핀치는 일반적으로 "핀치"와 "스트레칭"을 의미하지만 XNA Game Studio 4.0의 핀치 프로세스는 프로세스를 이 두 가지로 특별히 제한하지 않으므로 한 터치포인트를 다른 터치포인트 중심으로 순환하는 작업을 수행할 수도 있습니다.

여기에서는 그 조작 방법으로 스프라이트를 회전시키고 싶습니다. 그건 그렇고, 이번에는 새로운 메소드 나 클래스가 나타나지 않았으며 이전 스케일링을 기반으로합니다.

이 문서의 샘플 코드에 대한 설명에서는 이전 크기 조정 샘플과 동일한 부분이 생략됩니다.

이 샘플 프로그램의 목표

두 터치포인트를 회전하면 스프라이트가 회전합니다. 이전 크기 조정 작업도 작동합니다.

図 2 :タッチポイントを回してスプライトを回転させています
그림 2: 터치포인트를 돌려 스프라이트 회전

프로그램 - 필드 선언

"스프라이트 회전량"과 "마지막 회전 각도"가 이전 스케일링 프로그램에 추가됩니다. 모든 각도는 라디안 단위로 계산됩니다.

/// <summary>
/// スプライトの回転量(radian)
/// </summary>
float rotate;

/// <summary>
/// 前回の回転角度(radian)
/// </summary>
float previousAngle;

프로그램 - 순환 프로세스

회전 프로세스는 핀치 제스처 중에 크기 조정과 동일한 방식으로 수행됩니다.

수학 이야기이기 때문에 회전 계산에 대해 너무 자세히 설명하지는 않겠지 만 터치 포인트 1에서 터치 포인트 2까지의 차이 벡터를 찾아 "Math.Atan2"방법으로 각도 라디안을 얻을 수 있습니다. 얻은 각도와 이전에 획득 한 각도의 차이를 찾아 스프라이트의 회전 각도에 추가하십시오.

switch (gs.GestureType)
{
  case GestureType.Pinch:
    //===== スケール計算 =====//
    // 前回と同じなので省略

    //===== 回転計算 =====//

    // 2点間のベクトルを求めます
    Vector2 pinchVector = gs.Position2 - gs.Position;

    // Atan2 で角度を求めます
    float nowAngle = (float)Math.Atan2(pinchVector.Y,
                                       pinchVector.X);

    if (previousAngle == 0)
    {
      // 前回の角度が 0 の場合は
      // 現在の角度を設定します
      // 初回は回転計算を行いません
      previousAngle = nowAngle;
    }
    else
    {
      // 前回の角度との差分をスプライトの回転角度に加算します
      rotate += nowAngle - previousAngle;

      // 今回の距離を次の計算のために保持します
      previousAngle = nowAngle;
    }
    break;
  case GestureType.PinchComplete:
    // ピンチが終了した場合は保持している距離、角度を 0 に戻して
    // 完了したことにします
    previousLength = 0;
    previousAngle = 0;
    break;
}

프로그램 - 스프라이트 그리기

그리기 스프라이트에는 큰 변화가 없습니다. SpriteBacth.Draw 메서드의 다섯 번째 인수는 계산된 회전 각도로 설정됩니다.

// スプライトの描画準備
spriteBatch.Begin();

// スプライトを描画する
spriteBatch.Draw(texture,
                 new Vector2(graphics.PreferredBackBufferWidth / 2,
                             graphics.PreferredBackBufferHeight / 2),
                 null,
                 Color.White,
                 rotate,
                 textureCenterPos,
                 scale,
                 SpriteEffects.None,
                 0.0f);

// スプライトの一括描画
spriteBatch.End();

이 샘플의 요약

이번에는 핀치 조작으로 스프라이트를 회전시켜 보았습니다. 특별히 새로운 클래스를 사용하지는 않지만, 제공된 기능을 기반으로 응용 처리를 실현할 수 있다는 점을 이해해 주셨으면 합니다.

마침내

샘플을 살펴보고 Windows Phone 7 및 XNA Game Studio 4.0을 사용한 터치 조작의 구현을 시연했습니다. 콘텐츠에는 터치 정보의 단일 터치 및 멀티 터치 터치 획득 및 조작, 제스처 별 방법을 사용한 터치 제스처 조작에 의한 처리가 포함되었습니다.

이번에는 터치 패널에 중점을 두었습니다 만, 아직 소개하지 않은 기능이 있습니다. Windows Phone 7에는 가속도계 입력 및 음성 입력과 같은 XNA Game Studio 4.0의 새로운 입력 기능도 포함되어 있습니다. 이번에 소개할 수 없었던 몇 가지 흥미로운 기능이 있으니, 사용하고 싶은 기능을 즐겨 탐색해 보세요.