FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »Unity
カテゴリー「Unity」の記事一覧

【Unity】EventTrigger のコールバック引数変わった?  


 先に結論を述べておくと、どうやらバグだったらしい。

 Unity2018.4.10f1 を使っているとき、ふとアタッチしてある EventTrigger のコールバックが "<Missing~ >" になっていて、原因がわからなかったのだが、Unity2018.4.11f1 にアップデートしたら直った。

(※) Unity 2018.4.8f1 - 2018.4.11f1 / Windows10(x64) で確認

 具体的に言うと、バージョンによって以下のように、コールバック引数の表示が違う。
 
●Unity2018.4.8f1 以前(引数が BaseEventData)


●Unity2018.4.9f1 ~ 4.10f1(引数が無い?!)


●Unity2018.4.11f1(引数が BaseEventData)



 Unity2018.4.11f1 の Release Note を見てみたが、明示的に EventTrigger とは書いてないので、

・UI: Fixed the UnityEvent property drawer showing UnityEvents in private properties correctly. (1178687, 1186175)

の関連の気がする。

 まぁ、このバグがあるとインスペクタから Dyanamic な引数でメソッドを登録できないので、早めに Unity2018.4.11f1 以降にアップデートした方が良いだろう。





(関連記事)
【Unity】【Android】2019.2.0 でパッケージ名(Bundle Identifer)でアンダーバーが使えない
【Unity】Unity2018.3.2 にアップグレードすると見た目がおかしくなることがある
【Unity】Unity2018 でビルドエラー「CommandInvokationFailure: Gradle build failed.」が出る


スポンサーサイト



category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityトラブルシューティング  Unityバグ 
tb: 0   cm: --

【Unity】【C#】BMP をランタイムで読み込む  


 実は VRM Live Viewer には既に導入されているのだが、BMP を画像素材(テクスチャ)として利用したいこともあるだろう。実装当時、ググっても英語サイトしか出てこなかったので、需要は少ないのかも知れないが、探すのに苦労しないように備忘録として残しておく。

 今回紹介する方法は、オープンソースの BMPLoader を使う方法だ。

 以前「ランタイム時にファイルをドラッグ&ドロップして取得する」で紹介した「UnityWindowsFileDrag-Drop」の作者の Bunny83 さんの配布ライブラリで、とても簡単に扱えたので、その方法を書いておこう。


(※) Unity 2018.4.8f1 / Windows10(x64) で確認



■BMPLoader を導入する

 導入方法は簡単だ。以下の公開サイトへ行き、コピペで C# ファイルを作って欲しい。ページの一番下の方に「Raw Paste Data」という欄があるので、ここからコピーするのが簡単だろう。

BMPLoader.cs





■簡単なサンプルを作ってみる(基本的なコード)

 ググってみるといくつか出てくるので、以下などを参考にするのも良いだろう。

How to load a BMP file in binary?
How can I use a .bmp file and create a Texture in Unity at runtime?

 実際には BMPLoader.LoadBMP() はいくつかオーバーロードがあるので、利用方法によって使い分けるのも良いかも知れない。ここでは後述する「非同期ロードに対応してみる」に合わせた書き方となっている。定義をみて自分なりに書き換えるのも良いだろう。

●BMPLoadTest.cs(※名前は任意)
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using B83.Image.BMP;

public class BMPLoadTest : MonoBehaviour
{
public RawImage image; //読み込み先(※インスペクタで UI を設定)
public string filePath = "c:/test/image/sample.bmp"; //※ファイルは任意

// Use this for initialization
private void Start()
{
var bytes = File.ReadAllBytes(filePath);
var loader = new BMPLoader();
//loader.ForceAlphaReadWhenPossible = true; // can be uncomment to read alpha
var bmpImage = loader.LoadBMP(bytes);
image.texture = bmpImage.ToTexture2D();
}

private void OnDestroy()
{
if (image.texture != null)
{
Destroy(image.texture);
image.texture = null;
}
}
}
#endif

 このサンプルではエラーのチェック等は省略しているので、あくまで全て必要なもの(ファイルとか)が揃っている場合であることを留意しておいて欲しい。

 とりあえず、BMP をロードして表示できたなら成功だ。





