Persistence

技術メモなど

Unityをいじってみた(その4〜お皿を回転させる技術〜)

これで最後の記事です。

お皿を回転させる技術

このゲームでこだわりたいポイントとして、ターンテーブルの動きをいかに自然に、指の動きに合わせて回転できるかということがありましたので、それについて試行錯誤した実装を説明します。

1.通常時の回転

ゲームシーンでは、何もしない状態で常に一定のスピードでターンテーブルが回転している状態にしておきます。それには、ターンテーブルのGameObjectにRigidbody2Dコンポーネントをつけて、Rigidbody2D.angularVelocityに値を設定します。angularVelocityの単位は角度/秒です。

2.指で回転させる動き

指の動きはTouchクラスで取得します。Touchの状態として、次の4つの状態があります。

  • TouchPhase.Began タッチし始めた時
  • TouchPhase.Moved タッチしながら指を動かした時
  • TouchPhase.Stationary タッチしながら指が動いていない時
  • TouchPhase.Ended タッチし終えて離した時

そして、それぞれの動作は次のとおりです。

BeganとEndedの時は何もしません。

Stationaryの時は、ターンテーブルを指で押さえている状態になるので、ターンテーブルのRigidbody2D.angularVelocityを0にして回転を止めます。

Movedの時は、前のフレームと今のフレームで、ターンテーブルの中心から何度回転したかを取得し、それをRigidbody2D.angularVelocityに回転速度として与えます。また、前のフレームと今のフレームでターンテーブルの回転方向が変わったら、判定処理を行います。

     // 更新前の回転の向き
        float beforeAngularVelocity = discRigidbody2D.angularVelocity;
        // 回転角度を求める
        float deltaAngle = GetDeltaAngle (goDisc.transform.position, touch.position, touch.position - touch.deltaPosition);
        // 回転速度にするために適当な倍率をかけ、回転速度の上限を設定する
        float angularVelocity = Mathf.Clamp (deltaAngle * 25, -500.0f, 500.0f);
        discRigidbody2D.angularVelocity = angularVelocity;

        // Discの回転の向きが変わったら && 一定以上の角度があったら反応する
        if (beforeAngularVelocity * angularVelocity <= 0.0f && Mathf.Abs (angularVelocity) > 10.0f) {
            // スクラッチ音の再生(省略)
            // 判定処理(省略)
        }
 // 3点間の角度を求める
    private float GetDeltaAngle (Vector2 p0, Vector2 p1, Vector2 p2)
    {
        float deltaAngle = GetAim (p0, p1) - GetAim (p0, p2);
        deltaAngle += deltaAngle > 180 ? -360 : 0;
        deltaAngle += deltaAngle < -180 ? 360 : 0;
        return deltaAngle;
    }

    // 2点間の角度を求める
    private float GetAim (Vector2 p1, Vector2 p2)
    {
        float dx = p2.x - p1.x;
        float dy = p2.y - p1.y;
        float rad = Mathf.Atan2 (dy, dx);
        return rad * Mathf.Rad2Deg;
    }

discRigidbody2DがターンテーブルのRigidbody2Dコンポーネントです。判定処理のため、まず現在の回転速度(回転方向)を取得しておきます。次にGetDeltaAngleメソッドにて前のフレームと今のフレームで、ターンテーブルの中心から何度回転したかを取得します。引数はターンテーブルの中心座標、今タッチしている座標、前のフレームでタッチした座標です。この3点から角度を求めます。後はその角度に適当な調整をかけて角速度にしてdiscRigidbody2D.angularVelocityに設定します。残りは判定処理です。

この「3点の角度を求める」という、おそらく三角関数の基礎なんでしょうが、それが分からず苦労しました。以下のサイトが参考になりました。

参考:【Unity2D】2点間の角度を求める - Qiita

そして壊れる

色々やっていたら、GameObjectがmissing状態になり読み込めない状態になってしまいました。どうやらメタファイルに記録されているゲームオブジェクトのUUIDが変わってしまったために起こる現象らしいです。原因としてはUnity Editor以外のFinderなどでファイルの変更操作を行ったりクラッシュだったり、色々とあるようなので操作は慎重にしてライブラリ管理をちゃんとやらないといけないですね。

参考:Unity開発者が複数人で開発を進める上で覚えておくと幸せになる9つの事 - テラシュールブログ

おわりに

というわけで最後は壊れてしまったのですが、どちらにしても作り直したいと思っていたし、Unity5もリリースされたので新しい機能などもチェックしつつ、次はもっとスマートな設計にしたいと思います。