ゴマちゃんフロンティア

アザラシが大好きなエンジニアの開発日記です

【Unity】エディタ拡張で「Blenderのテンキー」っぽい視点移動を作ってみる

time 2017/06/14

というわけで、近頃のゲーム業界はE3の件でにぎわっていますね!
特に気になるのはやはりPS4のモンハンでしょうか。久々のPSハードなので尚更ですね。

今回の内容ですが、珍しくUnityのエディタ拡張に関するお話です。
シーンビューであれこれ物を配置する際、「Blenderのようにテンキーで視点変えれたらな~」なんて思うことがあります。「シーンギズモ使えよ」という話ではありますが、やはりマウスカーソルはそのままで、パパっと回したいのが願望です。
エディタ拡張系はほとんど触ったことがなく、ちょうどいい機会なので「それっぽい動作」を作ってみました!

ちなみに「シーンギズモ」って↓のことらしいです。

これに名前があることを知ったのはかなり最近だったりします。Unity自体勢いで始めたので、各機能の名称が分からないことも多いです。普段は問題ありませんが、エディタ拡張関連であれこれ調べるときに面倒なことになります。

サンプルクラス

先に作ったクラスを記載します。
これをAsset以下のEditorフォルダに入れると機能します。
面倒が嫌いな方はこれをコピペすればBlenderっぽくなるはずです。

using UnityEngine;
using UnityEditor;

[InitializeOnLoad]
public class SwitchViewPoint {

    // 各キー名の定義
    private const string FRONT = "Keypad1";
    private const string TOP = "Keypad7";
    private const string RIGHT = "Keypad3";
    private const string PROJECTION_METHOD = "Keypad5";

    static SwitchViewPoint() {
        SceneView.onSceneGUIDelegate += onSceneView;
    }

    static void onSceneView(SceneView sceneView) {
        if (Event.current.isKey && Event.current.type == EventType.keyDown) {
            string current_key = Event.current.keyCode.ToString();

            if (current_key != "None") {
                // シーンビューの情報を取得
                Vector3 forward = sceneView.camera.transform.forward;

                // Ctrlキーが押されているか判定
                bool onControlKey = Event.current.modifiers.ToString() == "Control" ? true : false;

                // フロントビュー
                if (current_key == FRONT) {
                    forward = onControlKey ? Vector3.forward : -Vector3.forward;
                }

                // トップビュー
                if (current_key == TOP) {
                    forward = onControlKey ? Vector3.up : -Vector3.up;
                }

                // サイドビュー
                if (current_key == RIGHT) {
                    forward = onControlKey ? Vector3.right : -Vector3.right;
                }

                sceneView.LookAt(sceneView.pivot, Quaternion.LookRotation(forward));

                // 投影方法
                if (current_key == PROJECTION_METHOD) {
                    sceneView.orthographic = !sceneView.orthographic;
                }
            }
        }
    }
}

以下、各部分について少しずつ紹介していきます!

シーンビューのイベントへ追加

SceneView.onSceneGUIDelegateに作った関数を追加します。

static SwitchViewPoint() {
    SceneView.onSceneGUIDelegate += onSceneView;
}

実はデリゲートって概念がよく分かっていなかったりするので、詳しいことは説明できません。「関数を変数っぽく使える」みたいな雰囲気でしょうか。
気になる方はぐぐってみてください。

入力キーの取得

Event.current.keyCodeで入力されたキーのKeyCodeが取得できます。
また、修飾キーが押されている場合はEvent.current.modifiersで取れるので、Ctrlキーが押されているかの判定に使います。

if (Event.current.isKey && Event.current.type == EventType.keyDown) {
    string current_key = Event.current.keyCode.ToString();
    bool onControlKey = Event.current.modifiers.ToString() == "Control" ? true : false;

    if (current_key != "None") {
        /* 各処理 */
    }
}

キーによっては何故か2回実行され、2回目はNoneが返ってくるので、こちらも弾くようにしています。
公式フォーラムにそれっぽい話はありましたが、分かるような分からないような・・・という感じです。
http://answers.unity3d.com/questions/666996/why-does-pressing-a-key-generate-a-keydown-event-w.html

各操作の実装

各キーは何れも「テンキーの」数字・記号です。当然ですが、NumLockがオンの状態でないと動作しません。

視点移動

1でフロント、3でサイド(右側)、7でトップビューへの移動を実装します。
公式フォーラムにバックビューのやり方が載っていたので、参考にさせていただきました。

// シーンビューの情報を取得
Vector3 forward = sceneView.camera.transform.forward;

// フロントビュー
if (current_key == FRONT) {
    forward = -Vector3.forward;
}

// トップビュー
if (current_key == TOP) {
    forward = -Vector3.up;
}

// サイドビュー
if (current_key == RIGHT) {
    forward = -Vector3.right;
}

sceneView.LookAt(sceneView.pivot, Quaternion.LookRotation(forward));

カメラ方向を指定する際、Vector3upforwardrightを逆数にする必要があります。「その方向を向けるために移動すべき場所」を考えると分かりやすいかも。逆に分かりにくいという方は忘れてください。

視点移動 (逆側)

BlenderではCtrlを押しながら入力することで逆側に視点移動するので、そのあたりも考慮してみます。
先程のコードを少し修正します。

// シーンビューの情報を取得
Vector3 forward = sceneView.camera.transform.forward;

// Ctrlキーが押されているか判定
bool onControlKey = Event.current.modifiers.ToString() == "Control" ? true : false;

// フロントビュー
if (current_key == FRONT) {
    forward = onControlKey ? Vector3.forward : -Vector3.forward;
}

// トップビュー
if (current_key == TOP) {
    forward = onControlKey ? Vector3.up : -Vector3.up;
}

// サイドビュー
if (current_key == RIGHT) {
    forward = onControlKey ? Vector3.right : -Vector3.right;
}

sceneView.LookAt(sceneView.pivot, Quaternion.LookRotation(forward));

Ctrlが押されている場合は各ベクトルの符号を逆にすればOKです。
ここは三項演算子でスマートに設定しちゃいましょう。

投影方法の切り替え

5で透視投影と平行投影の切り替えを行います。Unityで言えば、シーンギズモの真ん中を押したときのアレですね。
あまり使わないとは思いますが、一応実装しておきます。

if (current_key == PROJECTION_METHOD) {
    sceneView.orthographic = !sceneView.orthographic;
}

SceneView自体にorthographicがあるので、こちらのtrue/falseを切り替えます。
SceneView.cameraにもorthographicがありますが、こちらを切り替えても反映されないようです。

動作

シーンビューで動作を確認してみます。

テンキーの操作だけでぐるぐる動きます!
gifアニメーションでは微妙ですが、実際の動きはシーンギズモ操作時とほとんど変わらないのでもっとなめらかです。

あとがき

ということで、Unityのエディタ拡張でBlenderっぽい視点変更を実現してみました!
本当は「15度ずつ回転」もやりたかったのですが、思った以上に厳しかったので固定での移動だけに限定しました。
15度回転はあまり使わないので、機能的にはこれで十分でしょう。

エディタ拡張入門を読んだ感じでは、思った以上にあれこれできるようです。
また面白いネタがあったら挑戦してみようと思います。

down

コメントする