20200101のUnityに関する記事は7件です。

[Unity][Fee]インプトマネージャでパッド対応

はじめに

自作ライブラリ開発日記です。
https://github.com/bluebackblue/fee_core

なにが問題なのか

インプットマネージャは「パッドの数」x「パッドの種類」x「ボタンの数」だけ設定をする必要がある。

解決策

必要最低限の全パターンを一括で登録する「InitializeInputManager」を作った。
コメント

image.png

「pad_0」は0番目のパッド。
「pad_1」は1番目のパッド。
「type_p」はPSコントローラ対応。
「type_x」はXBOXコントローラ対応。
「type_a」はAndroidでのXBOXコントローラ対応。

コード

/** 初期設定。
*/
public void Initialize()
{
    //0番目のパッドにXBOXコントローラが接続してあることが前提。
    Fee.Input.Pad.GetInstance().pad_status[0].pad_type = Fee.Input.Pad_InputManagerItemName.PadType.Type_X;

    //1番目のパッドにPSコントローラが接続してあることが前提。
    Fee.Input.Pad.GetInstance().pad_status[1].pad_type = Fee.Input.Pad_InputManagerItemName.PadType.Type_P;
}

/** 更新。
*/
public void Main()
{
    //0番目のパッドのデジタルボタン左が押された。
    if(Fee.Input.Pad.GetInstance().pad_status[0].left.down == true){
        UnityEngine.Debug.Log("pad 0 left down");
    }

    //1番目のパッドのデジタルボタン左が押された。
    if(Fee.Input.Pad.GetInstance().pad_status[1].left.down == true){
        UnityEngine.Debug.Log("pad 1 left down");
    }
}

動作確認

InputSystemと違いXBOXコントローラ、PSコントローラのどちらが接続されているのかの判別ができない。

WebGL 2019.2.17f1(WindowsChromeで実行)

XBOXコントローラ、PSコントローラ:どちらもType_Xとして動作する。

Standalone 2019.2.17f1(Windowsで実行)

XBOXコントローラ:Type_Xとして動作する。
PSコントローラ:Type_Pとして動作する。

Android 2019.2.17f1

XBOXコントローラ:USB接続で認識する。Type_Aとして動作する。
PSコントローラ:ブルートゥース接続で認識するがType_XでもType_Pでもない。かなり不安定。
複数パッド対応は未確認。

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

【Unity】iosデバッグ時のbuild設定 ios実機/Simulator

Build Setting

ios実機でデバッグする時
iphone_debug.png

X-code Simulatorでデバッグする時
simulator_debug.png

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

【Unity】DoTweenを使ってUIを上下ループさせて目立たせる

コード

UIPointer.cs
using UnityEngine;
using DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;

public class UIPointer : MonoBehaviour
{
    [SerializeField] private float _durationSeconds = 0.2f;

    private float _initY = 0;
    private float _endY = 0;
    [SerializeField] private float _moveY = 3f;

    private TweenerCore<Vector3, Vector3, VectorOptions> _tweener;

    public void InitDisplay(Vector3 position)
    {
        // 指定した位置に移動する
        transform.position = position;

        // 初期化
        _initY = transform.position.y;
        _endY = _initY - _moveY;

        // 表示する
        gameObject.SetActive(true);

        _tweener = transform
            .DOMoveY(_endY, duration: _durationSeconds)
            .SetEase(Ease.InCubic)
            .SetLoops(-1, LoopType.Yoyo)
            .Play();
    }

    private void OnDisable()
    {
        _tweener.Kill();
    }

    [ContextMenu("TestDisplay")]
    void TestDisplay()
    {
        InitDisplay(Vector3.zero);
    }
}

エディタ

image.png

デモ

参考

[Unity] DOTweenを使ってUI要素を点滅させる

余談

地味にコピペですぐ使えるコードが見つからなかったので記事にしました。

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

Unity Cloud Buildで自動ビルド環境を手に入れる

はじめに

皆様明けましておめでとうございます!

