Unityのタップ位置をCanvasのlocalPositionと合わせるfor iPhone/Android

  • 1
    Like
  • 0
    Comment

はじめに

Unityでスマートフォン向けの音ゲーを作ってみようと思って困ったタップについて
音ゲーに限らずタップの位置をキャンバスと合わせたい人に向けた記事になります。

条件

  • PlayStore、AppStoreの両方でリリース
  • iOSリリース予定最終日の前日(詰んだ)

今回の環境

  • macOS Sierra バージョン10.12.6
  • Unity Version2017.10f3 Personal

ここでやること

  • Gameウィンドウで見えるサイズをスマホと合わせる
  • Canvasの設定からUIが崩れないようにする
  • タップのlocalPositionをとる

画面サイズの設定

今回はiPhone、Androidの両方の端末から触れるようにしたいので、ゲームウィンドウの設定からしていきます。
Game>FreeAspect とあるところから、今回使用したい画面の比率を選びます。
調べたところ、16:9(縦画面なら9:16)が一番多いと出たんですが、うーん...ない。

スクリーンショット 2017-11-01 22.28.43.png


そういう時は自分で新しい比率を作っちゃいます。
一番下の + のアイコンをクリックしてもらうとAddって小さいウィンドウが出てくるので、ここに使いたい比率の名前、横幅、高さ、を入力して"OK"をクリックすれば新しい比率が選べるようになります。
私は自分持ってる実機のサイズと、一番多いと言われている1920 * 1080の比率を追加しておきました。
余談ですが、Galaxy S7 edgeは2560 * 1440(pixel)です。なかなか検索引っかかってくれないので。

スクリーンショット 2017-11-01 22.35.34.png
これで、エディタ上で実際のアスペクト比で見たときと同じように表示できるようになりました。

キャンバスの設定

さっき設定した比率をメインにCanvasの方も設定していきます。
Canvas>Canvas ScalerのReference Resolutionってところにさっき設定した比率を入力します。
この比率で設定したUIを極力崩さないようにしてくれるみたいです。

設定したい項目があと3つあります。一気に行きますね。

スクリーンショット 2017-11-01 23.03.30.png

  • UI Scale Mode → Scale With Screen Size
  • Screen Match Mode → Match Width Or Height
  • Match → 0(Width): 縦画面 / 1(Height): 横画面

今まで横画面で設定してきましたがここで急に画像が縦画面設定になってますね。すいません。
初めは1(Height)で設定していたんですが、AppStoreで公開する時に少し不具合がありまして0(Width)に設定しています。 PlayStoreで不具合出てたらどうしよう

タップの位置をとる

ここが一番苦戦しました。
iPhoneは実機テストの段階で気がついたんですが、AndroidはPlayStoreでレビューを書いていただくまで気がつきませんでした。本当にすいません。
これからそういうことを繰り返さないように失敗談含めて書いて行きますね。

普通に座標を取ってみる

まず初めに書いてみたのがこれです

tapPosition.cs
// タップ処理
  if (Input.touchCount > 0) {
    Touch touch = Input.GetTouch (0);

    if (touch.phase == TouchPhase.Began) {
      tapPos = touch.position;
    }

  }

タップした初めの位置を取りたかったのでTouchPhase.Beganのところでtouch.positionを取ってます。

今回必要だったのは2DのCanvas上のlocalPsitionでして...この書き方だど欲しい値は帰ってきませんでした。
何故かタップ位置がピッタリ画面半分だけ右上にズレてる...
Canvasとかを考えない状態ならこれで行けたんですけど...解せん。

よし、次だ。

原点の位置を合わせてみる

tapPosition.cs
// タップ処理
  if (Input.touchCount > 0) {
    Touch touch = Input.GetTouch (0);

    if (touch.phase == TouchPhase.Began) {
      tapPos = touch.position;
      tapPosOne.x -= CanvasRect.sizeDelta.x/2;
      tapPosOne.y -= CanvasRect.sizeDelta.y/2;
    }

  }