■非同期ロードに対応してみる

 とりあえず前述の基本的なコードでも十分なのだが、動作確認が取れたなら、ちょっと手を加えて非同期読み込みすると良いかも知れない。ただし、以下のコードは .NET 4.x 以降である必要がある。

●BMPLoadTest.cs(※名前は任意)
using System.IO;
using System.Threading.Tasks; //※追加
using UnityEngine;
using UnityEngine.UI;
using B83.Image.BMP;

public class BMPLoadTest : MonoBehaviour
{
public RawImage image; //読み込み先(※インスペクタで UI を設定)
public string filePath = "c:/test/image/sample.bmp"; //※ファイルは任意

// Use this for initialization
private async void Start() //※async を追加
{
var bytes = await Task.Run(() => File.ReadAllBytes(filePath)); //※Task で別スレッドで読み込み
var loader = new BMPLoader();
//loader.ForceAlphaReadWhenPossible = true; // can be uncomment to read alpha
var bmpImage = await Task.Run(() => loader.LoadBMP(bytes)); //※Task で別スレッドでロード
image.texture = bmpImage.ToTexture2D();
}

private void OnDestroy()
{
if (image.texture != null)
{
Destroy(image.texture);
image.texture = null;
}
}
}
#endif

 ファイルの大きさにもよるが、私が計測したところ、非同期にすれば約1.5倍くらいの速度で読み込める。もし、UniRx を使っているのなら、Task は UniTask にした方が良いだろう。

 ちなみに私が提供しているプラグインを使えば、Android でも BMP を読み込めた。実際にスマホで全天球ビューワを作ることも可能だ(これが VRM Live Viewer で実装されている)。

 ここでは簡単なサンプルなので Start() でやってしまったが、static なメソッドにしてしまえば、使い回しもできて非常に便利だ。その場合にはファイル名やファイル自体の存在チェック、非同期キャンセルのための CancellationToken など入れた方が良いだろう。Task.Run() は2回に分けてあるが、ファイル読み込み/テクスチャとしてロードするのに時間がかかることを考慮して、それぞれにキャンセルチェックをした方が良いと思う(きちんと実装すると結構長くなるため、今回は要点だけにした)。その辺りはご自由に(笑)。






(関連記事)
【Unity】【C#】ランタイム時にファイルをドラッグ&ドロップして取得する(Windows のみ)
【Unity】スマホで簡易360度(パノラマ, 全天球)ビューワを作る
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】AssetStore版 FantomPlugin のセットアップ


category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityオープンソースライブラリ  画像ファイル読み込み 
tb: 0   cm: --

【Unity】【C#】制限付きでテキストのサイズに合わせて他のオブジェクトのサイズも変化させる  


 ContentSizeFitter を使えば近い感じにもなるが、最小~最大みたいになると、レイアウトの入れ子になったり、オブジェクトを階層化しなくてはならなかったりと複雑になる気がするので、もっと簡単にできるものないかとググってみたら、やはり同じ様なものがあった

TextSizeAdjuster



 ただ試してみたら、ちょっと私が欲しい挙動と違ったので、元のスクリプトを参考に改造してみた。簡単に言えば「テキストの幅が最小~最大サイズまでは伸縮し、最大を超えたら折り返す」みたいにできるようにスクリプトに書き換えた。

 まぁ、自動レイアウトを駆使すれば同じことはできるかもしれないが、実は私も自動レイアウトは苦手なので、今回のスクリプト1つで簡単に実現できるのなら、それもアリかと(笑)。

【Unity】uGUIの自動レイアウトが分かりにくいと評判なので解説してみる

(※) Unity 2018.4.8f1 / Windows10(x64) で確認