本業はフロントエンドエンジニアですが、趣味ではサークルでゲームを作ったりしてまして、最近はこんなゲームを作ったりしてました。
このゲームは私(プランニング、プログラミング担当)ともう一人(グラフィック、サウンド担当)で作ったんですが、開発時に修正チェックなどでお互いの環境でビルドして動作確認するのが煩雑だなーと感じていました。
次回作を作るにあたり、このめんどくささを解消したいなと考え、調べた結果、Unity公式がUnity Cloud Buildというサービスを提供しており、今やりたいこととマッチしていたので実際に試してみました

実現したいこと

  1. GitHubで管理しているリポジトリに変更が加わる
  2. 自動的にビルドが行われる
  3. ビルド完了通知がSlackに送られる(ビルド生成物のダウンロードもできる)

Unity Team Advanced

Unity Cloud Buildの公式ページはこちらです。
キャプチャ1.PNG

公式ページを見ればわかる通り今回実現したいことを実現するためにはUnity Team Advancedを手に入れている必要があります。

キャプチャ2.PNG

ひと月あたり$9~(チーム人数によって変動)かかりますが、1か月は無料で使うことができるので、試してみて快適だなと感じたら課金しましょう。
Cloud Buildが使える以外にもBasicプランに比べていろいろパワーアップしています!

Unity Cloud Build

プロジェクト作成

Unity Team Advancedアカウントを作ってUnity Cloud Buildにログインするとこんな管理画面にアクセスできます
(私はすでにプロジェクトを作っているので一つだけプロジェクトがありますが無視してください)
キャプチャ3.PNG
まずプロジェクトを作りましょう
右上の「CREATE NEW PROJECT」という青いボタンを押します。
キャプチャ4.PNG
任意のプロジェクト名を入力し、先ほど作成したUnity Team Advancedアカウントを組織で選択します。

作成ボタンを押下すると以下のようなプロジェクト管理画面に遷移します。
キャプチャ5.PNG

GitHub連携

GitHubと連携して、ビルドを自動化しましょう。
左のメニューから「Cloud Build」 → 「Config」と進みます
キャプチャ6.PNG
ここから「Souce Control Setting」をEditします。
キャプチャ7.PNG
連携できるサービスが表示されます。
現状GitHub、Bitbucket、GitLabが選択できます。
ここでは「GitHub」を選択します。

GitHub側の認証を求めるので許可すると、以下のようなリポジトリを選択する画面に遷移します。
キャプチャ8.PNG
ここでビルドしたいUnityプロジェクトのリポジトリを選択して、「NEXT: TARGET SETUP」を押下します。
キャプチャ9.PNG

すると元のConfig画面に戻るのでSource Control SettingsのところにGitHubのSSH Keyが設定されているのを確認しつつ「SETUP NEW TARGET」を押下します
キャプチャ10.PNG
どのプラットフォーム用のビルドをするか聞かれるのでお好きなものを選択してください。

キャプチャ11.PNG

次の画面ではビルドの設定を行うことができます。
設定できる項目としては以下の通りです

項目 内容
ラベル ラベル名称。実行ファイル名になるみたいです(Windows 64bitで確認)。アルファベットとハイフンとスペースのみ使用可能
branch ビルド対象Branch
Project Subfolder rootフォルダ以外のところに資産が置いてある場合はここで指定します
Auto Detect Version ONにするとプロジェクト設定(ProjectSettings/ProjectVersion.txt)からUnityバージョンを自動検出するかどうか
Unity Version Auto Detect VersionがOFFの場合はUnityバージョンを明示的に指定します
Build with closest version Auto Detect VersionがONの場合で、検出したUnityバージョンがCloud Build上で使えない場合は、最も近いバージョンを使うことを許可するか
Auto-build リポジトリに変更があった場合に自動でビルドするかどうか

ビルドするプロジェクトや好みに応じてお好きに設定してください。
(今回やりたいことをやるためにはAuto-buildのONは必須です)

設定が終わったら「NEXT」を押下しましょう。

