20200630のUnityに関する記事は5件です。

【Unity:Log】Android Logcat

Androidのログ確認に使用するmonitorがUnity上で起動できる

UnityのPackageManagerからインストール可能

Window > Analysis > Android Logcat で開く
android_logcat.png

UnityHubでUnityインストール時にAndroidの一式をダウンロードしておけば特に他にインストールとかせずに使える

今まで別途JDKとか自分でインストールしてたのがUnityで完結するからとても楽

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

【Blender】Blenderでメッシュから服をつくるにあたり、画像で備忘録【メモ】

Blenderでメッシュ一種類だと、ショルダーのボーンについていかないときがある

下図の場合、T字ポーズだと違和感がないが、
再度VRMに変換した際に、シャツの肩部分がそのままなので
聖闘士星矢状態になる。
スクリーンショット 2020-06-30 13.36.53.png

まさに聖闘士星矢。
da-vinci0.1トリミング.png


unityでのボーン

そのため、Blenderでメッシュで服を作る際、
レイヤードシャツを作るイメージで、
またはガンプラを作るイメージで、
下図のボーンにあった服を別個に作る必要がある。

下図の場合、

  • ショルダー(L)
  • ショルダー(R)
  • アッパーチェスト
  • チェスト

などが該当する。
スクリーンショット 2020-06-30 14.15.21.png

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

UnityでXBOXコントローラーを振動させる

忘れそうなので自分用メモとして残しておきます。
Unity 2019.4で確認済みです。

今回はこちらのXInputDotNetというライブラリを使用させていただきました。
とても助かりました。感謝。
https://github.com/speps/XInputDotNet.git

手順

https://github.com/speps/XInputDotNet/releases

上にある最新のunityPackageをプロジェクトにインポートして

VibrationTest.cs
XInputDotNetPure.GamePad.SetVibration(0,5,5);

この一行で振動してくれました。お手軽。
左右別々のモーターをそれぞれ動かすことができるようです。

例えばこんな風にテスト用のスクリプトを書いてみました。

VibrationTest.cs
using System.Collections;
using UnityEngine;
using XInputDotNetPure;

public class VibrationTest : MonoBehaviour
{
    [SerializeField] float right_power = 1;
    [SerializeField] float left_power = 1;
    [SerializeField] float duration = 0.5f;

    void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            StartCoroutine("RightVibration");
        }

        if (Input.GetButtonDown("Fire2"))
        {
            StartCoroutine("LeftVibration");
        }
    }

    IEnumerator RightVibration()
    {
        GamePad.SetVibration(0, 0, right_power);
        yield return new WaitForSecondsRealtime(duration);
        GamePad.SetVibration(0, 0, 0);
    }

    IEnumerator LeftVibration()
    {
        GamePad.SetVibration(0, left_power, 0);
        yield return new WaitForSecondsRealtime(duration);
        GamePad.SetVibration(0, 0, 0);
    }

}

今のところ0をセットすることで振動を止めていますが、これでいいのでしょうか…

参考

【Unity】ゲームパッドを振動させてみる

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

Unity+ADX2環境でエディタからプロジェクト設定情報(acf)を確認する

acfファイルの中身をエディタで表示&クリップボードにコピー

.acfファイルはADX2から出力される、ADX2のプロジェクト設定が入ったファイルです。
Atom Craftでは「プロジェクトツリー」の「全体設定」以下で設定する項目となっており、ゲームプロジェクト全体で使用するADX2の設定情報になります。Atom Craftを開けばどんな設定になっているかすぐに確認できます。

しかしながら、複数人で作業している場合や、今作業している環境にAtom Craftやプロジェクトファイルがない状態のときは、出力されたacfファイルの中身がどんなものであるかはわかりません。そこで、Unity Editor上でacfの中身を取り出しておき、作業者がAtom Craftを開かずとも設定が簡単に確認できることを目指します。

今回は「カテゴリーの情報」と「AISACコントロールの情報」の2つを表示するウィンドウをエディタ拡張で作成します。

ADX2AcfViewer.png

ソースコードとunitypackage

Unity ADX2 Acf Viewer
https://github.com/TakaakiIchijo/UnityADX2AcfViewer

確認環境

Unity 2019.4.1f1
ADX2 LE SDK 2.10.05

Scriptable Objectでacf情報を保存する

ADX2 LEでは、エディタで一度ゲームを実行するとacfファイルの中身をADX2のランタイムが読み込む仕組みになっています。
これから作成するACF Viewerもゲームを実行してからデータ読み込み、という手続きになりますが、エディターを起動するたびに読み込むのは面倒です。そこで、一回読み込んだacfのデータはScriptable Objectとして保存しておき、次回起動時にはこのScriptableObjectからデータを読み込むことにします。