■テキストのサイズに合わせて他のオブジェクトのサイズも変化させる(サイズ制限付き)

●TextSizeSync.cs
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif

/// <summary>
/// https://gist.github.com/iwashihead/db6e88e7de74f43c43fb9ebbd6769516
/// を改造
/// Text の preferredWidth / preferredHeight に合わせて
/// 他の RectTransform のサイズも変更する.
/// </summary>
[ExecuteInEditMode]
//[ExecuteAlways]
public class TextSizeSync : MonoBehaviour
{
//サイズを調整する方向
public enum AdjustMode
{
Width, Height, Both,
}
public AdjustMode adjustMode = AdjustMode.Width;

public bool alwaysAdjust = false; //Update でテキスト変化を検出

public Text referenceText; //サイズを参照するテキスト

public float minWidth = -1; //調整する最小幅 (※負で無視)
public float maxWidth = -1; //調整する最大幅 (※負で無視)
public float minHeight = -1; //調整する最小高 (※負で無視)
public float maxHeight = -1; //調整する最大高 (※負で無視)

//同期させるオブジェクトの余白(テキストサイズ+余白になる)
public RectOffset padding = new RectOffset();

//サイズを同期させるオブジェクト
public RectTransform[] syncRectTransforms = new RectTransform[0];


//Editor only
private void Reset()
{
if (referenceText == null)
referenceText = GetComponent<Text>();
}

//Editor only
private void OnValidate()
{
if (referenceText != null)
Adjust();
}

private void OnEnable()
{
if (referenceText != null)
Adjust();
}

// Use this for initialization
private void Start()
{
Adjust();
}

// Update is called once per frame
private void LateUpdate()
{
if (alwaysAdjust && IsTextChanged)
Adjust();
}

string _oldText;

//テキストの内容が変化したか?
public bool IsTextChanged {
get {
if (_oldText == null || _oldText != referenceText.text)
{
_oldText = referenceText.text;
return true;
}
return false;
}
}

//サイズの調整
public void Adjust()
{
switch (adjustMode)
{
case AdjustMode.Width:
AdjustWidth();
break;
case AdjustMode.Height:
AdjustHeight();
break;
case AdjustMode.Both:
AdjustBoth();
break;
}

AdjustSyncRectTransforms();
}


Vector2 _size = Vector2.zero;

//幅を調整
void AdjustWidth()
{
var w = ClampWidth(referenceText.preferredWidth);
var h = referenceText.rectTransform.sizeDelta.y;
_size.Set(w, h);
referenceText.rectTransform.sizeDelta = _size;
}

//高さを調整
void AdjustHeight()
{
var w = referenceText.rectTransform.sizeDelta.x;
var h = ClampHeight(referenceText.preferredHeight);
_size.Set(w, h);
referenceText.rectTransform.sizeDelta = _size;
}

//幅・高さの両方を調整
void AdjustBoth()
{
var w = ClampWidth(referenceText.preferredWidth);
var h = ClampHeight(referenceText.preferredHeight);
_size.Set(w, h);
referenceText.rectTransform.sizeDelta = _size;
}

//幅の制限
float ClampWidth(float w)
{
if (minWidth >= 0) w = Mathf.Max(minWidth, w);
if (maxWidth >= 0) w = Mathf.Min(maxWidth, w);
return w;
}

//高さの制限
float ClampHeight(float h)
{
if (minHeight >= 0) h = Mathf.Max(minHeight, h);
if (maxHeight >= 0) h = Mathf.Min(maxHeight, h);
return h;
}

//他の RectTransform のサイズ同期(余白付き)
void AdjustSyncRectTransforms()
{
var w = ClampWidth(referenceText.preferredWidth);
var h = ClampHeight(referenceText.preferredHeight);

foreach (var rt in syncRectTransforms)
{
var x = rt.sizeDelta.x;
var y = rt.sizeDelta.y;
switch (adjustMode)
{
case AdjustMode.Width:
x = padding.left + w + padding.right;
break;
case AdjustMode.Height:
y = padding.top + h + padding.bottom;
break;
case AdjustMode.Both:
x = padding.left + w + padding.right;
y = padding.top + h + padding.bottom;
break;
}
_size.Set(x, y);
rt.sizeDelta = _size;
}
}
}