するとこんな感じでビルドヒストリーを見られる画面に遷移します。
この画面で右上の「BUILD DEFAULT~」という青いボタンを押せば、手動ビルドすることも可能です。
キャプチャ12.PNG

これでリポジトリに変更が加われば自動的にビルドが行われるようになりました!

Slack連携

ただこれではビルドは自動で行ってくれるのですが、いつ完了するのかは都度この画面で確認する必要があって面倒です(今回作ったゲームで試したところビルド時間はそこそこかかった)。
終わったら教えてくれるのが理想ですね。
現状平時の連絡はSlackで行っているので、終わったらSlackに通知してくれるようにしましょう。
連携の口はCloud Buildが提供してくれているので、設定を行うだけで連携完了します。
キャプチャ13.PNG

左のメニューから「Settings」→「Integrations」を選択します。
「NEW INTEGRATION」を押下して連携設定を新規作成しましょう。
キャプチャ14.PNG

選べるサービスもいくつかありますが、今回はSlackを選択します。
(最近流行ってるコミュニケーションツールは大体揃ってる印象ですね)
キャプチャ15.PNG
次の画面ではどのアクションをSlack側に通知するかを選べます。
この辺りは好みに応じてお好きにどうぞ。
(個人的にはCloud Build全てとCollaborateを選択していますが、とりあえず全部チェックしといて邪魔だったら消すでいいとも思います)
設定完了後、「NEXT」を押下するとUnity Serviceに許可する情報と通知が投稿されるチャンネルを指定すれば連携完了です。

連携完了後

連携完了後に指定したリポジトリのブランチに変更を加えると以下のような形でSlackに通知が投稿されます!
キャプチャ16.PNG

Downloadリンクをクリックすればビルドされたゲームの実行フォルダがダウンロードできます

管理画面ではリアルタイムにログを確認することもできます
キャプチャ17.PNG

おわりに

こんなことしてるから肝心のゲーム開発本体が進まない説

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

【Unity Editor拡張 with Odin】 Addressable AssetReferenceのプレビューを表示する

環境

Unity 2019.2.17f1
Addressable 1.5
Odin Inspector 2.1.8 (有料プラグイン)
odin.png

AssetReferenceって何を参照しているのか分かりにくい。。。

名前を設定している場合はまだ分かりやすいですが、フォルダを指定している場合フルパスが表示されるのでかなり分かり辛いです。それを有料プラグインのOdinを使って解決してみようと思います。

まずは Before / After

Before...
Addressable.gif
After !!!!
AddressableWithOdin.gif
だいぶ分かりやすくなりましたね。
Prefab名をクリックするとProject内のPrefabをハイライトしてくれます。

Code

OdinWithAddressableAssetReference.cs
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AddressableAssets;
using Sirenix.OdinInspector;

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
#endif

[CreateAssetMenu(menuName = "Sample/OdinWithAddressableAssetReference")]
public sealed class OdinWithAddressableAssetReference : ScriptableObject
{
    [SerializeField, HideInInspector] AssetReferenceGameObject references;

    public AssetReferenceGameObject References => references;

    #region Inspector
#if UNITY_EDITOR
#pragma warning disable 0649
    [SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly;
    [ShowInInspector, ReadOnly, InlineEditor(InlineEditorModes.LargePreview), ShowIf("ReferencePreviewShowIfEditorOnly")] GameObject PreviewOnEditor;
    [SerializeField, ValueDropdown("AssetGroupDropDownEditorOnly", IsUniqueList = true), LabelText("Addressable Group Filter")] string[] targetAssetGroupGuidsEditorOnly;
#pragma warning restore 0649

    IEnumerable ReferenceDropDownEditorOnly()
    {
        return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly)
                .Select(x => new ValueDropdownItem(x.AssetPath, x.guid));
    }

    IEnumerable AssetGroupDropDownEditorOnly()
    {
        return GetAllAssetGroups()
                .Select(x => new ValueDropdownItem(x.Name, x.Guid));
    }

    void ReferenceValueChangedEditorOnly(string guid)
    {
        var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly);
        var item = entrys.FirstOrDefault(x => x.guid == guid);

