(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]

SRDebuggerなら実機でも使えるデバッグメニュー(Time.timeScaleの変更など)が簡単に作れる【Unity】【アセット】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 2018.2.17f1


はじめに


以前、実機上でコンソールのログを確認したり、簡易的なプロファイラが使えるSRDebugger

というアセットを紹介しました。


f:id:kan_kikuchi:20180524085806j:plain
f:id:kan_kikuchi:20180524092900j:plain


今回は、その時に詳細は省いた実機でも使えるデバッグメニュー(Options)についての記事です。

イメージとしては以下のような感じ。


f:id:kan_kikuchi:20190217120231g:plain:w700


基本的な使い方

基本的な使い方はpartial型のSROptionsを作り、そこにプロパティを実装するだけ。

public partial class SROptions {

  public float MyProperty {
    get;
    set;
  }

}


これだけでOptions欄にプロパティの確認、変更が行えるGUIが表示されるようになります。


f:id:kan_kikuchi:20190217105817g:plain


さらにプロパティの型によって自動でGUIが変わります。

(Boolean, Enum, int, uint, short, ushort, byte, sbyte, float, double, stringに対応)

public float MyProperty {
  get;
  set;
}

public bool BoolProperty {
  get;
  set;
}

public string StringProperty {
  get;
  set;
}

f:id:kan_kikuchi:20190217102423j:plain


ちなみにpartialとはクラスなどの定義を複数のファイルに分割して記述するためのものです。



イメージとしては元からあるSROptionsというクラスにコードを追加してる感じ。

(実際、SROptionsにコードを追加しても同じように動く)


f:id:kan_kikuchi:20190217101700j:plain
f:id:kan_kikuchi:20190217101712j:plain


ただし、SROptionsというクラス名は同じですが、ファイル名は同じに出来ません。

なので、SROptionsとは違うファイル名にしなければなりませんが、

その際、SROptionsのpartialと分かるようにSROptions.Gameplayなど、

SROptionsの後にドットで繋げる感じにすると良いでしょう。


f:id:kan_kikuchi:20190217100632j:plain


なお、Time.timeScaleなどの既に存在してる数値をプロパティから変える事も可能ですし、

public float TimeScale {
  get { return Time.timeScale; }
  set { Time.timeScale = value; }
}


読み取り専用にする事も可能です。

public partial class SROptions {

  public float MyProperty {
    get;
    private set;
  }

}

f:id:kan_kikuchi:20190217102858j:plain


また、実装したプロパティにはSROptions.Currentを使ってアクセスします。

float prop = SROptions.Current.MyProperty;



属性で表示や動作を変える

プロパティに特定の属性を付与するとGUIの表示や動作を変える事が出来ます。

ここからはその属性について説明していきます。

DisplayName

DisplayNameを使うと、GUI上の名前を変える事が出来ます。

(デフォルトではプロパティの名前がそのまま表示される)

[DisplayName("ディスプレイネーム")]//ディスプレイネームと名前が表示されるように
public float MyProperty {
  get;
  set;
}

f:id:kan_kikuchi:20190217105915j:plain


NumberRange

NumberRangeを使うと、最小値と最大値を設定出来ます。

[NumberRange(0, 10)]//0 ~ 10の値で収まるように
public float MyProperty {
  get;
  set;
}

f:id:kan_kikuchi:20190217110338g:plain


Increment

Incrementを使うと、ボタンを押した時の減少値と増加値を設定出来ます。

(デフォルトでは1ずつ増減する)

[Increment(2.5f)]//ボタンを押した時に2.5ずつ増減するように
public float MyProperty {
  get;
  set;
}

f:id:kan_kikuchi:20190217110635g:plain


Category

Categoryを使うと、そのプロパティにカテゴリを設定出来ます。

GUI上ではカテゴリごとにまとめて表示されるようになります。

//Categoryの属性を使うのに必要
using System.ComponentModel;
[Category("カテゴリ1")]//カテゴリ1というCategoryを設定
public float MyProperty1 {
  get;
  set;
}

[Category("カテゴリ1")]//MyProperty1と同じく、カテゴリ1というCategoryを設定
public float MyProperty2 {
  get;
  set;
}

[Category("カテゴリ2")]//MyProperty1と2とは別のカテゴリ2というCategoryを設定
public float MyProperty3 {
  get;
  set;
}

f:id:kan_kikuchi:20190217110551j:plain