#if UNITY_EDITOR
//※エディタ用
//OnValidate() では他のコンポーネント変化が検知できないので、
//インスペクタの更新で変化をチェックする
[CustomEditor(typeof(TextSizeSync))]
public class TextSizeSyncEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();

var obj = target as TextSizeSync;
if (obj.IsTextChanged)
{
obj.Adjust();
}
}
}
#endif

 色々付け加えたので長くなった(笑)。まぁ、少し古いバージョン(.NET3.5)でも対応できるようにしてるせいもあるけどね。
"[ExecuteInEditMode]" なんかもいつの間にか "[ExecuteAlways]" になったらしいしね。

 使い方は、参照する Text と同じ GameObject にアタッチし、変化させたいオブジェクトを syncRectTransforms に登録するだけだ。あとは最小~最大サイズや余白を設定しておく。






●例えば以下のようタグを囲むのに使っている


※ただし、レイアウトの計算は同じフレーム内では上手く反映されないので、1フレーム遅らせて反映させた方が確実。



 ちなみに、gif アニメの ContetnSizeFitter と TextSizeAdjuster の設定は以下のようになる。



●ContentSizeFitter ① を使い、LayoutElement で MinWidth を設定





●ContentSizeFitter ② を使い、LayoutElement で MinWidth, PereferedWidth を設定





●TextSizeAdjuster と ContentSizeFitter を使う

TextSizeAdjuster






 まぁ、自動レイアウトを極めれば色々できるかも知れないが、とにかく組み合わせを考えるのが大変なので、何重にもレイアウトの入れ子になるくらいなら、簡単なスクリプトを作るのも1つの手かも知れない(笑)。

【Unity】uGUIの自動レイアウトが分かりにくいと評判なので解説してみる
【Unity】逆引き自動レイアウトのトレーニング。UIをLayoutGroupで並べる
逆引き、UnityのuGUIのレイアウトトレーニング(uGUI RectTransform入門その2)






(関連記事)
【Unity】【C#】RectTransform の矩形の実座標を取得する
【Unity】【C#】uGUI ドロップダウンの要素をコードで設定と取得、外観のカスタマイズなど
【Unity】【C#】インスペクタの表示項目を動的に変更する
【Unity】【C#】独自のギズモ(Gizmo)を表示する


category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  uGUI 
tb: 0   cm: --

【Unity】【C#】インスペクタで入力不可(Disable)な属性を作る  


 インスペクタに表示するだけで、インスペクタからは入力はできないフィールドを作りたいときは良くある。デバッグ用に表示だけしたいときとかね。

 サードパーティのインスペクタの拡張アセットなどにはよく付いているのだが、インポートするまでもなく、簡単に済ませたいときなどに便利なので掲載しておこう。何でもかんでもアセット導入すると、ファイルが増えすぎてビルド時間も長くなるしね。自作なら色々応用効くのも魅力だ(笑)。

(※) Unity 2018.4.8f1 / Windows10(x64) で確認



 必要なスクリプトは PropertyAttribute を継承した属性用スクリプトと、PropertyDrawer を継承したエディタ(インスペクタ)用スクリプトになる。エディタ表示用スクリプトは「Editor」フォルダを作って、そこに置いておく必要がある。

PropertyAttribute
PropertyDrawer



●属性用スクリプト:DisableAttribute.cs
using UnityEngine;

public class DisableAttribute : PropertyAttribute
{
//※中身は空で良い
}

●エディタ表示用スクリプト:DisableDrawer.cs
using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(DisableAttribute))]
public class DisableDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label, true);
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
GUI.enabled = false; //ここで入力不可にしている
EditorGUI.PropertyField(position, property, label, true);
GUI.enabled = true; //元に戻しておく
}
}


 例として適当な GameObject にテスト用スクリプトをアタッチして、インスペクタの表示を見てみよう。



