20191009のUnityに関する記事は8件です。

Unity玉転がしチュートリアル 2-1.カメラの移動

この記事の対象者

  • Unity入門したい人
  • 最初の一歩が踏み出せない人

OSとか環境とか

  • Windows 10 Pro
  • macOS Mojave
  • Unity 2019.2.8f1
  • Rider 2019.2.2

補足

  • 公式動画にて利用しているのはMacなので、Windowsユーザーはある程度脳内変換して見る事
  • 筆者はWindows、Macの両方の環境で確認。Ubuntuとかでは検証してない。
  • 基本Unityは英語メニューで利用
  • 間違いがあったらツッコミ大歓迎

公式

https://unity3d.com/jp/learn/tutorials/projects/roll-ball-tutorial/moving-camera

カメラの移動

現状のままだとカメラが固定なので、プレイヤーオブジェクトが非常に見づらい
→カメラとプレイヤーオブジェクトを紐付ければ万事解決じゃない?

下準備としてカメラの位置調整

PositionのYを10,Zを-10
RotationのXを45
に調整して、少し上から見下ろす形にする

image.png

Playerの子としてMainCameraを設定

image.png

この状態にすると、Playerオブジェクトが動かした場合(移動や回転)Main Cameraも一緒に移動する
※上記設定後「あー余裕だわー」とPlayして玉を動かすと高速なラートみたいな視点になるので落ち着きましょう

カメラとプレイヤーの関係性

あくまで「プレイヤーの子としてカメラが設定された」だけで、相対的な位置関係は変わっていない
なので
・親のSphereオブジェクトが動く
→回転して移動する
・子のMain Cameraオブジェクトが動く
→親のSphereオブジェクトに連動して同じく「回転」する

なので、Main CameraがSphereの子の状態だと視点がラートになる
カメラとプレイヤーはスクリプトで紐付ける必要がある

カメラへのスクリプトの追加

CameraControllerという名前でスクリプトを追加します
※カメラとスクリプトの紐付けは行っている事

追加するスクリプトは以下

CameraController.cs
using System.Collections;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    public GameObject player;
    private Vector3 offset;

    void Start()
    {
        offset = transform.position - player.transform.position;
    }

    void LateUpdate()
    {
        transform.position = player.transform.position + offset;
    }
}

内容については単純なので割愛

ポイントとしては、毎フレーム処理する時にUpdateを使わずにLateUpdateを利用する事

ライフサイクルだとGame Logicに当たる箇所の

image.png

はじめに呼ばれるのがUpdate
最後に呼ばれるのがLateUpdate
となる

真・カメラとプレイヤーの紐付け

スクリプトを保存して、UnityエディタでCameraControllerのPlayer部分を見ると「None」となっているので紐付け

image.png

紐付ける方法は動画ではPlayerオブジェクトをドラッグしているが、フィールドの右にある小さい○をクリックして
出てくるダイアログで選択してもOK

これでPlayをすると、ボールの動きを追従するカメラの出来上がりとなる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityのCreator Kit: PuzzleをVR空間内でPuzzleの配置ができるようにする

はじめに

前回記事 UnityのCreator Kit: PuzzleをOculusQuestで動かしてみる の続きです。

前回記事では、既存のPuzzleが配置されたシーンを動かすところまででしたが、今回、Puzzleのオブジェクトを自由に配置できるようにしました。
元のコードではPuzzleを配置する機能はエディター拡張機能を使用して実装されているのですが、VR空間内で動作させるためにはエディター拡張機能は使用できないため、この部分のコードは新規に作成する必要がありました。
ソースコードはGitHubのCreatorKitPuzzleに置いています(前回記事から更新しました)。

開発環境

Unity 2019.2.4f1
Creator Kit: Puzzle - 1.1
Oculus Integration for Unity - 1.40
VrGrabber-v0.0.3 (hecomi氏作)
DotNetZip-v1.9

ビルド手順

  1. GitHubのCreatorKitPuzzle からcloneでファイルをローカルに持ってきます。
  2. 持ってきたファイルを指定してUnityでプロジェクトを開きます。
  3. Build Settings から Platform を Android に Switch Platformします。
  4. Oculus Integrationをアセットストアからダウンロードし、インポートします。
  5. Creator Kit: Puzzleをアセットストアからダウンロードし、インポートします。インポートする際、すべてインポートしてしまうとプロジェクトの設定が上書きされてしまうため、ProjectSettingsのチェックを外します。image.png
  6. オブジェクトをつかむためのアセットVrGrabberをVrGrabber からダウンロードし、インポートします。自分がダウンロードしたファイルは"VrGrabber-v0.0.3.unitypackage"ですが、数字の部分はバージョンにより変わります。
  7. OculusQuest向けに変更したシーンLevelFreeを開きます。image.png
  8. OVRCameraRigのTarget DevicesをQuestに変更します。image.png
  9. ビルドするシーンを選択し、Build Settings からビルドします。image.png

操作方法

・左側コントローラー
スティック 前後移動、左右方向転換

