Windows Phone 7 のゲーム開発でのタッチ操作 その 3 ドラッグ操作

ページ更新日 :
ページ作成日 :

プログラミング! - 3.カードをタッチに合わせて動かしてみる

今回のサンプルについて

今回は 4 つのカードを画面上に配置してタッチした場所にカードを配置、ドラッグさせるプログランを作ってみたいと思います。最初に Mouse クラスでスプライトをドラッグしたプログラムのマルチタッチ版です。今までは説明が多かったので今回はプログラム中心で説明していきたいと思います。

このサンプルプログラムのゴール

マルチタッチでタッチした数だけ複数のカードを同時にドラッグします。

図 1 :マルチタッチによるドラッグ操作
図 1 :マルチタッチによるドラッグ操作

プログラム - カードクラス

マルチタッチになると複数のオブジェクトを持つ必要が出てきますのでここでは移動させるスプライトを「カード」とし「Card」クラスを作成したいと思います。

/// <summary>
/// ドラッグできるカード
/// </summary>
public class Card
{
  /// <summary>
  /// タッチ ID
  /// </summary>
  public int Id { get; set; }

  /// <summary>
  /// カードの位置
  /// </summary>
  public Vector2 Position { get; set; }

  /// <summary>
  /// カードの色
  /// </summary>
  public Color Color { get; set; }
}

あまり複雑なコードにならないようにテクスチャーは一つとしてカードクラスには「タッチID」「位置」「色」の 3 つのプロパティを持たせるようにしています。特に詳しく説明する項目はありませんが、「タッチID」はどのタッチポイントと紐づいているかをチェックするために使用します。

プログラム - フィールドの宣言

カード情報を持つために Card クラスの配列を持っている点以外については新しいものは特にありません。今回は今までのサンプルの応用みたいなものです。カードは 4 枚作成し、描画時に違いが分かるようにそれぞれ別々の色を設定しています。

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

/// <summary>
/// カードの一覧(4 枚分)
/// </summary>
Card[] cards = new Card[]
{
  new Card { Color = Color.White, },
  new Card { Color = Color.Yellow, },
  new Card { Color = Color.Fuchsia, },
  new Card { Color = Color.Aqua, },
};

プログラム - タッチ情報の取得

Game.Update メソッド内部です。このあたりは定型的なものなので特に新しい点はありません。

// タッチパネルの機能情報を取得
TouchPanelCapabilities capabilities = TouchPanel.GetCapabilities();

// タッチパネルが使用可能であるかチェック
if (capabilities.IsConnected)
{
  // 現在のタッチパネルの入力情報を取得
  TouchCollection touches = TouchPanel.GetState();

  //   :
  // ここに処理
  //   :
}

プログラム - タッチした際にタッチ ID とカードを紐づける

サンプルプログラムでは処理コストの面から順番が逆なのですがこちらから説明した方がわかりやすいので先にこちらを説明します。

まず取得した TouchCollection を foreach でループさせて各情報を取得します。

/// タッチ情報の処理を行う
foreach (TouchLocation tl in touches)
{
  // タッチ状態を調べる
  switch (tl.State)
  {
    case TouchLocationState.Pressed:
      // タッチされた瞬間は空いているカードを検索して紐づける
      Card card = cards.Where(c => c.Id == 0).FirstOrDefault();
      if (card != null)
      {
          card.Id = tl.Id;
          card.Position = tl.Position;
      }
      break;
  }
}

「TouchLocation.State」プロパティを調べて「TouchLocationState.Pressed」ならタッチした瞬間であることを示します。

今回のサンプルではカードの ID が「0」の場合は使用されていないという形で定義しているので、「cards.Where(c => c.Id == 0).FirstOrDefault()」でカードの一覧から ID が 0 のカードを検索して見つかったらそのカードを取得するようにしています。見つからない場合は null を返します。ここではコードの簡素化のために LINQ による拡張メソッドの呼び出しを行っていますが、処理コストなどを気にするのであれば for ループなどで逐一検索しても構いません。

カードが見つかったらタッチ ID とタッチ位置をカードにセットします。

プログラム - タッチ中のカードの処理と放した時の処理

タッチしている間はそのカードを常にドラッグ状態にしておき、放したときにタッチポイントとカードとの紐づけを切るようにします。

// 各カードの情報を調べる
foreach (Card card in cards)
{
  if (card.Id != 0)
  {
    // 紐づくタッチ情報がまだ存在するか ID で検索
    TouchLocation tl;
    if (touches.FindById(card.Id, out tl) == true)
    {
      // まだタッチされている場合は位置情報取得
      card.Position = tl.Position;
    }
    else
    {
      // すでにタッチ情報がなかったら紐付を外す
      card.Id = 0;
    }
  }
}

カード一覧を foreach でループさせ各カードに対して処理を行います。ID が 0 以外であればタッチポイントとの紐づけが行われているので処理を継続させます。

TouchCollection 構造体には「FindById」メソッドが用意されており、指定した ID が存在する場合はそのタッチ情報を取得できるようになっています。Card.Id プロパティが0でない場合はどこかのタッチポイントと紐づけが行われていると仮定できるので、FindById メソッドでタッチ情報の取得を試みます。

FindById メソッドが true を返した場合はまだタッチ状態であるため、TouchLocation.Position プロパティからタッチ位置を取得してカードクラスにセットします。FindById メソッドが false を返した場合はタッチが放されたことになるので Card.ID を 0 にして誰も触っていない状態として設定します。

プログラム - カードの描画

描画に必要なパラメータはすでに Card クラスに設定されているはずなので特に目新しい部分はありません。

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

// 各カードを描画
foreach (Card card in cards)
{
  spriteBatch.Draw(texture, card.Position, card.Color);
}

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

今回のサンプルのまとめ

今回はマルチタッチを使用して実際にゲーム内でオブジェクトを動かすようなイメージのプログラムを作成してみました。また、タッチ情報の ID を使用して複数のカードを同時にドラッグした際に、他の指を放したりタッチしなおしたりしてもカードの移動が矛盾しないように処理されていることも確認できました。

今回のサンプルはあくまでもサンプルであって簡易的な処理しか行っておりません。ですが、実際のゲームプログラミングでタッチパネルによるマルチタッチの動作の基本的な部分は賄えているはずなので、これをもとに自分のゲームにあったマルチタッチ処理へ応用してみてください。