これは我ながら頭が悪いことをしたと思います...でも私の実機だと正確に動いたんです(言い訳)
まずタップした位置を取ります。これはさっきと同じです。
次にCanvasの横幅・縦幅の半分だけ引いてみました。罠です。成功しました。
ただ、これではうまくいかない機種がiPhone含めいくつかあるようです。

うまくいかない機種ではタップ位置が右にズレていくにつれて、タップ位置とキャンバス上の検知される位置の差が大きくなっていくみたいでした。参考までに。

目標はPlayStore、AppStore両方でのリリース...私の実機が全てとは言えないので。
よし、次行きます。

ズレていく割合を計算してみる

tapPosition.cs
// タップ処理
  if (Input.touchCount > 0) {
    Touch touch = Input.GetTouch (0);

    if (touch.phase == TouchPhase.Began) {
      tapPosOne.x = (touch.position.x - Screen.width / 2) / Screen.width * CanvasRect.sizeDelta.x;
      tapPosOne.y = (touch.position.y - Screen.height / 2) / Screen.height * CanvasRect.sizeDelta.y;
    }

  }

できた!!!!!
さっきの失敗で、右に行くほどズレて行くっていうのがあったと思います。
これ、CanvasのlocalPositionは中心が原点で、タップの位置をとるスクリプトではたしか左下が原点だったはずで...それが前回成功してしまった理由でもあるんですが。
前回やったのはスクリプトの原点を無理やりキャンバスの中心と合わせたってことだったんです。

それをヒントに原点からのズレを実機との割合で出して、キャンバスサイズをかけてみました。
キャンバスを実機のサイズに合わせてるはずなのにどうして実機サイズとキャンバスサイスが違うのか...ここらへんがよくわからないんですがとりあえず全実機に対応するようなタップ位置が取れた!はず!!

余談

キャンバスサイズと実機サイズ、私の感覚で行くと同じじゃない?って思ったので試してみました。

tapPosition.cs
// タップ処理
  if (Input.touchCount > 0) {
    Touch touch = Input.GetTouch (0);

    if (touch.phase == TouchPhase.Began) {
      tapPosOne.x = (touch.position.x - CanvasRect.sizeDelta.x / 2) / CanvasRect.sizeDelta.x * Screen.width;
      tapPosOne.y = (touch.position.y - CanvasRect.sizeDelta.y / 2) / CanvasRect.sizeDelta.y * Screen.height;
    }

  }

あらぬところに反応が出たのでどうやら私は運が良かったようです。
最初にこれを引き当ててたらこの計算諦めてた
キャンバスサイズと実機サイズは違うみたいですね。


あと試したのはこれですかね...

tapPosition.cs
    tapPosOne = Input.mousePosition;
    tapPosOne = Camera.main.ScreenToWorldPoint(Input.mousePosition);

スクリーン座標をワールド座標に変換するみたいなやつなんですけど、うまくいきませんでした。
そもそもキャンバスって何座標で動いているのか...

どうしてキャンバス設定が縦画面なのか

これはAppStoreでリジェクトされたからなんです...
前まではiPhone専用アプリとか出せたみたいなんですけど、今はiPhone・iPad対応のアプリしかリリースさせてくれないみたいでして。
リジェクトの理由の部分に4.デザイン規約みたいに書かれて謎の4:3の画像が貼られてきました。
正直何を言われてるのかさっぱりわからなかったですが、どうやらiPadだとこう見えるよって言っていたようです。

確かにCanvas ScalerのReference Resolutionを4:3にするとそれと同じ表示に...
そこでCanvas設定を縦画面設定にしてみたところ、表示自体は全部見えるようになりました。
その代わりにUnityのデフォルトのSkyBoxが見えてしまったんですが...。
公開までの時間も残り少なく、素材を作り直しているような余裕もなかったので仮置きでSkyBoxを隠す黒いImageを上下に配置して対処しました。

はーーーApple製品わかんね。
ジャイロセンサーの向きも違うみたいですし、どうにか仲良くしてもらえないですかね...。

長くなりましたがここまで読んでくださってありがとうございます。
少しでも皆様のお力になれますように。