●テスト用スクリプト:DisableAttributeTest.cs(※名前は任意)
using UnityEngine;

public class DisableAttributeTest : MonoBehaviour
{

[Disable] public string str = "hoge"; //インスペクタからは入力できない
[SerializeField, Disable] int num = 1; //インスペクタからは入力できない

[HideInInspector] public float f = Mathf.PI; //※これは単にインスペクタに表示しない例
}

 今回作ったのは "[Disable]" という属性だ。以前のバージョンでは "[DisableAttribute]" と書く必要があったらしいが、現在の Unity バージョンでは "Attribute" は省略できる。

 "[HideInInspector]" は単に表示したくないときの属性で、元々 Unity にビルトインされている。他にも色々な属性があるので、少し古いが、以下に資料を載せておこう。

UnityのAttribute(属性)についてまとめてメモる。

 アセットによっては "[ReadOnly]" などになってるかもだが、C# Job System でも使われる属性なので、今後はコンフリクトするかも知れない。その場合は namespace を付けておくのも一つの手だ。もっと色々自作したいなら、以下も少し古いが、資料を載せておこう。

自分だけのPropertyDrawerを作ろう!






(関連記事)
【Unity】インスペクタの値を保持したまま変数をリネームする
【Unity】【C#】インスペクタでの UnityEvent のコールバック登録の有無を調べる
【Unity】【C#】UnityEvent, Action, delegate, interface でのコールバック実装方法とインスペクタでの登録
【Unity】【C#】インスペクタの表示項目を動的に変更する
【Unity】【C#】独自のギズモ(Gizmo)を表示する


category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityリファレンス  エディタ拡張 
tb: 0   cm: --

【Unity】5ボタンマウスの KeyCode 図解  


 Unity の UI 操作でも、マウスのバックボタンが使えたら少し便利かな、と思って調べてみたら、簡単だった(笑)。早速「VRM Live Viewer」に導入してみたら、結構良い感じ。クリティカルでない「はい/いいえ」の2択を「進む(フォワード)/戻る(バック)」ボタンで操作できたら、色々楽になるかもね。

 何でも図や表にしておくのは、ただの私のクセ。まぁ、何度もマニュアルを見て探すのが億劫なので、一見してわかるものが欲しいだけなんだけどね(笑)。

KeyCode

(※) Unity 2018.4.6f1 / Windows10(x64) で確認



■マウスのボタンと KeyCode 対応図


 あくまでもデフォルト状態なので、専用ドライバ等でカスタマイズしてる場合は定かではない。たぶん、ゲーミングマウスみたいな多ボタンマウスも 5~n で行けるんだろうね(※未確認)。

 判定するメソッドは Input.GetKey / GetKeyDown / GetKeyUp などお好みで。

 Input.GetMouseButtonDown(int) などでも引数の番号を入れれば、マニュアルには 0~2 までしか書いてないが、3, 4 でもバック/フォワード判定できるみたい

 ホイールの Input.mouseScrollDelta はオマケ(笑)。

(マニュアル)
KeyCode
Input.GetKey
Input.GetKeyDown
Input.GetKeyUp
Input.GetMouseButton
Input.GetMouseButtonDown
Input.GetMouseButtonUp
Input.mouseScrollDelta
Input.GetAxis



[マウス イラスト素材]
無料イラスト素材倉庫 (※少し加工)






(関連記事)
【Unity】【C#】KeyCode をリアルタイムで調べる / Windows 日本語キーボードでの記号の KeyCode 一覧
【Unity】【C#】長押し(ロングタップ)を取得してコールバックする
【Unity】【C#】スワイプ(フリック)を判定、方向を取得してコールバックする
【Unity】【C#】ピンチ操作を取得してコールバックする


category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityリファレンス  図解 
tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop