エイリアンプログラム

主にゲームプログラミングに関するブログです。

GameObjectをCanvasの座標に合わせて移動する方法

前回の記事で、UIの座標からスクリーン座標に変換してそれをワールド座標に変換すれば出来ますと記載しました。

RectTransformからワールド座標に変換する方法 - エイリアンプログラム

ただこの方法だと、カメラが平行投影(Orthographic)の時に、移動させるGameObjectが移動先のGameObject(UI)よりズレた座標に配置されてしまう問題が発生します。

しかしどうやら上記のやり方以外に簡単な方法でやれるみたいです。
なので今回はそのやり方をご紹介したいと思います。

やり方は非常にシンプルで、Canvasの中にGameObjectを入れればいいだけの話です。
それを行う前に以下の設定を行う必要がございます。

設定

  1. CanvasのRenderModeをScreen Space - Cameraに設定。(取りあえずMainCameraでOK)
  2. 適当にUIを配置(私はImageを使いました)。
  3. Canvasの下に空(Empty)のGameObjectを配置。
  4. 3番で設定した空のGameObjectの下に、CubeもしくはSphereを配置。座標は(0, 0, 0)、Scaleは適当に値(※1)を入れてください。
  5. 4番で配置したGameObjectのLayerをUIに設定。

※1 : Scaleが(1, 1, 1)だと小さすぎて見にくかった

大体以下の画像のようになっていれば問題ございません。
無理に画像のように合わせなくても大丈夫です。

f:id:alien_program:20170811111414p:plain f:id:alien_program:20170811111423p:plain

適当にスクリプトを生成して以下のように配置してください。

public class Move : MonoBehaviour {
    public RectTransform m_toRect; //移動先
    public RectTransform m_target; //移動させたいGameObject(4番で設定した空のGameObject)

    private void Start()
    {
        MoveGameObject(m_toRect);
    }

    private void MoveGameObject(RectTransform rect)
    {
                //移動させたいGameObjectを移動先のGameObjectの座標を代入
        m_target.position = rect.position;
    }
}

Unityエディタを再生させると以下のようにSphereが赤色のImageに移動します。

f:id:alien_program:20170811112402p:plain

結果としてつまりCubeやSphereの代わりにRectTransformの座標であるGameObjectを移動させてあげればいいだけの話です。
この方法を使えば、カメラが平行投影でも問題なく移動先の座標にGameObjectが移動しました。

RectTransformからワールド座標に変換する方法

さてさて、今回はRectTransform(uGUI)からワールド座標に変換する方法を投稿しようと思います。
昔、私がUnityを始めた頃はnGUIが盛んでしたが、時が経つにつれて今ではuGUIが主流となってきました(まあ、作った人は同一人物らしいですが…)。

細かい説明を省きますが、通常uGUI(Canvasと記す)の座標とワールド座標は全くの別物です。
例えば、Canvas内のImage(以下の画像の①)の座標が(-39.1, 5.72, 0)だとして、ワールド座標であるGameObjectの座標(以下の画像の②)に(-39.1, 5.72, 0)を代入しても、ImageとGameObjectは重なりません。 f:id:alien_program:20170806155743p:plain

そこで以下の処理を行うことで、ImageとGameObjectを重ねることが出来ます。

private Vector3 GetWorldPositionFromRectPosition(RectTransform rect)
{
//UI座標からスクリーン座標に変換
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(m_canvas.worldCamera, rect.position);

//ワールド座標
Vector3 result = Vector3.zero;

//スクリーン座標→ワールド座標に変換
RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, screenPos, m_canvas.worldCamera, out result);

return result;
}

上記で行った内容は以下の通りです。
1. RectTransformUtility.WorldToScreenPointで、UIの座標をスクリーン座標に変換する。
2. 1で取得したスクリーン座標を、RectTransformUtility.ScreenPointToWorldPointInRectangleを使ってワールド座標に変換(result)する。

結果は以下の通りになります。
* 左の画像:赤色のImageの座標をワールド座標に算出して、GameObjectの座標にそれを代入した状態
* 右の画像:青色のImageの座標をワールド座標に算出して、GameObjectの座標にそれを代入した状態
f:id:alien_program:20170806160613p:plain

※捕捉

RectTransformUtility.WorldToScreenPoint
第一引数:UIのカメラ。今回はCanvasで設定したRenderCameraを代入(RenderModeをScreenSpace Cameraに設定)
第二引数:スクリーン座標に変換したいUIのRectTransformを代入

f:id:alien_program:20170806152547p:plain

RectTransformUtility.ScreenPointToWorldPointInRectangle
第一引数:指定のUIのRectTransformを代入
第二引数:指定のUIのスクリーン座標を代入
第三引数:Canvasで使用しているCameraを代入
第四引数:取得したワールド座標の結果(参照渡し)


以上となります。
正直細かい説明は端折ましたが、これを使用することによって指定のGameObjectを指定のUIのところに移動させることが可能になりました。

初回はUnityで行こうと思います。

はじめまして普段仕事でUnityを触っている平凡なプログラマーです。

今回、スキルアップの成果を広めるため、定期的にプログラミングに関する内容を投稿して行こうと思います。

ここ最近UE4とかにも興味を持ち、近いうちにそれについても書いていこうと思います。

 

何卒宜しくお願い致します。