        if (item != default)
        {
            references = new AssetReferenceGameObject(item.guid);
            UpdatePreviewAssetEditorOnly();
        }
    }

    bool ReferencePreviewShowIfEditorOnly()
    {
        if(PreviewOnEditor == default)
        {
            UpdatePreviewAssetEditorOnly();
        }

        return PreviewOnEditor != default;
    }

    void UpdatePreviewAssetEditorOnly()
    {
        PreviewOnEditor = default;

        if(references.RuntimeKeyIsValid())
        {
            PreviewOnEditor = LoadAsset<GameObject>(references);
        }
    }

    /// <summary>
    /// アセットの取得
    /// </summary>
    /// <returns>The asset.</returns>
    /// <param name="reference">Reference.</param>
    /// <typeparam name="T">The 1st type parameter.</typeparam>
    public static T LoadAsset<T>(AssetReference reference) where T : Object
    {
        return reference.RuntimeKeyIsValid()
                      ? AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(reference.AssetGUID))
                      : default;
    }

    /// <summary>
    /// グループ一覧を取得
    /// </summary>
    /// <returns>The asset groups.</returns>
    public static List<AddressableAssetGroup> GetAllAssetGroups()
    {
        var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
        var gropus = new List<AddressableAssetGroup>();

        if (setting != default)
        {
            gropus = setting.groups;
        }

        return gropus;
    }

    /// <summary>
    /// 全エントリーを取得
    /// </summary>
    /// <returns>The asset entrys editor only.</returns>
    /// <param name="groupFilterGuids">Group filter.</param>
    public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null)
    {
        var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
        var entrys = new List<AddressableAssetEntry>();

        if (setting != default)
        {
            foreach (var group in setting.groups)
            {
                if (groupFilterGuids != null
                    && groupFilterGuids.Length > 0
                    && !groupFilterGuids.Any(guid => guid == group.Guid))
                {
                    continue;
                }

                var _entrys = new List<AddressableAssetEntry>();
                group.GatherAllAssets(_entrys, false, true, false);
                entrys.AddRange(_entrys);
            }
        }

        return entrys;
    }
#endif
    #endregion

}

実装のポイント

AddressableAssetSettingsの取得方法が変わりました

OdinWithAddressableAssetReference.cs
var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);

プレビュー用GameObjectをシリアライズされないようにする

プレビューを表示するためのGameObjectがシリアライズされないようにprivateでShowInInspectorアトリビュートを使用しています。
publicにしたい場合は、[System.NonSerialized]を追加。

更に、プレビューは参照だけで使用されることが無いので#pragma warningでCS0649警告が表示されないようにしています。

OdinWithAddressableAssetReference.cs
[ShowInInspector, ()] GameObject PreviewOnEditor;

OdinでAddressableは非対応なのでGuidを保存する

Reference.png
ドロップダウンは実はテキストです(string referenceGuidEditorOnly)。
表示するリストを生成する際(ReferenceDropDownEditorOnly())、表示用のアセットパスと保存用のGuidをOdinのValueDropdownItemに代入しています。
そして、Guidに変更があった場合(ReferenceValueChangedEditorOnly(string guid))でプレビューを更新する仕様です。

OdinWithAddressableAssetReference.cs
[SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly;

IEnumerable ReferenceDropDownEditorOnly()
{
    return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly)
            .Select(x => new ValueDropdownItem(x.AssetPath, x.guid));
}

void ReferenceValueChangedEditorOnly(string guid)
{
    var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly);
    var item = entrys.FirstOrDefault(x => x.guid == guid);

    if (item != default)
    {
        references = new AssetReferenceGameObject(item.guid);
        UpdatePreviewAssetEditorOnly();
    }
}