・右側コントローラー
スティック つかんだPuzzleのオブジェクトの操作
スティック押下 オブジェクトを消去(オブジェクトをつかんでいる状態の時)
B UIの表示切り替え
A ハンマー、フリッパー等稼働するオブジェクトの操作/UI上での選択
IndexTrigger オブジェクトの生成
HandTrigger オブジェクトをつかむ

改造方法の検討

Puzzleを配置する機能を実現するために、以下のことができればよさそうと考えました。
・配置できるPuzzleを表示し、選択する機能
・選択したPuzzleを生成し、自由に配置する機能
・配置をセーブ・ロードする機能

さらに各機能について以下のように検討しました。

配置できるPuzzleを表示し、選択する機能

元のプロジェクトにPuzzleのPrefabが含まれているので、それをシーンに一度配置して、後で検索できるようにタグをつけます。FindGameObjectsWithTagで検索したオブジェクトをリスト化してUIに表示し、選択できるようにします。(グラフィカルなプレビュー画面があるほうがわかりやすいのですが、とりあえずはオブジェクトの名前のテキストで表示します)
リスト化が終わったら、シーンに配置したオブジェクトを無効化して見えなくします(最初は有効にしておかないと検索できないので)。

選択したPuzzleを生成し、自由に配置する機能

選択したPuzzleをInstantiateでインスタンス化します。配置するときは勝手に動いてほしくないので、RigidbodyのuseGravity=falseに、isKinetic=trueに設定しておきます。
インスタンス化した後、Puzzleを動かす方法はVrGrabberの機能をそのまま使用します。このためにPuzzleのPrefabにはあらかじめVrgGrabbableコンポーネントをつけておきます。また、消去する機能を実現するために、VrgGrabbableコンポーネントのOn Grab Clickedには消去するためのスクリプトを設定しておきます。

配置をセーブ・ロードする機能

Unityでデータを保存する機能としてはPlayerPrefsがありますが、今回のように保存するデータが大きくなる可能性がある用途には向かなさそうでした。手順としてはC#オブジェクトからJsonに変換し、System.IO等でファイルに保存すればよさそうということがわかりましたが、色々調べたところ、@tricrow氏の記事Unityでユーザーデータをローカルにファイルとして保存するが私にはわかりやすかったため使用させていただくことにしました(自分の使い方ではコードを変更する箇所がなく、全くのコピペです)。
1点、現在では圧縮に使用しているライブラリDotNetZipのファイルを入手する方法が難しく(わかりにくく)なっており、CodePlexからバイナリを入手を参考にさせていただきました。DotNetZipのライセンスはMicrosoft Public License (MS-PL)となっています。また、バイナリをAssets\Plugins\DotNetZipに置いています。
Jsonへの変換にはJsonUtilityを使用していますが、変換可能なオブジェクトには色々と制約があります。最初知らずにPuzzleのオブジェクトを突っ込んでいたらうまくいかず、結構はまりました。最終的には、オブジェクトの名前と位置だけを保存し、復元するときはそれをもとに再度インスタンス化するようにしました。この辺りは実機上でデバッグするのは難しく、PC上で実行して生成されたJsonを確認(自分はVisual Studio Codeを使いました)を繰り返しました。

GitHubに置いたソースコードについて

DebugUIBuilderHand.csは、Oculus Integrationに含まれているDebugUIBuilder.csをもとに改変したもののため、ライセンスはOculus Integrationに従います(Assets\Oculus\SampleFramework\license.txtをご確認ください)。
IDataFile.cs, DataFilePlain.csは、@tricrow氏の記事Unityでユーザーデータをローカルにファイルとして保存する中に記載されているコードをそのまま持ってきたものです。
そのほかのソースコードはCC0としますので好きなようにご使用ください。
PlayUI.csは、Puzzleの操作に関するUIを構築するためのもので、Puzzleを配置する機能はほとんどこのコードで実装しています。DebugUI.csは、デバッグ用の情報を表示するためのUIを構築するためのもので、DebugMover.csは、キャラクターを操作するためのものです。

制限事項

以下既知の問題があります。
・オブジェクトを消去すると、アプリが落ちることがあります。
・複数のパーツで構成されたオブジェクトを移動するとバラバラになることがあります。
・ボールに映る映像には配置したオブジェクトは反映されません。
・Restartすると配置モードに戻ります。
・Restartするとログが更新されなくなります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[随時更新]超初心者がUnityで気を付けること

プログラミング全般

・ちゃんとした変数名、関数名をつけよう。void Test()とかint countとか作っちゃだめだぞ

GameObject関係

・GameObject.Findは重いから使わない(使っても精々Start、Awake系だけ)

Transform関係

・transform.rotationは理解できるまで触らない
Quatanionは複雑な値なので、RotateやeulerAnglesを使おう

・scaleの比率を1:1:1以外にした上で回転させると予想外のことが起きやすい。やめとこう。

・transform.Findで参照できるのは直近の子供だけ
全ての子供を取りたい時はGetComponentsInChildren()を使おう(Tは欲しいクラス。Transformも取れる)。ただし重い。

・子の中の、常に特定の物を取りたいなら、transform.GetChild()を使うとよい

その他

別PCにプレハブを移動させたい時は、Assets/ExportPackageからパッケージにして持っていこう

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity玉転がしチュートリアル 1-2.プレイヤーの移動