「カテゴリー」と「AISACコントロール」のプロパティを保存するScriptable Object
は次の通りです。

AcfDataSo.cs
using System.Collections.Generic;
using UnityEngine;
using ACFDataClass;

public class AcfDataSo : ScriptableObject
{
    public List<CategoryInfo> categoryInfoList = new List<CategoryInfo>();
    public List<AisacControlInfo> aisacControlInfoList = new List<AisacControlInfo>();
}

namespace ACFDataClass
{
    [System.Serializable]
    public class CategoryInfo
    {
        public string name;
        public uint groupNo;
        public uint id;
        public uint numCueLimits;
        public float volume;

        public CategoryInfo(uint groupNo, uint id, string name, uint numCueLimits, float volume)
        {
            this.groupNo = groupNo;
            this.id = id;
            this.name = name;
            this.numCueLimits = numCueLimits;
            this.volume = volume;
        }
    }

    [System.Serializable]
    public class AisacControlInfo
    {
        public string name;
        public uint id;

        public AisacControlInfo(string name, uint id)
        {
            this.name = name;
            this.id = id;
        }
    }
}

ウィンドウが有効になったらScriptable Objectを作成する

次に、保存用のScriptableObjectのファイルをエディタ上で生成します。
EditorWindowのOnEnableメソッドで、指定のパスにScriptableObjectが存在するか確認し、なければ新しく作ります。

CriAtomAcfViewerWindow.cs
using System;
using System.Collections.Generic;
using System.Linq;
using ACFDataClass;
using UnityEditor;
using UnityEngine;

public class CriAtomAcfViewerWindow : EditorWindow
{
    const string acfScriptableObjectPath = "Assets/Editor/CriWare/CriAtom/acfDataSo.asset";

    private AcfDataSo acfDataSo;

    [MenuItem("Window/CRIWARE/Open Acf Viewer Window", false, 100)]
    static void OpenWindow()
    {
        GetWindow<CriAtomAcfViewerWindow>("Acf Viewer");
    }