/// <summary>
/// 全エントリーを取得
/// </summary>
/// <returns>The asset entrys editor only.</returns>
/// <param name="groupFilterGuids">Group filter.</param>
public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null)
{
    var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
    var entrys = new List<AddressableAssetEntry>();

    if (setting != default)
    {
        foreach (var group in setting.groups)
        {
            if (groupFilterGuids != null
                && groupFilterGuids.Length > 0
                && !groupFilterGuids.Any(guid => guid == group.Guid))
            {
                continue;
            }

            var _entrys = new List<AddressableAssetEntry>();
            group.GatherAllAssets(_entrys, false, true, false);
            entrys.AddRange(_entrys);
        }
    }

    return entrys;
}

グループフィルターに対応

Group.png
フィルタ機能もつけてみました。
ほんとはLabel用のフィルタ機能もつけたかったのですが、 LabelTableがprivateの為一覧取得ができず断念しました。

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

【Unity Editor拡張 with Odin】 Addressable AssetReferenceのプレビュー表示とグループでのフィルタリング

環境

Unity 2019.2.17f1
Addressable 1.5
Odin Inspector 2.1.8 (有料プラグイン)
odin.png

AssetReferenceって何を参照しているのか分かりにくい。。。

名前を設定している場合はまだ分かりやすいですが、フォルダを指定している場合フルパスが表示されるのでかなり分かり辛いです。それを有料プラグインのOdinを使って解決してみようと思います。

まずは Before / After

Before...
Addressable.gif
After !!!!
AddressableWithOdin.gif
だいぶ分かりやすくなりましたね。
Prefab名をクリックするとProject内のPrefabをハイライトしてくれます。
そしてグループでのフィルタリングにも対応しました。

Code

OdinWithAddressableAssetReference.cs
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AddressableAssets;
using Sirenix.OdinInspector;

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
#endif

[CreateAssetMenu(menuName = "Sample/OdinWithAddressableAssetReference")]
public sealed class OdinWithAddressableAssetReference : ScriptableObject
{
    [SerializeField, HideInInspector] AssetReferenceGameObject references;

    public AssetReferenceGameObject References => references;

    #region Inspector
#if UNITY_EDITOR
#pragma warning disable 0649
    [SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly;
    [ShowInInspector, ReadOnly, InlineEditor(InlineEditorModes.LargePreview), ShowIf("ReferencePreviewShowIfEditorOnly")] GameObject PreviewOnEditor;
    [SerializeField, ValueDropdown("AssetGroupDropDownEditorOnly", IsUniqueList = true), LabelText("Addressable Group Filter")] string[] targetAssetGroupGuidsEditorOnly;
#pragma warning restore 0649

    IEnumerable ReferenceDropDownEditorOnly()
    {
        return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly)
                .Select(x => new ValueDropdownItem(x.AssetPath, x.guid));
    }

    IEnumerable AssetGroupDropDownEditorOnly()
    {
        return GetAllAssetGroups()
                .Select(x => new ValueDropdownItem(x.Name, x.Guid));
    }

    void ReferenceValueChangedEditorOnly(string guid)
    {
        var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly);
        var item = entrys.FirstOrDefault(x => x.guid == guid);

        if (item != default)
        {
            references = new AssetReferenceGameObject(item.guid);
            UpdatePreviewAssetEditorOnly();
        }
    }

    bool ReferencePreviewShowIfEditorOnly()
    {
        if(PreviewOnEditor == default)
        {
            UpdatePreviewAssetEditorOnly();
        }

        return PreviewOnEditor != default;
    }

    void UpdatePreviewAssetEditorOnly()
    {
        PreviewOnEditor = default;

        if(references.RuntimeKeyIsValid())
        {
            PreviewOnEditor = LoadAsset<GameObject>(references);
        }
    }

    /// <summary>
    /// アセットの取得
    /// </summary>
    /// <returns>The asset.</returns>
    /// <param name="reference">Reference.</param>
    /// <typeparam name="T">The 1st type parameter.</typeparam>
    public static T LoadAsset<T>(AssetReference reference) where T : Object
    {
        return reference.RuntimeKeyIsValid()
                      ? AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(reference.AssetGUID))
                      : default;
    }

    /// <summary>
    /// グループ一覧を取得
    /// </summary>
    /// <returns>The asset groups.</returns>
    public static List<AddressableAssetGroup> GetAllAssetGroups()
    {
        var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
        var gropus = new List<AddressableAssetGroup>();

        if (setting != default)
        {
            gropus = setting.groups;
        }

        return gropus;
    }

    /// <summary>
    /// 全エントリーを取得
    /// </summary>
    /// <returns>The asset entrys editor only.</returns>
    /// <param name="groupFilterGuids">Group filter.</param>
    public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null)
    {
        var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
        var entrys = new List<AddressableAssetEntry>();

        if (setting != default)
        {
            foreach (var group in setting.groups)
            {
                if (groupFilterGuids != null
                    && groupFilterGuids.Length > 0
                    && !groupFilterGuids.Any(guid => guid == group.Guid))
                {
                    continue;
                }

                var _entrys = new List<AddressableAssetEntry>();
                group.GatherAllAssets(_entrys, false, true, false);
                entrys.AddRange(_entrys);
            }
        }

        return entrys;
    }