ちなみに1画面に表示出来ない場合は、スクロール出来るようになります。


f:id:kan_kikuchi:20190217111102g:plain


Sort

通常、先に宣言したものがGUI上では右に表示されます。

public float MyProperty1 {
  get;
  set;
}

public float MyProperty2 {
  get;
  set;
}

public float MyProperty3 {
  get;
  set;
}

f:id:kan_kikuchi:20190217111147j:plain


Sortを使えば、この表示順を変更(低い値のやつほど左に)出来ます。

[Sort(0)]
public float MyProperty1 {
  get;
  set;
}

[Sort(1)]
public float MyProperty2 {
  get;
  set;
}

[Sort(2)]
public float MyProperty3 {
  get;
  set;
}

f:id:kan_kikuchi:20190217111157j:plain


ただし、同じカテゴリ内の順序を変更するだけなので、カテゴリの上下は出来ません。

(カテゴリは先に宣言したものが上に表示される)

[Category("カテゴリ1"), Sort(1)]
public float MyProperty1 {
  get;
  set;
}

[Category("カテゴリ2"), Sort(0)]
public float MyProperty2 {
  get;
  set;
}

f:id:kan_kikuchi:20190217111348j:plain


メソッドでデバッグメニューを作成

ここまでの例ではプロパティを使ってデバッグメニューを作成していましたが、

同じようにメソッドを使う事も可能です。


ただし、使えるメソッドはpublicかつ返り値がvoid、そして引数がないものに限ります。

using UnityEngine;

public partial class SROptions {
  
  public void Pause() {
    Time.timeScale = 0f;
    Debug.Log("ポーズ!");
  }

}

f:id:kan_kikuchi:20190217133123g:plain


なお、前述した属性のうち、DisplayNameとCategoryはメソッドでも使えます。

using UnityEngine;

public partial class SROptions {
  
  [DisplayName("ポーズ"), Category("たいむすけーる")]
  public void Pause() {
    Time.timeScale = 0f;
    Debug.Log("ポーズ!");
  }

}

f:id:kan_kikuchi:20190217132136j:plain


GUIの更新にはOnPropertyChanged

OPTIONSのGUIは、開いた時か操作した時に更新されるので、以下のように

timeScaleをメソッド(Pause)のGUIで操作した場合、プロパティ(TimeScale)のGUIは更新されません。

[NumberRange(0, 1), Increment(0.2f)]
public float TimeScale {
  get { return Time.timeScale; }
  set { Time.timeScale = value; }
}

public void Pause() {
  Time.timeScale = 0f;
}

f:id:kan_kikuchi:20190217112820g:plain


そんな時はOnPropertyChanged(引数にプロパティ名)を使います。

値の変更後にOnPropertyChangedを実行すればGUIを更新する事が出来ます。

[NumberRange(0, 1), Increment(0.2f)]
public float TimeScale {
  get { return Time.timeScale; }
  set { Time.timeScale = value; }
}

public void Pause() {
  Time.timeScale = 0f;
  //TimeScaleのプロパティが変更された事を通知し、GUIを更新
  OnPropertyChanged("TimeScale");
}

f:id:kan_kikuchi:20190217112915g:plain


ピン留めで画面上に固定

OPTIONSはピン留めする事で画面上でデバッグメニューを固定する事が出来ます。


f:id:kan_kikuchi:20190217113547g:plain


ただ、エディタの再生を終了したり、実機ならアプリを再起動したらこの固定は解除されてしまいます。

なので、最初から固定しておきたいメニューは以下のようにプログラムで指定する必要があります。

//名前を指定して、メニューをピン留めする
SRDebug.Instance.PinOption("ディスプレイネーム");
//解除する時はUnpinOption
//SRDebug.Instance.UnpinOption("ディスプレイネーム");

//カテゴリを指定して、そのカテゴリ内の全メニューをピン留めする
SRDebug.Instance.PinAllOptions("カテゴリ1");
//解除する時はUnpinAllOptions
//SRDebug.Instance.UnpinAllOptions("カテゴリ1");

//ピン留めされているものを全て解除
//SRDebug.Instance.ClearPinnedOptions();



おわりに

エディタ上ではエディタ拡張を使って、わりと簡単にデバッグメニューは作れますが、


f:id:kan_kikuchi:20180328201056g:plain


これを実機でやろうとすると結構、手間がかかったりします。

そんな手間をSRDebuggerを使えばかなり削減出来るという話でした。