    private void OnEnable()
    {
        acfDataSo = AssetDatabase.LoadAssetAtPath<AcfDataSo>(acfScriptableObjectPath);

        if (acfDataSo == null)
        {
            acfDataSo = CreateInstance<AcfDataSo>();
            AssetDatabase.CreateAsset(acfDataSo, acfScriptableObjectPath);
            AssetDatabase.Refresh();
        }
    }

//以下略

ADX2のランタイムからacf情報を読み込む

ランタイムからのacf情報読み込みは、CriAtomExAcfDebugクラスを経由して行います。
カテゴリー情報はGetNumCategoriesでカテゴリーの数を取得し、GetCategoryInfoByIndexでカテゴリの情報を取得できます。

CriAtomAcfViewerWindow.cs
    private List<CategoryInfo> LoadCategory()
    {
        List<CategoryInfo> categoryInfoList = new List<CategoryInfo>();

        for (ushort i = 0; i < CriAtomExAcfDebug.GetNumCategories(); i++)
        {
            CriAtomExAcfDebug.GetCategoryInfoByIndex(i, out var categoryInfo);

            categoryInfoList.Add(new CategoryInfo(
                categoryInfo.groupNo,
                categoryInfo.id, 
                categoryInfo.name,
                categoryInfo.numCueLimits,
                categoryInfo.volume));
        }

        return categoryInfoList;
    }

AISACコントロール情報も全く同様に、GetNumAisacControlsで数を取得し、GetAisacControlInfoで情報を取得できます。

CriAtomAcfViewerWindow.cs
    private List<AisacControlInfo> LoadAisacControlList()
    {
        List<AisacControlInfo> aisacControlInfoList =new List<AisacControlInfo>();

        for (ushort i = 0; i < CriAtomExAcfDebug.GetNumAisacControls(); i++)
        {
            CriAtomExAcfDebug.GetAisacControlInfo(i, out var aisacControlInfo);

            aisacControlInfoList.Add(new AisacControlInfo(
                aisacControlInfo.name,
                aisacControlInfo.id));
        }

        aisacControlInfoList.Sort((a,b) => (int)a.id - (int)b.id);

        return aisacControlInfoList;
    }

ウィンドウの各要素の描画

次に、ウィンドウを構成する各要素の描画処理を書いていきます。

ADX2AcfViewer.png

acf読み込みボタンの描画

「Load ACF data from runtime」ボタンは、EditorApplication.isPlayingを使ってゲームが実行中かどうかを判定し、実行中のみacfの読み込み処理を行います。
先ほど作成したScriptableObjectにカテゴリの情報、アイザックの情報を読み込み、保存します。

CriAtomAcfViewerWindow.cs
    private void DrawLoadButton()
    {
        GUILayout.BeginHorizontal();
        {
            if (GUILayout.Button("Load ACF data from runtime", GUILayout.Width(200), GUILayout.Height(50)))
            {
                if (!EditorApplication.isPlaying)
                {
                    Debug.LogError("Please load acf data in editor playing");
                }
                else
                {
                    acfDataSo = AssetDatabase.LoadAssetAtPath<AcfDataSo>(acfScriptableObjectPath);

                    acfDataSo.categoryInfoList = LoadCategory();
                    acfDataSo.aisacControlInfoList = LoadAisacControlList();

                    EditorUtility.SetDirty(acfDataSo);
                    AssetDatabase.SaveAssets();
                }
            }
            //中略
        }
        GUILayout.EndHorizontal();
    }

カテゴリー情報の項目名を描画

カテゴリー情報を表示する箇所の、「項目名」部分を描画します。
これらはボタンで構成されており、クリックすることでそれぞれの項目の昇順で並び替えを行うことができます。

CriAtomAcfViewerWindow.cs
    private void DrawCategoryItemNames()
    {
        List<CategoryInfo> categoryInfoList = acfDataSo.categoryInfoList;

        GUILayout.BeginHorizontal();
        {
            GUIStyle style = new GUIStyle(EditorStyles.miniButtonMid);
            style.alignment = TextAnchor.LowerLeft;

           if(GUILayout.Button("Category Name", style))
           {
               categoryInfoList.Sort((a,b) => String.CompareOrdinal(a.name, b.name));
           }

           if(GUILayout.Button("Volume", style, GUILayout.Width(80)))
            {
                categoryInfoList.Sort((a,b) => (int)a.volume - (int)b.volume);
            }

            if(GUILayout.Button("Cue Limit", style, GUILayout.Width(80)))
            {
                categoryInfoList.Sort((a,b) => (int)a.numCueLimits - (int)b.numCueLimits);
            }

            if(GUILayout.Button("Id", style, GUILayout.Width(80)))
            {
                categoryInfoList.Sort((a,b) => (int)a.id - (int)b.id);
            }

            if(GUILayout.Button("Group No", style, GUILayout.Width(80)))
            {
                categoryInfoList.Sort((a,b) => (int)a.groupNo - (int)b.groupNo);
            }
        }
        GUILayout.EndHorizontal();
    }

カテゴリーのリストを描画

カテゴリー情報のリストを順番に描画します。「カテゴリ名」の部分はボタンになっておおり、クリックするとそのカテゴリ名をクリップボードにコピします。
EditorGUIUtility.systemCopyBuffer を使うことで、簡単にクリップボードにアクセスできます。
ラジオボタンにしている理由は、見た目がリストっぽくなるためです。
クリックされた行はインデックスを保持しておき、黄色で表示します。

CriAtomAcfViewerWindow.cs
    private int selectedInfoIndex;

//中略

    private void DrawCategoryList()
    {
        List<CategoryInfo> categoryInfoList = acfDataSo.categoryInfoList;

        for(int i = 0; i < categoryInfoList.Count; ++i) {
            EditorGUILayout.BeginHorizontal();
            if (this.selectedInfoIndex == i) {
                GUI.color = Color.yellow;
            } else {
                GUI.color = Color.white;
            }

            var categoryName = categoryInfoList[i].name;

            if (GUILayout.Button(categoryName, EditorStyles.radioButton)) {

                EditorGUIUtility.systemCopyBuffer = categoryName;
                this.selectedInfoIndex = i;

                Debug.Log("Saved to clipboard " + "\""+categoryName+ "\"");
            }

            GUILayout.Label(categoryInfoList[i].volume.ToString(), GUILayout.Width(75));

            string numCueLimits = categoryInfoList[i].numCueLimits == UInt32.MaxValue
                ? "Unlimited"
                : categoryInfoList[i].numCueLimits.ToString();

            GUILayout.Label(numCueLimits, GUILayout.Width(75));

            GUILayout.Label(categoryInfoList[i].id.ToString(), GUILayout.Width(75));
            GUILayout.Label(categoryInfoList[i].groupNo.ToString(), GUILayout.Width(70));

            EditorGUILayout.EndHorizontal();

        }
        GUI.color = Color.white;
    }

キューリミットの値については、リミットを設定していない場合はuintの最大値( 4,294,967,295)が入るため、これと一致した場合は「Unlimited」と表示するようにしています。

AISACコントロール情報の項目名を描画

AISACコントロールについてもカテゴリと同様です。項目名をボタンで表示し、クリック時にソートを行います。

CriAtomAcfViewerWindow.cs
    private void DrawAisacControlItemNames()
    {
        List<AisacControlInfo> aisacControlInfoList = acfDataSo.aisacControlInfoList;

        GUILayout.BeginHorizontal();
        {
            GUIStyle style = new GUIStyle(EditorStyles.miniButtonMid);
            style.alignment = TextAnchor.LowerLeft;

            if (GUILayout.Button("Aisac Control Name", style))
            {
                aisacControlInfoList.Sort((a,b) => String.CompareOrdinal(a.name, b.name));
            }

            if (GUILayout.Button("ID", style, GUILayout.Width(80)))
            {
                aisacControlInfoList.Sort((a,b) => (int)a.id - (int)b.id);
            }
        }
        GUILayout.EndHorizontal();
    }

AISACコントロールのリストを描画

AISACコントロールの表示にはオプションとして「デフォルトのAISAC値を表示するかどうか」というチェックボックスを設けます。「AisacControl_00」のフォーマットでデフォルトでは16個用意されているため、これをリスト上で見せるか見せないかを切り替えます。

CriAtomAcfViewerWindow.cs
    bool hideDefaultAisacControls = true;

//中略