#endif
    #endregion

}

実装のポイント

AddressableAssetSettingsの取得方法が変わりました

OdinWithAddressableAssetReference.cs
var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);

プレビュー用GameObjectをシリアライズされないようにする

プレビューを表示するためのGameObjectがシリアライズされないようにprivateでShowInInspectorアトリビュートを使用しています。
publicにしたい場合は、[System.NonSerialized]を追加。

更に、プレビューは参照だけで使用されることが無いので#pragma warningでCS0649警告が表示されないようにしています。

OdinWithAddressableAssetReference.cs
[ShowInInspector, ()] GameObject PreviewOnEditor;

OdinでAddressableは非対応なのでGuidを保存する

Reference.png
ドロップダウンは実はテキストです(string referenceGuidEditorOnly)。
表示するリストを生成する際(ReferenceDropDownEditorOnly())、表示用のアセットパスと保存用のGuidをOdinのValueDropdownItemに代入しています。
そして、Guidに変更があった場合(ReferenceValueChangedEditorOnly(string guid))でプレビューを更新する仕様です。

OdinWithAddressableAssetReference.cs
[SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly;

IEnumerable ReferenceDropDownEditorOnly()
{
    return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly)
            .Select(x => new ValueDropdownItem(x.AssetPath, x.guid));
}

void ReferenceValueChangedEditorOnly(string guid)
{
    var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly);
    var item = entrys.FirstOrDefault(x => x.guid == guid);

    if (item != default)
    {
        references = new AssetReferenceGameObject(item.guid);
        UpdatePreviewAssetEditorOnly();
    }
}

/// <summary>
/// 全エントリーを取得
/// </summary>
/// <returns>The asset entrys editor only.</returns>
/// <param name="groupFilterGuids">Group filter.</param>
public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null)
{
    var setting = AddressableAssetSettingsDefaultObject.GetSettings(false);
    var entrys = new List<AddressableAssetEntry>();

    if (setting != default)
    {
        foreach (var group in setting.groups)
        {
            if (groupFilterGuids != null
                && groupFilterGuids.Length > 0
                && !groupFilterGuids.Any(guid => guid == group.Guid))
            {
                continue;
            }

            var _entrys = new List<AddressableAssetEntry>();
            group.GatherAllAssets(_entrys, false, true, false);
            entrys.AddRange(_entrys);
        }
    }

    return entrys;
}

グループフィルターに対応

Group.png
フィルタ機能もつけてみました。
ほんとはLabel用のフィルタ機能もつけたかったのですが、 LabelTableがprivateの為一覧取得ができず断念しました。

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

ARで穴をあける[ウソ穴]システムの作り方

紹介すること

個人で開発している『ウソ穴』というシステムの作り方を紹介します。

ウソ穴とは

ウソ穴は、AR(拡張現実)とストリーミングを組み合わせて穴があいたかのような感覚を提供するシステムです。
こちらは、板にウソ穴を搭載したときの動画です。板に穴が空いているように見えますが、実際には板に穴はあいていません。

穴をあけたように見せかけているので、このように体に穴をあける(あけたように見せかける)こともできます。

