初めに
皆さんこんばんは~!
クリスマスをいかがお過ごしでしょうか?
クリスマスの定番と言ったら何でしょうか?…そうクソアプリ開発ですよね!!
ということで今回は自分が作ったクリスマスにぴったりのクソアプリとその作り方について紹介していこうと思います
今回作るもの
今回作るもの(作ったもの)はこちらになります。
このアプリについて簡単に説明すると、スマホの画面をタッチした場所に某漫画の人気キャラクターが勇ましいBGMと共に3Dで登場するというものです。
聖夜に作るにふさわしいクソアプリですよね!
Unityでapkファイルとしてこのアプリを作り、それをAndroid(バージョンは7以上ならOK)のスマホで動かしています。
もしこのアプリを自分のスマホで動かしたい方は自分のGitHubのリポジトリからダウンロードしてください
作り方
このアプリは以下のサイトの情報をもとに作りました。
このアプリの作成手順は上記の記事(特に一番目の記事)で詳しく説明されているので、この記事では作成手順については扱いません。しかし、その代わりにこの記事ではこのアプリの動作(挙動)を担うスクリプトを詳しく見ていこうと思います。(スクリプトについて興味がない方は読み飛ばしてしまって大丈夫です!)
アプリの動作(挙動)を担うスクリプト
そのスクリプトは以下の通りです。コメントアウト部分は解説用につけたものや元から書いてあるのを消し忘れたものなので、気にしなくてよいです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems; // .......(1)
public class PlaneDetection : MonoBehaviour
{
ARRaycastManager raycastManager;
[SerializeField] GameObject obj;
AudioSource audioSource;
[SerializeField] AudioClip sound1; // .......(2)
// Start is called before the first frame update
private void Awake() // .......(3)
{
raycastManager = GetComponent<ARRaycastManager>();
audioSource = GetComponent<AudioSource>();
audioSource.clip = sound1;
}
// Update is called once per frame
private void Update() // .......(4)
{
if(Input.touchCount == 0 || Input.GetTouch(0).phase != TouchPhase.Ended || obj == null)
{
return;
}
var hits = new List<ARRaycastHit>();
if(raycastManager.Raycast(Input.GetTouch(0).position, hits, TrackableType.Planes))
{
var hitPose = hits[0].pose;
Instantiate(obj , hitPose.position, hitPose.rotation);
audioSource.Play();
}
}
}
ここからはコメントアウトとして付け加えた番号順でこのスクリプトの解説をしていきます。(このアプリの作成を通じて初めてC#を触れた身ですので、解説がガバいところがあります)
(1)まずは宣言されている名前空間の確認をします。
-
System.CollectionsおよびSystem.Collections.GenericはC#においてコレクションの利用のために宣言されています。コレクションとは配列よりも縛りの緩い要素の集合体です。(自分が使用してきたPHPやJSだと要素の集合体にコレクションや配列という区別がなく、基本的には要素の集合体=配列です) -
UnityEngineにはUnit内の要素の操作に必要なものが含まれていて、この名前空間内のMonoBehaviourクラスやInputクラスの利用のためには宣言必須のものとなっています。 -
UnityEngine.XR.ARFoundationには3Dオブジェクトを表示する場所の検知するクラスなどが含まれており、ARを利用する上では必須のものとなっています。 -
UnityEngine.XR.ARSubsystemsには検知する場所の形状を表す定数などが含まれており、こちらもARを利用する上では必須のもの(?)となっています。
(2)次に継承するクラスや初めに宣言する変数について見ていきます。
-
PlaneDetectionクラスが継承しているのはMonoBehaviourクラスというものであり、このクラスを継承することで継承先のクラスはUnity内のオブジェクトのコンポーネントが参照できるGetComponentメソッドやUnityの世界内に新たなオブジェクトを配置するInstantiateメソッドが使えるようになります。
変数raycastManagerは後程行われるUnityEngine.XR.ARFoundation内のARRaycastManagerクラスのインスタンスの代入のために宣言されます。 - 変数
objにはこのアプリで表示するオブジェクトが入ります。変数の前に[SerializeField]と書くことで、Unityのインスペクターウィンドウから表示したいオブジェクトを指定できます。 - 変数'audioSource'は後程行われる
UnityEngine内のAudioSourceクラスのインスタンスの代入のために宣言されます。 - 変数
sound1には再生したい音声ファイルが入ります。これもUnityのインスペクターウィンドウから表示したいオブジェクトを指定できます。
(3)そして今度はAwakeメソッドを見ていきます。AwakeメソッドはMonoBehaviourクラスが所有するメソッドで、このスクリプトが実行される際に最も早く、そして一度だけ行われるメソッドです。
-
GetComponentメソッドを使用し、変数raycastManager、audioSourceにそれぞれGameObject内のコンポーネントであるAR Raycast Manager、Audio Sourceが代入されます。ちなみにGetComponentの横にある<>はジェネリックと呼ばれ、これによりこの中に書かれた型に対応したクラスを返してくれるそうです。(PHPにはこんな簡単に返り値の型を指定できる方法が(おそらく)ないので良いな~) -
audioSourceのclipプロパティに先ほどセットしたsound1を代入します。
(4)最後にUpdateメソッドを見ていきます。UpdateメソッドもAwakeメソッドと同様にMonoBehaviourクラスが所有するメソッドで、このアプリの毎フレームごとに呼び出されます。公式サイトでは、Not every MonoBehaviour script needs Update.と書かれていたので、Unityの動作をつけるうえでは基本となるメソッドのようです。
- 最初のif文では、
Inputクラスを使用してアプリの使用者が画面のタッチを行る状態の場合かつ表示するオブジェクトが指定されている場合のみ次のステップへ進み、それ以外は何もしません。 - 変数
hitsにSystem.Collections.Generic内のListクラスによってコレクション化されたARRaycastHitが代入されます。ARRaycastHitにはアプリ内のオブジェクトを表示する場所の位置情報などが書き込まれます。 - 二つ目のif文では
ARRaycastManagerクラスのRaycastメソッドを使用し、アプリ内でオブジェクトが配置可能な場所に使用者がタッチした場合次のステップへ進み、そうでない場合は何もせずに次のUpdateメソッドへ進みます。Raycastメソッドについてもう少し詳しく言うと、第一引数Input.GetTouch(0).positionが第三引数TrackableType.Planesにおいて検知可能とされた場合に、その位置情報を第二引数のhitsへ渡すという感じです。 -
Raycastメソッドで渡された位置情報を変数hitPoseへ代入し、第2、3引数にその情報による場所と表示する向き、そして第1引数に表示するオブジェクトがセットされたInstantiateメソッドが実行され、アプリ内にオブジェクトが表示されます。 - 一番最後に
AudioSourceクラスのPlayメソッドが実行され、変数sound1としてセットした音声ファイルが鳴ります。
終わりに
初めてUnityやC#を触り、またWebアプリしか作ってこなかったにも関わらず簡単にAndroidで動くアプリを作れて感動しました。
今度はARマーカーを使ったアプリやWebで動くARアプリなんかも作れたらな~と考えています。