この記事の対象者

  • Unity入門したい人
  • 最初の一歩が踏み出せない人

OSとか環境とか

  • Windows 10 Pro
  • macOS Mojave
  • Unity 2019.2.8f1
  • Rider 2019.2.2

補足

  • 公式動画にて利用しているのはMacなので、Windowsユーザーはある程度脳内変換して見る事
  • 筆者はWindows、Macの両方の環境で確認。Ubuntuとかでは検証してない。
  • 基本Unityは英語メニューで利用
  • 間違いがあったらツッコミ大歓迎

公式のリンク

https://unity3d.com/jp/learn/tutorials/projects/roll-ball-tutorial/moving-player

プレイヤーの移動

追加したSphereがキーボードで動く様に調整する

移動時の条件

・ゲームエリア全体を転がる
・壁にぶつかる
・常に接地している(宙に浮かない)
・アイテムに接触したらアイテムを取得する

→物理演算が必要
Rigidbodyコンポーネントをアタッチする必要がある

アタッチする方法

  1. アタッチする対象のゲームオブジェクトを選択(今回はPlayerゲームオブジェクト)
  2. Component>Physics>Rigidbodyを選択

rigidbody.png

上記のようにアタッチされる
アタッチした要素は並び替えが可能となるので、要素が増えたりしたら並び替え等でキレイキレイする

キーボードの入力について

動きを制御するスクリプトをアタッチして実現する

スクリプトを格納するフォルダ「Scripts」を作成し、その中にスクリプトを格納するのが良い

追加方法は何個かあるのだが、今回は「Add Component」から追加する方法が有効
メニューよりNew Scriptという項目から追加
→スクリプトを別で用意しても良いが、そのスクリプトをアタッチする手間が省けるので楽
PlayerControllerという名前でスクリプトを追加

NewScript.png

これでこのPlayerオブジェクトにスクリプトがアタッチされる

スクリプトの記述

基本スクリプトファイルをダブルクリックして紐付いたエディタが起動する

※筆者はRiderを使ってコーディングするので、Riderが起動するが、こだわりがなければVisualStudio2019 Communityあたりが起動する

PlayerController.csの記述方法等については動画参照の事ですが何点か補足

  • 動画でも説明されているが、**公式のドキュメントを読むのは基本

 Unityに限った事ではないので、なんか文字沢山書いてあるなーと思わないで
 公式のドキュメントはちゃんと読みましょう!
 何なら公式ドキュメントの読み方も超丁寧に動画にしてくれている
 Just Do It!

  • ライフサイクル

https://docs.unity3d.com/ja/2019.1/Manual/ExecutionOrder.html
を参照すれば良さそう

出来上がったものがこちら!

PlayController.cs
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float speed;
    public Rigidbody rb;
    // See also:https://docs.unity3d.com/ja/2019.1/Manual/ExecutionOrder.html

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    private void FixedUpdate()
    {
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");

        Vector3 movement = new Vector3(moveHorizontal,0.0f,moveVertical);
        rb.AddForce(movement * speed);
    }

}

Publicで定義した変数はUnityのエディタ内で直接値を編集出来るのが特徴的なので覚えておく事

public.png

これでボールの制御が出来るようになるので大勝利

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity iOS/Androidで位置情報を取得する

Unity上のiOS/Androidで位置情報を取得とiOS/Androidのパーミッションまわりについて試して見たことを記載します。

Unity公式の位置情報取得のサンプルコード

Unity公式の位置情報取得のサンプルコードのコメントを訳したものを下記に記載します。

このコードでも位置情報を取得できますが、Unityの位置情報の取得を管理するクラスLocationServiceがシンプルすぎて、iOS/Androidの位置情報取得の可否の状態によってどういう挙動をするのかがドキュメントからは不明瞭なので、本記事ではそのあたりを実機を動かして確認していきます。

using UnityEngine;
using System.Collections;

public class TestLocationService : MonoBehaviour
{
    IEnumerator Start()
    {
        // 最初に、ユーザーがロケーションサービスを有効にしているかを確認する。無効の場合は終了する
        if (!Input.location.isEnabledByUser)
            yield break;

        // 位置を取得する前にロケーションサービスを開始する
        Input.location.Start();

        // 初期化が終了するまで待つ
        int maxWait = 20; // タイムアウトは20秒
        while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
        {
            yield return new WaitForSeconds(1); // 1秒待つ
            maxWait--;
        }

        // サービスの開始がタイムアウトしたら(20秒以内に起動しなかったら)、終了
        if (maxWait < 1)
        {
            print("Timed out");
            yield break;
        }

        // サービスの開始に失敗したら終了
        if (Input.location.status == LocationServiceStatus.Failed)
        {
            print("Unable to determine device location");
            yield break;
        }
        else
        {
            // アクセスの許可と位置情報の取得に成功
            print("Location: " + Input.location.lastData.latitude + " "
                               + Input.location.lastData.longitude + " "
                               + Input.location.lastData.altitude + " "
                               + Input.location.lastData.horizontalAccuracy + " "
                               + Input.location.lastData.timestamp);
        }

        // 位置の更新を継続的に取得する必要がない場合はサービスを停止する
        Input.location.Stop();
    }
}