概要図

仕組み図解

  • ラズパイをストリーミングサーバにして、ラズパイに装着したカメラの映像を配信します。
  • 配信した映像をテクスチャとした3Dオブジェクトを作成します。
  • 作成した3DオブジェクトをARで表示されるようにします。

  • 板にARマーカを付けます。
  • ARを設定したカメラを通して板を見るとを、ARマーカーの位置をもとに3Dオブジェクトが表示されます。これがウソ穴です。

 ※ 写真はこちらから拝借 https://www.pexels.com/ja-jp/photo/1128065/

セットアップの概要

ラズパイとWinPCで行うセットアップの概要です。

  • ラズパイ (Raspberry Pi 4 Model B / 4GB)
    • カメラを付ける
    • MJPG-streamerでストリーミングサーバーにする
    • →カメラ映像をストリーミングで配信する
  • WinPC (Window10)
    • Unityをインストール
    • VuforiaでARマーカーを認識
    • ARで3Dオブジェクを表示する
    • →穴の形状をした3Dオブジェクトを作成する
    • →3Dオブジェクトにストリーミング映像をテクスチャとしてマッピングする

参考リンク

※注意※

  • セキュリティ対策は不十分です。
  • ウソ穴のシステムは安定稼働に課題があり、ストリーミングサーバが意図せず停止することがあります。(連続稼働は5分くらいが限度)
  • 備忘録なので説明が不十分なところがあります。それら情報も参考リンクで紹介した記事など参照することで確認できると思います。

ラズパイをセットアップしよう

簡単ですがラズパイのセットアップ手順を紹介します。OSは、Rasbian(2019-09-26)をインストールしました。

ssh接続します。

ssh pi@raspberrypi.local
# パスワード raspberry

ホスト名を変更します。

sudo nano /etc/hostname
sudo nano /etc/hosts
  • 更新します。
# パッケージ更新
$ sudo apt-get update
$ sudo apt-get upgrade -y
$ sudo apt-get dist-upgrade

# ファームウェアを更新
$ sudo rpi-update
  • ※先ほどの更新をシェルでまとめて実行するとこうなります。
# setup.sh という空ファイル作成
$ sudo touch setup.sh
setup.sh
#!/bin/sh

sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get dist-upgrade -y
sudo rpi-update -y
# 実行権限を付与
$ chmod +x setup.sh
# シェル実行
$ ./setup.sh
  • Wi-Fi接続設定をします。
/etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
        ssid="xxxxx-1"
        psk="xxxx"
        priority=0
        scan_ssid=1
        id_str="home1"
}

network={
        ssid="xxxxx-2"
        psk="xxxx"
        priority=0
        scan_ssid=1
        id_str="home2"
}

  • sudo raspi-configで色々設定していきます。

  • パスワード変更

    • 1 Change User Password Change password for the current user
  • ロケールを設定

    • 4 Localisation options - Change Locale - ja_JP.UTF-8
  • タイムゾーンを設定

    • 4 Localisation Options - I2 Change Timezone - Asia - Tokyo
  • Wifiロケールを設定します

    • 4 Localisation Options - I4 Change Wi-fi Country - JP Japan
  • pipバージョンアップ

$ sudo pip install --upgrade pip

必須ではないですが、Windowsとのデータ移行が楽になるので、sambaをインストールします。

$ sudo apt-get install samba
$ cd /etc/samba
  • /etc/samba/smb.confの最後尾に以下を追記します。
[pi-raspberry]
path = /home/pi
read only = No
guest ok = Yes
force user = pi

[tmp-raspberry]
path = /var/tmp
read only = No
guest ok = Yes
force user = pi
  • sambaを再起動するとWindowsのエクスプローラ経由でアクセスできるようになります。
$ sudo service smbd restart
$ sudo service nmbd restart
  • カメラモジュールを認識させます。
$ sudo raspi-config

5 Interfacing Options - P1 Camera - はい - 了解

  • OSを再起動後に再接続(ssh接続)します。
  • カメラが認識されているか確認します。