    private void DrawAisacControlList()
    {
        List<AisacControlInfo> list = acfDataSo.aisacControlInfoList;

        if (hideDefaultAisacControls)
        {
            list = list.Where(a => a.name.Contains("AisacControl_") == false).ToList();
        }

        for(int i = 0; i < list.Count; ++i) {
            EditorGUILayout.BeginHorizontal();
            if (this.selectedInfoIndex == i) {
                GUI.color = Color.yellow;
            } else {
                GUI.color = Color.white;
            }

            var aisacName = list[i].name;

            if (GUILayout.Button(aisacName, EditorStyles.radioButton)) {

                EditorGUIUtility.systemCopyBuffer = aisacName;
                this.selectedInfoIndex = i;

                Debug.Log("Saved to clipboard " + "\""+aisacName+ "\"");
            }

            GUILayout.Label(list[i].id.ToString(), GUILayout.Width(70));

            EditorGUILayout.EndHorizontal();
        }
        GUI.color = Color.white;
    }

OnGUIで各描画パーツを呼んでウィンドウを描画する

最後にOnGUIの中でDrawLoadButton、DrawCategoryItemNames、DrawCategoryList、DrawAisacControlItemNames、DrawAisacControlListをスクロールビューで囲みながら順番に呼びます。

CriAtomAcfViewerWindow.cs
    private Vector2 scrollPos_Window, scrollPosCategory, scroppPosAisacControl;

//中略

    public void OnGUI()
    { 
        DrawLoadButton();

        if (acfDataSo == null) return;

        this.scrollPos_Window = GUILayout.BeginScrollView(this.scrollPos_Window);
        {
            DrawCategoryItemNames();

            float categoryHeight = this.position.height - 300.0f;
            if (categoryHeight < 100.0f) categoryHeight = 100.0f;
            scrollPosCategory = EditorGUILayout.BeginScrollView(scrollPosCategory, GUILayout.Height(categoryHeight));

            DrawCategoryList();

            EditorGUILayout.EndScrollView();

            DrawAisacControlItemNames();

            float aisacControlHeight = this.position.height - 300.0f;
            if (aisacControlHeight < 100.0f) aisacControlHeight = 100.0f;

            scroppPosAisacControl = EditorGUILayout.BeginScrollView(scroppPosAisacControl);

            DrawAisacControlList();

            EditorGUILayout.EndScrollView();
        }

        GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(2));

        hideDefaultAisacControls = GUILayout.Toggle(hideDefaultAisacControls, "Hide default name AISAC controls");

        GUILayout.Space(10);
        EditorGUILayout.EndScrollView();
    }

一番下でGUILayout.Toggleを使って、デフォルトのAISACコントロール名を表示するかしないかのオプションを描画しています。

拡張性

今回は「カテゴリー」「AISACコントロール」のみを表示しましたが、acfにはほかの情報も含まれています。

全体設定.png

DSPバス設定やゲーム変数、セレクタなどが取得できますが、データの取得と描画方法は全く一緒です。プロジェクトに応じて必要な情報を見られるウィンドウを作ってみましょう。

また、保存したScriptable ObjectはEditor以外の位置に配置すればランタイムでも利用できます。

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

Unity メモ

キー入力

Input.GetKeyDown( KeyCode.Space );

カメラをプレイヤーに追従させる

CameraController.cs
public class CameraController : MonoBehaviour
{
    GameObject player;

    void Start()
    {
        this.player = GameObject.Find("player");
    }

    void Update()
    {
        Vector3 playerPos = this.player.transform.position;
        transform.position = new Vector3( transform.position.x, playerPos.y, transform.position.z );
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む