動作環境

  • Unity 2018.4f8 Mac版
  • XCode 11.0

各OSの位置情報取得の許可の状態について

iOSとAndroidのOSごとの位置情報取得の許可の状態について下記で記載します。
UnityではこのあたりがLocationServiceによって抽象化されてしまっています。

iOS

CLAuthorizationStatusに記載されているように、下記の5状態が存在します。

  • notDetermined - ユーザーは未選択
  • restricted - 許可されていない(ユーザーは特に拒否していないが何らかの理由で使用できない場合)
  • denied - ユーザーは拒否
  • authorizedAlways - 常に許可
  • authorizedWhenInUse - アプリの使用中のみ許可

notDetermined

ユーザーはアプリで位置情報サービスを使用できるかどうかを選択していない。

位置情報取得の確認ダイアログをまだ表示したことがないのがこの状態。

iOS 13.2.1での位置情報取得の確認ダイアログ
位置情報取得の確認ダイアログ

restricted

アプリは位置情報サービスの使用を許可されていない。

ユーザーは位置情報サービスの使用を特に拒否していないが、何らかの理由で使用できない場合にこの状態になるはず。
「設定 > プライバシー > 位置情報サービス」で位置情報サービスをオフにした場合はこの状態(iOS 13.1.2で確認)。

denied

ユーザーがアプリの位置情報サービスの使用を拒否したか、設定でグローバルに無効化されている。

位置情報の取得確認ダイアログで拒否を選択したか、「設定 > プライバシー > 位置情報サービス」で「なし」を選択したかのどちらかがこの状態。

authorizedAlways

ユーザーは、いつでも位置情報サービスを開始することをアプリに許可した。

位置情報の取得確認ダイアログで「常に」を選択するとこの状態になる。アプリがバックグラウンドにいてもアプリは位置情報が取得可能。

authorizedWhenInUse

ユーザーは、アプリが使用中に位置情報サービスを開始することを承認した。

位置情報の取得確認ダイアログで「使用中のみ」を選択するとこの状態になる。アプリがフォアグラウンドの状態でのみアプリは位置情報が取得可能。

Android

下記の3状態が存在する。

  • 未選択・1度だけ拒否
  • 許可済み
  • 拒否

未選択・1度だけ拒否

ユーザーはアプリで位置情報を使用できるかどうかを選択していない。
または、アプリで位置情報を使用を許可していない。

位置情報取得の確認ダイアログをまだ表示したことがないのがこの状態。
または、位置情報取得の確認ダイアログで拒否を選択したのがこの状態。

Android 9での位置情報取得の確認ダイアログ
位置情報取得の確認ダイアログ

許可済み

ユーザーは位置情報サービス使用することをアプリに許可した。

位置情報取得の確認ダイアログで許可を選択したのがこの状態。

拒否

アプリで位置情報を使用を許可していない。

位置情報取得の確認ダイアログで「今後表示しない」を選択したのがこの状態。

Android 9での位置情報取得の確認ダイアログで「今後表示しない」のチェックが存在するもの
位置情報取得の確認ダイアログで「今後表示しない」のチェックが存在するもの

位置情報取得の許可ごとの挙動について

LocationService.isEnabledByUser

LocationService.isEnabledByUser
ユーザーが位置情報サービスを有効にするかどうか。

iOS

「設定 > プライバシー > 位置情報サービス」で位置情報サービスをオフにした場合にfalseが返る。
位置情報の許可の有無とは関係なさそう。

状態 LocationService.isEnabledByUserの返値
notDetermined true
restricted false
denied true
authorizedAlways true
authorizedWhenInUse true

Android

状態 LocationService.isEnabledByUserの返値
未選択・1度だけ拒否 false
許可済み true
拒否 false

LocationService.Start

LocationService.Start
位置情報サービスの更新を開始します。
LocationService.Startを呼び出し後、LocationService.statusLocationServiceStatus.Runningになったら、LocationService.lastDataより位置情報を取得できます。

iOS

状態 LocationService.Start呼び出し後の動作
notDetermined 位置情報の取得の確認ダイアログが表示される。
restricted "位置情報を利用できるようにするには、位置情報をサービスをオンにしてください"というダイアログが表示される。LocationService.statusはFailedになる。
denied LocationService.statusはFailedになる。
authorizedAlways LocationService.statusはRunningになる。
authorizedWhenInUse LocationService.statusはRunningになる。

位置情報の取得の確認ダイアログで許可を選択した場合に、LocationService.statusRunningとなる。

"位置情報を利用できるようにするには、位置情報をサービスをオンにしてください"のダイアログ
"位置情報を利用できるようにするには、位置情報をサービスをオンにしてください"のダイアログ

Android

状態 LocationService.Start呼び出し後の動作
未選択・1度だけ拒否 位置情報の取得の確認ダイアログが表示される。LocationService.statusはStoppedのままで、許可を選択するとLocationService.isEnabledByUserはtrueになる。
許可済み LocationService.statusはRunningになる。
拒否 LocationService.statusはStoppedになる。

位置情報の取得の確認ダイアログで許可を選択しても、LocationService.isEnabledByUserはtrueになるがLocationService.statusの状態に変化はない。
位置情報を取得する場合はもう一度LocationService.Startを呼ぶ必要がありそう。

LocationService.Stop

LocationService.Stop
位置情報サービスの更新を停止します。

iOS/Android

LocationService.statusStoppedになります。
LocationService.lastDataの値が更新されなくなります。

まとめ

  • iOSは「設定 > プライバシー > 位置情報サービス」がオンかオフかはLocationService.isEnabledByUserを見れば分かる
  • iOSはアプリの位置情報取得が許可されているかどうかはあらかじめ分からない。LocationService.Startを呼んだ挙動で判定するしかなさそう。
  • iOSアプリは位置情報取得の許可ダイアログが表示されるかどうかはあらかじめ分からない。LocationService.Startを呼んだときにOSにより位置情報取得の許可ダイアログが表示される。

  • Androidはアプリの位置情報取得が許可されているかどうかはLocationService.isEnabledByUserを見れば分かる

  • Androidアプリは位置情報取得の許可が無い場合(LocationService.isEnabledByUserがfalseの場合)に、位置情報取得の許可ダイアログが表示されるかどうかはあらかじめ分からない。LocationService.Startを呼んだときにOSにより位置情報取得の許可ダイアログが表示される。

位置情報が取得できるかどうかをiOSとAndroidの両方に対応しようとすると、LocationService.Startを呼んだ上でLocationService.statusの値がどうなるかを監視するくらししかなさそうです。

コード

https://github.com/yhirano/UnityLocationServiceResearch

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity AddressableAssetSystemの使用方法

はじめに

実装したソースはこちら
https://github.com/zi-su/ScriptLibrary/tree/master/Editor

Unityではアセット管理としてAssetBundleがあります。
このAssetBundleを使い膨大なアセットをまとめてアセット管理を行ってきました。
そのためにそれぞれAssetBundleManagerクラスを作成していたと思います。UnityがAssetBundleManagerを提供していましたが現在ではサポートされておりません。
https://bitbucket.org/Unity-Technologies/assetbundledemo/src/default/
AssetBundleクラス自体は低レベルなクラスであり、実際のゲーム開発で使いやすくするために拡張が必要です。
オレオレAssetBundleManagerを作り出すと参照カウント付きクラスで隠蔽したり、依存バンドルを調べてロード・アンロード処理を書いたりすることが必要です。

こういった面倒な実装とAssetBundleの仕組みをもっと楽にしようということでAddressableAssetSystem(AAS)が作られました。
https://blogs.unity3d.com/jp/2019/07/15/addressable-asset-system/
Unity2018.3以降では使用可能ということです。
このAddressableAssetSystemの使い方、機能、ゲーム開発に使えるのかを調べていきます。

使用したバージョン

Addressables ver1.2.4
Unity 2019.3.0b4

AddressableAssetSystemとは

公式ドキュメント

まずは公式ドキュメントです。
一次ソースを調べることは何より重要です。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/manual/index.html
UniteTokyo2018の講演
https://learning.unity3d.jp/355/

GettingStartedを読めば最低限の導入まではできます。
1. PackageManagerからAddressablesをインストール
2. 初期化ウィンドウが出るので初期化
3. 各アセットのインスペクタでアドレスを指定
4. Window->AssetManagement->Addressablesを開く
5. 各アセットをグループに分ける
6. BuildからBuildPlayerContentでアセットバンドルを作成

GettingStartedだけではロード処理しか書いていないのでこのままではメモリに残り続けます
ReleaseやメモリについてはMemoryManagementを読みます。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/manual/MemoryManagement.html

実際に使用する

AASをゲーム開発で使用するケースを考えます。
マニュアルやスライドを見ているとAASの各種設定は
Window->AssetManagement->Addressablesのメニューから行っています。
GUI上でグループを作成しアセットをグループへドラッグアンドドロップすることはとてもわかりやすいです。サンプルで数十ファイルの間は。

膨大なアセット数

ゲームに使用するアセットは軽く数百を超えていき、数万アセットにもなることがあります。
数万を超えるアセット数に対してこの手順は人間がするものではありません

多くの場合アセットを保存しているルートディレクトリからのパスでグループ化しフォルダ内のアセットはそのグループに属するといった設定になるでしょう。
アセットインポート時にグループの作成とグループへの追加を実装する方法がないか、APIドキュメントを読んで探します
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/api/index.html

AddressableAssetSettings

最初にAddressablesメニューを開くときに作成されたAddressableAssetSettings.assetを選択したときのインスペクタを見ます。名前からしてAASに関する設定を持っていそうです。
Groupsを開くと自分で作成したグループが追加されていることがわかります。
他にもいろいろな設定があります。
インスペクタ上で歯車をクリックするとEditScriptが表示されるのでスクリプトを確認するとScriptableObjectであることがわかります。
APIドキュメントを見るとグループの追加やアセットの登録に必要な機能があることがわかります。(CreateGroupやCreateOrMoveEntry)
このScriptableObjectを取得してきます。