$ vcgencmd get_camera

supported=1 detected=1と表示されれば認識成功です。

ラズパイにMJPG-streamerをインストールしてストリーミングサーバにしよう

  • mjpeg-streamerをインストールして、起動します。
$ sudo apt-get install build-essential libjpeg8-dev imagemagick libv4l-dev cmake -y
$ git clone https://github.com/jacksonliam/mjpg-streamer.git
$ cd mjpg-streamer/mjpg-streamer-experimental
  • CMakeLists.txtを編集します。
  • ⾏頭にʼ#ʼを追加してコメントアウトします。(これすると、make実行時のエラー発生を対策できるみたいです)
#add_subdirectory(plugins/input_opencv)
$ make
$ sudo make install
  • ※よくわからんのだが、↓をするといいらしい
~/mjpg-streamer/mjpg-streamer-experimental $ cp input_raspicam.so ../
  • MJPEG-streamerのインストールが完了したので、ストリーミング配信を試します。
  • コマンドを実行し配信を開始したら、ブラウザで http://{{ラズパイのIP}}:8080/にアクセスして、ラズパイカメラの映像が表示されれば成功です。
# ストリーミング起動
$ /usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 640 -y 480 -fps 15 -q 80" -o "output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www" 
# -> http://{{ラズパイのIP}}:8080/
# -> http://{{ラズパイのIP}}:8080/javascript_simple.html
# -> http://{{ラズパイのIP}}:8080?action=snapshot
# -> http://{{ラズパイのIP}}:8080?action=stream
  • ウソ穴では、このような設定にしていました。
# ウソ穴
$ /usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 64 -y 64 -fps 10 -q 80" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www" 
# -> http://{{ラズパイのIP}}:8090?action=stream

  • 配信を開始するコマンドをShellにしておくと便利です。
/usr/local/bin/start_mjpeg.sh
#!/bin/sh
/usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 256 -y 256 -fps 15 -q 80" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www"
  • 実行権限を付与します。
chmod +x start_mjpeg.sh

ラズパイでストリーミング再生をスケジュール実行しよう

  • Unityからストリーミングサーバへの要求が厳しいのか、ウソ穴を実行すると5分くらいでMJPEG-streamerが落ちるという課題があります。そこで、1分単位でMJPEG-streamerが止まっていたら実行するようにスケジュールを設定します。
mjpeg.sh
#!/bin/sh
/usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 64 -y 64 -fps 10 -q 80" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www" 
  • スケジュール実行のルールを書いたファイルを作ります(ファイル名は任意)
cron.conf
0-59 * * * * /bin/bash /home/pi/mjpeg.sh
@reboot /bin/bash /home/pi/mjpeg.sh
  • cronにジョブとして登録します。
$ crontab cron.conf

※注意※
ルールを書いたファイルcron.confを編集した場合は、再度ジョブ登録が必要です。

ラズパイOSイメージのバックアップ

  • ラズパイOSのセットアップが完了したら、バックアップすることをオススメします。
  • Disk Imageで、WindowsにラズパイOSのバックアップイメージを保存できます。

Unityプロジェクトを作ろう

  • ここからはWindowsでの作業になります。Unityがインストールされていることが前提です。
  • ストリーミングのスナップショットをテクスチャにマッピングするスクリプトGetNetworkImage6.csを作成します。
GetNetworkImage6.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GetNetworkImage6 : MonoBehaviour
{
    private float timeleft;

    IEnumerator RenewImage(){
        string url = "http://{{ラズパイのIP}}:8090/?action=snapshot";
        WWW www = new WWW(url);
        Debug.Log (www);
        yield return www;
        RawImage rawImage = GetComponent<RawImage>();
        rawImage.texture = www.textureNonReadable;
    }

    void Start()
    {
        StartCoroutine( RenewImage() );
    }

    void Update()
    {
        StartCoroutine( RenewImage() );
    }
}
  • GetNetworkImage6.csをAssetに登録します。

  • 詳細は割愛しますが、各オブジェクトの設定はこのようになります。


以上でおわりです。

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