まえがき
ミクさんにおうちでも踊ってもらいたくない??wowwowARミクさんアプリだとみくちゃとかが有名ですね。完成度が高くて素晴らしいと思います。ですが著作権とかもあるのかな、曲に合わせて踊ってくれる機能に関してはついていません。ないなら作ればいいじゃないか、我々にはUnityとか強いARのapiがある、ということで頑張ってみました。なお始まった時点では筆者はsceneってなんやってくらいUnityの初心者でした。(今も初心者ですが)今回ググりまくって色々やったのですが情報がたくさんありすぎて結構時間がかかったので動いたものに関して個人的に引っかかったところをQ&A方式でブログは書いていきたいなと思います。
注意ですがとりあえず私の環境で動くというだけなので、もっといいやり方があるかもしれないし間違っているかもしれません。(なので間違いはコメント等でビシバシ指摘していただけると幸いです)
前提知識
jyukoさんのARがわかる本(https://jyuko.booth.pm/items/1560126)というのを最初にやりました。やった本はこれだけです。Unity初心者にもわかるようにめちゃくちゃ親切に書いてあるし、Unityでは今最新?のARFoundation(Unity用のAndroid、iOS両対応のライブラリ)使えるのでとてもオススメです。この本に書いてあることは本を買ってください。主にARFoundationの基礎的な使い方です。
環境
macOS Mojave(バージョン10.14.5)
Unity 2019.2.6f1
Xcode Version 11.1
Q&A
Q1
ARだとキャラクターを元からヒエラルキーに置かずにinstantiateしたりして配置することも多いけれど、そのキャラクターに対する操作はどうやってやればいいの?
誤答例
Assetsからスクリプトに直接キャラクターのプレハブを[Serializefield]などを用いてアタッチして動かす
解説
誤答例のようにしてしまうとゲーム画面には存在しないけど確かにどこかに存在するキャラクターに対しスクリプトの処理を実行してしまうのでinstantiateしたオブジェクトは思い通りに動かないし、エラーメッセージも出ないので意味不明に陥ってしまいます、、、、、正解としてはinstantiateした返り値を用いて処理の実行を行います。以下に例を示します。
character = Instantiate(prefabs[0], trackedImage.transform);
Animator animator = character.GetComponent<Animator>();
上の例だとcharacterにアタッチされているAnimatorを取得しています。このように返り値を通常のゲームオブジェクトと同様に扱うと良いです。
Q2
ボタン押したときに関数を実行したくない?wowwow
誤答例
ゲームオブジェクトのボタンを[Serializefield]使ってアタッチしてなんかやろうとする
解説
ボタンを操作するにはUnityについている機能を使います。onClick()というやつですね。結構時間がかかったので丁寧に説明します。
1. 何らかのGameObjectにアタッチされているスクリプトの中でボタンに紐付けたい関数をpublic属性をつけて宣言する。
public void onClickscreen(){ Debug.Log("HelloWorld"); }
以上のようにします。ゲームオブジェクトの欄にはヒエラルキーからゲームオブジェクトをドラックアンドドロップし、その後、関数を選びます。(選べる関数は自動で出てきます)
以上のようにすると、ボタンが押されたときに指定した関数が呼ばれるようになります。実はとても簡単です。
Q3
IOSにアプリを焼くとUIのレイアウトが思ってたのと違うようになるけどどうすればいいの?
解説
Canvasのinspectorの設定をいじりましょう。(Canvas Scaler)
Canvasの設定をiOSに揃えました。UI Scale ModeはScale With Screen Sizeです。私の開発機のiphone8はx=320,y=568と調べたら出てきました。あと、Matchをwidth=1まで引っ張ると見た目の横の縮尺が合う代わりに縦がおかしくなります。逆も然りです。どうやらUnityのウィンドウ上の横長の長方形はどうにもならないみたいです。(うまい方法があるなら教えて欲しいです)しっかりと合わせたいときはウィンドウで合わせるのではなく数値を設定して合わせましょう。数値の基準は先ほど設定したReference Resolutionです。出来るだけ初期に設定してしまうことをお勧めします。
Q4
スクリプト同士で変数の共有したいけどどうやればいいかわからん!!!publicとかかいとけばいいの??
解説
1. 宣言したいスクリプト内でpublic宣言します。(GameObject hoge内のhogehoge.csとします)
public int flag ;
こんな感じですね。ここで注意なのですが、グローバル領域で初期化してしまうとupdate関数が呼ばれるたびに初期化されてしまうのでやめましょう。startなどの中で初期化しましょう。
2. 別のその変数を使いたいスクリプトでゲームオブジェクト、スクリプトの取得を行う。
[Serializefield] private GameObject hoge; hogehoge hoge_script; void start(){ hoge_script=hoge.GetComponent<hogehoge>(); } void hello(){ hoge_script.flag=1; }
そしてSerializefieldにGameObject hogeをアタッチする。
こうすることでhello関数を実行するとpublicのflagが1に更新されます。まあしかしpublic変数をいたずらに増やすことはバグの原因になるので注意しましょう。
Q5
たくさんのScene使いたい!!
解説
sceneが増えるとアプリっぽくて嬉しいし機能増やしやすくていいですよね。
1. File->new sceneで新しいsceneを作成してsaveし、sceneを作っていく。
2. 変数の共有などをする
[やり方]
変数宣言するシーンで
public static string music_title;
こんな感じでstatic宣言しておく。(関数の外です)
その後変数を利用したいシーン内において
[変数宣言したシーンの名前].music_title
で利用可能です。引き継ぎなどはunity側がやってくれるみたいです。とてもラクチンですね。
Q6
キャラクターにアニメーションつけて、スクリプトで操作したいねー
解説
1. Animator Controllerを作成しEntryから順番に遷移したい順番に右クリックして矢印を生やして繋げる。(Entryから一つ目へは勝手に遷移するので注意)
こんな感じですね。
2. parametersのタブで遷移の条件となるparameterを作成する(今回の画像はbool値で作成しています)
ここで注意ですがbool値の場合チェックが入っていない場合初期値がFalseになります。逆も然りです。
3. 1.で作成した矢印を選択し、矢印の遷移条件を定める。
parameterを使う場合Has Exit Timeはオフで良いそうです。(ここよくわからないので誰か教えてください())
conditionsのところでparameterと遷移の条件を設定します。
4. スクリプトでいじいじする。
Animator animator = character.GetComponent<Animator>(); animator.SetBool("odoru", true);
今回の例だとこんな感じです。
今回はcharacterというゲームオブジェクトにAnimator Controllerがアタッチされているとします。(characterの中にキャラの3dモデルが子として存在しています)
Animatorをゲームオブジェクトから取得した後で、animatorを操作します。parameterの名前はそのまま流用します。意外と簡単です。(時間かかりました)
Q7
UIをデフォルトのものじゃなくてもっと綺麗にしたいな
解説
試行錯誤中
あとがき
Unityよくわかんないですね。今回いわゆる入門本的なものを買わずに(結構高いので)ググってやっているわけですが、↑の内容全部入門書の1章とかに書いてありそうな気がしているのでこれからUnityやる人は本買うなり公式のチュートリアルするなりしたほうがいい気がします。また気づいたことがあったらどんどん追記予定です。間違いあったらどんどん指摘してください。