//アドレサブルアセットセッティング取得
var s = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEditor.AddressableAssets.Settings.AddressableAssetSettings>(
"Assets/AddressableAssetsData/AddressableAssetSettings.asset"
);

グループ作成の自動化

取得してきたAddressableAssetSettingsスクリプトを使用してグループ作成をします。
APIはCreateGroupを使用します。
APIドキュメントを見て引数を調べます。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/api/UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.html#UnityEditor_AddressableAssets_Settings_AddressableAssetSettings_CreateGroup_System_String_System_Boolean_System_Boolean_System_Boolean_System_Collections_Generic_List_UnityEditor_AddressableAssets_Settings_AddressableAssetGroupSchema__System_Type___
変わった引数でschemasToCopyがあります。
何を設定するのか迷いますがAddressablesメニューのDefaultLocalGroupと同じ設定にするには
//スキーマ生成
List<UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema> schema = new List<UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema>() {
new UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema(),
new UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema()
};

というリストを指定します

アセットをグループへ追加・削除

各アセットを作成したグループへ追加しなければアセットバンドルに含まれません。
APIはCreateOrMoveEntryを使用します。
APIドキュメントを見て引数を調べます。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/api/UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.html#UnityEditor_AddressableAssets_Settings_AddressableAssetSettings_CreateOrMoveEntry_System_String_UnityEditor_AddressableAssets_Settings_AddressableAssetGroup_System_Boolean_System_Boolean_
guidとtargetParentでアセットのGUIDとグループを指定するだけで良さそうです。
guidはAssetPathToGUIDで取得できます
//アセットGUIDを取得
var assetGuid = UnityEditor.AssetDatabase.AssetPathToGUID("Assets/Data/hogeMat.mat");

自動ビルド

UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.BuildPlayerContent();
を呼ぶだけでビルドしてくれます。
アセットバンドルビルドスクリプトを自作していた時のことを思い出すとこれだけで感動します。

おわりに

AddressableAssetSystemはゲーム開発に使用する機能も揃っているようです。
AssetBundleManagerを使用してビルドスクリプトを自作してといった旧時代の遺物は捨て去り、Unity2018.3以降はAddressableAssetSystemを使用していきましょう。
どんどん使用されていき知見が溜まっていくことを期待してます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity AddressableAssetSystemの使用方法と自動化の機能調査

はじめに

実装したソースはこちら
https://github.com/zi-su/ScriptLibrary/tree/master/Editor

Unityではアセット管理としてAssetBundleがあります。
このAssetBundleを使い膨大なアセットをまとめてアセット管理を行ってきました。
そのためにそれぞれAssetBundleManagerクラスを作成していたと思います。UnityがAssetBundleManagerを提供していましたが現在ではサポートされておりません。
https://bitbucket.org/Unity-Technologies/assetbundledemo/src/default/
AssetBundleクラス自体は低レベルなクラスであり、実際のゲーム開発で使いやすくするために拡張が必要です。
オレオレAssetBundleManagerを作り出すと参照カウント付きクラスで隠蔽したり、依存バンドルを調べてロード・アンロード処理を書いたりすることが必要です。

こういった面倒な実装とAssetBundleの仕組みをもっと楽にしようということでAddressableAssetSystem(AAS)が作られました。
https://blogs.unity3d.com/jp/2019/07/15/addressable-asset-system/
Unity2018.3以降では使用可能ということです。
このAddressableAssetSystemの使い方、機能、ゲーム開発に使えるのかを調べていきます。

使用したバージョン

Addressables ver1.2.4
Unity 2019.3.0b4

AddressableAssetSystemとは

公式ドキュメント

まずは公式ドキュメントです。
一次ソースを調べることは何より重要です。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/manual/index.html
UniteTokyo2018の講演
https://learning.unity3d.jp/355/

GettingStartedを読めば最低限の導入まではできます。
1. PackageManagerからAddressablesをインストール
2. 初期化ウィンドウが出るので初期化
3. 各アセットのインスペクタでアドレスを指定
4. Window->AssetManagement->Addressablesを開く
5. 各アセットをグループに分ける
6. BuildからBuildPlayerContentでアセットバンドルを作成

GettingStartedだけではロード処理しか書いていないのでこのままではメモリに残り続けます
ReleaseやメモリについてはMemoryManagementを読みます。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/manual/MemoryManagement.html

実際に使用する

AASをゲーム開発で使用するケースを考えます。
マニュアルやスライドを見ているとAASの各種設定は
Window->AssetManagement->Addressablesのメニューから行っています。
GUI上でグループを作成しアセットをグループへドラッグアンドドロップすることはとてもわかりやすいです。サンプルで数十ファイルの間は。

膨大なアセット数

ゲームに使用するアセットは軽く数百を超えていき、数万アセットにもなることがあります。
数万を超えるアセット数に対してこの手順は人間がするものではありません

多くの場合アセットを保存しているルートディレクトリからのパスでグループ化しフォルダ内のアセットはそのグループに属するといった設定になるでしょう。
アセットインポート時にグループの作成とグループへの追加を実装する方法がないか、APIドキュメントを読んで探します
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/api/index.html

AddressableAssetSettings

最初にAddressablesメニューを開くときに作成されたAddressableAssetSettings.assetを選択したときのインスペクタを見ます。名前からしてAASに関する設定を持っていそうです。
Groupsを開くと自分で作成したグループが追加されていることがわかります。
他にもいろいろな設定があります。
インスペクタ上で歯車をクリックするとEditScriptが表示されるのでスクリプトを確認するとScriptableObjectであることがわかります。
APIドキュメントを見るとグループの追加やアセットの登録に必要な機能があることがわかります。(CreateGroupやCreateOrMoveEntry)
このScriptableObjectを取得してきます。

//アドレサブルアセットセッティング取得
var s = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEditor.AddressableAssets.Settings.AddressableAssetSettings>(
"Assets/AddressableAssetsData/AddressableAssetSettings.asset"
);

グループ作成の自動化

取得してきたAddressableAssetSettingsスクリプトを使用してグループ作成をします。
APIはCreateGroupを使用します。
APIドキュメントを見て引数を調べます。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/api/UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.html#UnityEditor_AddressableAssets_Settings_AddressableAssetSettings_CreateGroup_System_String_System_Boolean_System_Boolean_System_Boolean_System_Collections_Generic_List_UnityEditor_AddressableAssets_Settings_AddressableAssetGroupSchema__System_Type___
変わった引数でschemasToCopyがあります。
何を設定するのか迷いますがAddressablesメニューのDefaultLocalGroupと同じ設定にするには
//スキーマ生成
List<UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema> schema = new List<UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema>() {
new UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema(),
new UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema()
};

というリストを指定します

アセットをグループへ追加・削除

各アセットを作成したグループへ追加しなければアセットバンドルに含まれません。
APIはCreateOrMoveEntryを使用します。
APIドキュメントを見て引数を調べます。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/api/UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.html#UnityEditor_AddressableAssets_Settings_AddressableAssetSettings_CreateOrMoveEntry_System_String_UnityEditor_AddressableAssets_Settings_AddressableAssetGroup_System_Boolean_System_Boolean_
guidとtargetParentでアセットのGUIDとグループを指定するだけで良さそうです。
guidはAssetPathToGUIDで取得できます
//アセットGUIDを取得
var assetGuid = UnityEditor.AssetDatabase.AssetPathToGUID("Assets/Data/hogeMat.mat");

自動ビルド

UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.BuildPlayerContent();
を呼ぶだけでビルドしてくれます。
アセットバンドルビルドスクリプトを自作していた時のことを思い出すとこれだけで感動します。

おわりに

AddressableAssetSystemはゲーム開発に使用する機能も揃っているようです。
AssetBundleManagerを使用してビルドスクリプトを自作してといった旧時代の遺物は捨て去り、Unity2018.3以降はAddressableAssetSystemを使用していきましょう。
どんどん使用されていき知見が溜まっていくことを期待してます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity Addressable Asset Systemの使用方法と自動化の機能調査

はじめに

実装したソースはこちら
https://github.com/zi-su/ScriptLibrary/tree/master/Editor
AASUtility.csにまとめています。

Unityではアセット管理としてAssetBundleがあります。
このAssetBundleを使い膨大なアセットをまとめてアセット管理を行ってきました。
そのためにそれぞれAssetBundleManagerクラスを作成していたと思います。UnityがAssetBundleManagerを提供していましたが現在ではサポートされておりません。
https://bitbucket.org/Unity-Technologies/assetbundledemo/src/default/
AssetBundleクラス自体は低レベルなクラスであり、実際のゲーム開発で使いやすくするために拡張が必要です。
オレオレAssetBundleManagerを作り出すと参照カウント付きクラスで隠蔽したり、依存バンドルを調べてロード・アンロード処理を書いたりすることが必要です。

こういった面倒な実装とAssetBundleの仕組みをもっと楽にしようということでAddressableAssetSystem(AAS)が作られました。
https://blogs.unity3d.com/jp/2019/07/15/addressable-asset-system/
Unity2018.3以降では使用可能ということです。
このAddressableAssetSystemの使い方、機能、ゲーム開発に使えるのかを調べていきます。

使用したバージョン

Addressables ver1.2.4
Unity 2019.3.0b4

AddressableAssetSystemとは

公式ドキュメント

まずは公式ドキュメントです。
一次ソースを調べることは何より重要です。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/manual/index.html
UniteTokyo2018の講演
https://learning.unity3d.jp/355/

GettingStartedを読めば最低限の導入まではできます。
1. PackageManagerからAddressablesをインストール
2. 初期化ウィンドウが出るので初期化
3. 各アセットのインスペクタでアドレスを指定
4. Window->AssetManagement->Addressablesを開く
5. 各アセットをグループに分ける
6. BuildからBuildPlayerContentでアセットバンドルを作成

GettingStartedだけではロード処理しか書いていないのでこのままではメモリに残り続けます
ReleaseやメモリについてはMemoryManagementを読みます。
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/manual/MemoryManagement.html

実際に使用する

AASをゲーム開発で使用するケースを考えます。
マニュアルやスライドを見ているとAASの各種設定は
Window->AssetManagement->Addressablesのメニューから行っています。
GUI上でグループを作成しアセットをグループへドラッグアンドドロップすることはとてもわかりやすいです。サンプルで数十ファイルの間は。

膨大なアセット数

ゲームに使用するアセットは軽く数百を超えていき、数万アセットにもなることがあります。
数万を超えるアセット数に対してこの手順は人間がするものではありません

多くの場合アセットを保存しているルートディレクトリからのパスでグループ化しフォルダ内のアセットはそのグループに属するといった設定になるでしょう。
アセットインポート時にグループの作成とグループへの追加を実装する方法がないか、APIドキュメントを読んで探します
https://docs.unity3d.com/Packages/com.unity.addressables@1.2/api/index.html

AddressableAssetSettings

最初にAddressablesメニューを開くときに作成されたAddressableAssetSettings.assetを選択したときのインスペクタを見ます。
image.png

名前からしてAASに関する設定を持っていそうです。
Groupsを開くと自分で作成したグループが追加されていることがわかります。
他にもいろいろな設定があります。
image.png

インスペクタ上で歯車をクリックするとEditScriptが表示されるのでスクリプトを確認するとScriptableObjectであることがわかります。
APIドキュメントを見るとグループの追加やアセットの登録に必要な機能があることがわかります。(CreateGroupやCreateOrMoveEntry)
AddressableAssetSettings
このScriptableObjectを取得してきます。

        //アドレサブルアセットセッティング取得
        var s = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEditor.AddressableAssets.Settings.AddressableAssetSettings>(
            "Assets/AddressableAssetsData/AddressableAssetSettings.asset"
            );

グループ作成の自動化

取得してきたAddressableAssetSettingsスクリプトを使用してグループ作成をします。
APIは CreateGroup を使用します。
APIドキュメントを見て引数を調べます。
CreateGroup
変わった引数でschemasToCopyがあります。
何を設定するのか迷いますがAddressablesメニューのDefaultLocalGroupと同じ設定にするには

        //スキーマ生成
        List<UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema> schema = new List<UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema>() 
{
            new UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema(),
            new UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema()
        };

というリストを指定します。
初期状態のグループが
image.png
AASUtility.csのCreateGroupメソッドを呼べば
image.png
CreatedGroupというグループが作成されました。

アセットをグループへ追加・削除

各アセットを作成したグループへ追加しなければアセットバンドルに含まれません。
APIはCreateOrMoveEntryを使用します。
APIドキュメントを見て引数を調べます。
CreateOrMoveEntry
guidとtargetParentでアセットのGUIDとグループを指定するだけで良さそうです。
guidはAssetPathToGUIDで取得できます

//アセットGUIDを取得
var assetGuid = UnityEditor.AssetDatabase.AssetPathToGUID("Assets/Data/hogeMat.mat");

AASUtility.csのAddAssetToGroupメソッドを呼べば
image.png
グループにアセットが追加されました。

アセットにラベルを指定

複数のアセットを一括でロードする機能としてラベルがあります。
ゲームの一ステージを構成するアセットをステージ遷移が発生する前に先読みしておきシームレスに見せるといった時に使えそうな機能です。
このラベルを設定するAPIを調べます。
AddressableAssetEntry.labelsが該当します。
APIドキュメントを見てセット関数を調べます。
SetLabel
AddressableAssetEntryを取得してSetLabels関数を使用することで設定できそうです。

AddressableAssetEntryを取得する方法を調べます。
AddressableAssetSettingsにGetAllAssetsという関数があります。
APIドキュメントを調べます。
GetAllAssets
第一引数のリストに設定されてる全アセットを返してくれることがわかります。
アセット数が数万になりリストが膨大になる場合Filterの引数で絞れそうです。

これで取得したリストの中からラベルをセットしたいアセットのassetGUIDを検索し取得したAddressableAssetEntryのSetLabelを呼べば設定完了です。

    static void SetLabelToAsset(List<string> assetGuidList, string label, bool flag)
    {
        var s = GetSettings();
        //ラベルを追加するように呼んでおく。追加されていないと設定されない。
        s.AddLabel(label);
        List<UnityEditor.AddressableAssets.Settings.AddressableAssetEntry> assetList = new List<UnityEditor.AddressableAssets.Settings.AddressableAssetEntry>();
        s.GetAllAssets(assetList, true);
        foreach (var assetGuid in assetGuidList)
        {
            var asset = assetList.Find((a) => { return a.guid == assetGuid; });
            if(asset != null)
            {
                asset.SetLabel(label, flag);
            }
        }
    }

image.png
コードから設定されました。

自動ビルド

UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.BuildPlayerContent();
を呼ぶだけでビルドしてくれます。
アセットバンドルビルドスクリプトを自作していた時のことを思い出すとこれだけで感動します。

おわりに

AddressableAssetSystemはゲーム開発に使用する機能も揃っているようです。
AssetBundleManagerを使用してビルドスクリプトを自作してといった旧時代の遺物は捨て去り、Unity2018.3以降はAddressableAssetSystemを使用していきましょう。
どんどん使用されていき知見が溜まっていくことを期待してます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む