LessonEX 小ネタ
ページ数節約用 ページを作るほどでもないかなって感じの小ネタ集です。
項目ごとに関連性はないので、気になる内容だけ見てください。
EX-1 Attributeについて
変数やクラスにAttribute(属性)をつけることで、特殊な挙動を設定することができます。ここでは制作を補助するAttributeを中心に紹介していきます。
よく使うのは [SerializeField] で、これを付与した変数はprivateでもインスペクター内に表示されるようになります。
移動速度やジャンプ力など、後から調整したいパラメータにつけておくと便利です。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Test : MonoBehaviour
{
// インスペクターに表示されるprivate変数
[SerializeField]
int TestNum;
}

変数をpublicにしておくとどこから編集されるかわからない、というリスクがあります。ですが変数をprivateにするとインスペクターから値を編集できなくて不便です。
そういった問題を解決したい時は [SerializeField] を使いましょう。
[Header("テスト")] を使うことで、変数名の前に文章を表示することができます。日本語も使用可能です。
また、アトリビュートは,(カンマ)で区切ることで一度に複数付与することができます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Test : MonoBehaviour
{
// インスペクターに表示されるprivate変数
[SerializeField, Header("テスト用変数")]
int TestNum;
}

移動用パラメータや攻撃用パラメータなど、項目ごとにHeaderを使うと後から見やすいインスペクターになります。
[Range(0, 100)] を使うことで、第一引数から第二引数の範囲内に収まるスライダーを表示することができます。サンプルでは0~100の範囲で動かせるスライダーを作っています。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Test : MonoBehaviour
{
// インスペクターに表示されるprivate変数
[SerializeField, Header("テスト用変数")]
int TestNum;
// 指定した範囲内に収まるスライダー
[Range(0, 100)]
public int TestSlider;
}

ここで指定できる範囲はあくまでインスペクター内で有効です。スクリプトから範囲外の変数を代入したとしても、自動で範囲内に収めてくれる訳ではないので注意してください。
[Tooltip("テスト")] を使うことで、インスペクター内の変数にマウスカーソルが重なっている時にメッセージを表示することができます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Test : MonoBehaviour
{
// インスペクターに表示されるprivate変数
[SerializeField, Header("テスト用変数")]
int TestNum;
// 指定した範囲内に収まるスライダー
[Range(0, 100), Tooltip("マウスが重なった時に表示")]
public int TestSlider;
}

改行コード(¥n)を使うと改行もできます。

特に複雑な用途の変数は、後から見返したときにどういった変数か忘れてしまうこともあるので、Tooltipを使って注釈を書いておくと良いでしょう。
string型の変数はAttributeを付与しなかった場合1行しか記入できませんが、[Multiline] を使うことで複数行記入することができるようになります。
引数に行数を設定することもできます。ただし行数を0から数えているので、10行書けるようにしたい場合は11を引数にする必要があります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Test : MonoBehaviour
{
// インスペクターに表示されるprivate変数
[SerializeField, Header("テスト用変数")]
int TestNum;
// 指定した範囲内に収まるスライダー
[Range(0, 100), Tooltip("マウスが重なった時に表示\n改行も可")]
public int TestSlider;
// 指定行数記入できるstring
[Multiline(11)]
public string TestString;
}

[TextArea(2,11)] を使うことで最小行数と最大行数を指定することもできます。サンプルでは最初は1行分の欄しかありませんが、行数を増やすと10行目まで拡張されていきます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Test : MonoBehaviour
{
// インスペクターに表示されるprivate変数
[SerializeField, Header("テスト用変数")]
int TestNum;
// 指定した範囲内に収まるスライダー
[Range(0, 100), Tooltip("マウスが重なった時に表示\n改行も可")]
public int TestSlider;
// 指定行数記入できるstring
[TextArea(2,11)]
public string TestString;
}


クラスに設定できるAttributeもあります。
クラスに [DisallowMultipleComponent] を付与することで、同じオブジェクトに同じコンポーネントが複数アタッチできないようにできます。同じオブジェクトにうっかり同じコンポーネントを複数アタッチしてしまうことがありますが、それをエラー文で防げるようになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 複数アタッチできないようにする
[DisallowMultipleComponent]
public class EXK_Test : MonoBehaviour
{
// インスペクターに表示されるprivate変数
[SerializeField, Header("テスト用変数")]
int TestNum;
// 指定した範囲内に収まるスライダー
[Range(0, 100), Tooltip("マウスが重なった時に表示\n改行も可")]
public int TestSlider;
// 指定行数記入できるstring
[TextArea(2,11)]
public string TestString;
}


関数に設定するAttributeも解説します。
[RuntimeInitializeOnLoadMethod()] と記述すると、設定した関数はゲーム起動時のシーンを開く前に呼ばれます。クラスをオブジェクトにアタッチする必要はありません。
ただし対象とする関数をstaticにする必要があるので注意しましょう。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Test : MonoBehaviour
{
[RuntimeInitializeOnLoadMethod()]
static void GameInit()
{
Debug.Log("どのシーンから開始しても呼ばれる");
}
}
この関数はどのシーンからゲームを開始しても呼ばれます。どのシーンにも共通で生成したいオブジェクトがある場合や、初期化したいものがある場合に使ってみてください。

Attributeを使うことでインスペクターの操作が楽になるので、ぜひ活用してみましょう。
【参考】https://tsubakit1.hateblo.jp/entry/2015/01/03/203843
EX-2 アニメーションステートが難しい人へ
過去のLessonではアニメーションステートを使ってアニメーションを遷移させていました。
ですが「アニメーションステートは複雑で扱いにくい…」という感想を持った人もいると思います。そういった人向けに簡単にアニメーションを管理する方法を解説します。
まずはアニメーションに対応したパラメータを用意します。
今回はパラメータの型にTriggerを使用します。これは名前の通りトリガーのように一瞬だけ有効判定されるもので、有効にした瞬間だけtrueになって、直後自動的にfalseになるbool型をイメージするのがわかりやすいかと思います。


Any Stateから全てのステートへ伸びるトランジションを作成してください。
Any StateはAny(どれでも)の名の通り、どのステートからでも繋げられるステートになります。

トランジションの設定も今までと変わりません。
Conditionsには対応したTrigger型のパラメータを指定してください。

もし複数の遷移条件を同時に満たした場合、Transitionsの上部にある項目が優先されます。ドラッグ&ドロップで並び替えることが可能です。

後はAnimatorを取得して、SetTrigger関数でパラメータを変更するだけです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EXK_Player : MonoBehaviour
{
Animator m_animator;
void Start()
{
// 自分にアタッチされたアニメーターを取得
m_animator = GetComponent<Animator>();
}
void Update()
{
// キーに応じてアニメーションを変更
if (Input.GetKeyDown(KeyCode.Alpha1))
{
m_animator.SetTrigger("Idle");
}
if (Input.GetKeyDown(KeyCode.Alpha2))
{
m_animator.SetTrigger("Run");
}
if (Input.GetKeyDown(KeyCode.Alpha3))
{
m_animator.SetTrigger("Jump");
}
if (Input.GetKeyDown(KeyCode.Alpha4))
{
m_animator.SetTrigger("Damage");
}
if (Input.GetKeyDown(KeyCode.Alpha5))
{
m_animator.SetTrigger("Clear");
}
}
}
KeyCode.Alpha1 などは1キー、2キーなどを示すKeyCodeになります。
これで比較的直感的にアニメーションを操作することが可能です。
ただしどのステートからでも同じ設定で遷移してしまうので注意してください。「待機状態から歩き状態に切り替える時だけはこうやって遷移したい!」という条件がある場合は、今まで通り各トランジションを繋ぐ必要があります。
EX-3 検索欄の隠し機能
Unityの検索欄には隠し機能があります。
ヒエラルキー内の検索欄はオブジェクトの名前だけでなく、コンポーネント名を入力することで「そのコンポーネントがアタッチされているオブジェクト」を検索することができます。RigidbodyなどUnity標準のコンポーネントだけでなく、自分で作ったコンポーネントも検索できます。


EX-4 EditorOnlyタグ
Unityに標準で実装されている「EditorOnly」タグを設定したオブジェクトは、Unityエディタ上でのみ存在するオブジェクトになります(ビルド時に自動で削除される)
デバッグ用に使うことができます。

EX-5 オブジェクトのアイコン
インスペクター左上でオブジェクトのアイコンを設定することができます。
例えば上部のアイコンを設定すると、シーン内でオブジェクト名を確認できるようになります。


アイコンを設定することで、モデルやスプライトが設定されていない透明なオブジェクトでも、シーン内の場所を確認しやすくなります。例えばマップ移動用の当たり判定など「透明だけど場所はわかりやすくしたい」オブジェクトに設定すると便利です。


オブジェクトだけでなく、スクリプトにもアイコンを設定することができます。
「Other…」ボタンをクリックすることで好きな画像をアイコンに指定することも可能です。

アイコンを設定したスクリプトをアタッチすると、そのスクリプトに設定したアイコンがシーン内で表示されます。
例えば敵に共通してアタッチするEnemyスクリプトや、アイテムに共通してアタッチするItemスクリプトなどがある場合、スクリプトにアイコンを設定することでより分かりやすくすることができます。


アイコンを設定したスクリプトが複数アタッチされている場合は、インスペクター内で上部にあるスクリプトのアイコンが優先されます。
アイコンを設定することで制作をスムーズに進めましょう。
【公式マニュアル】https://docs.unity3d.com/ja/2019.4/Manual/AssigningIcons.html

EX-6 ラベルとお気に入り
アセットにラベルを設定することで、素材を管理しやすくすることができます。
アセットを選択中、右下のAsset Labelsボタンからラベルを設定できます。Unity側でよく使いそうな名前は用意してくれていますが、用意されていない名前を入力して好きな名前のラベルを作ることもできます。
設定したラベルはインスペクター下部に並びます。複数設定することもできるので、区別しやすいように設定してください。


プロジェクトウィンドウの右上のボタンから、選択したラベルに絞り込むことができます。

ラベル検索の隣には素材の分類(ScriptやModelなど)で絞り込むことができます。

プロジェクトウィンドウ右上の★マークのボタンで、現在の検索状態を「お気に入り」として保存することもできます。
開発を効率化する機能なので、状況に応じて使ってください。


EX-7 物理演算の更新について
Unityには物理演算が搭載されていますが、衝突解決やOnCollisionEnterなどの関数の呼び出しはどのタイミングで行われるのでしょうか。
Project SettingsのTime内にFixed Timestepという項目があります。ここが物理演算の更新やFixedUpdate関数が呼ばれる周期になります。物理演算の更新頻度を上げたい場合は小さい値にすることで精度を上げられますが、その分負荷がかかるため注意しましょう。

一定周期での物理演算更新ではUpdate関数との噛み合いが悪い場合、更新のタイミングを変更することができます。
例えば「Update関数内の任意のタイミングでOnTriggerEnter関数の更新を行いたい」といったパターンです。物理演算の更新は一定周期で行われますがUpdate関数は毎フレーム実行されるため、このままでは2つの関数の更新タイミングにずれが生じることになります。
Project SettingsのPhysics(2Dの場合はPhysics 2D)にはSimulation Modeという、物理演算の更新タイミングを指定するパラメータがあります。

【各設定の違い】
・Fixed Update
初期設定です。前述したFixed Timestepごとの周期で物理演算が更新されます。処理は安定していますが、Update関数との噛み合いは悪いです。
・Update
Update関数の実行後に物理演算が更新されます。FPSによって実行頻度が可変となるため、Fixed Updateに比べて更新頻度は安定しません。
ただし、Update関数と物理演算の連携はとりやすくなるため、ゲームの内容によってはFixed Updateから切り替えると良いでしょう。
・Script
Unity側が自動で物理演算を更新するのではなく、スクリプトから手動で物理演算を更新するようにします。
以下の画像は2Dゲームでの物理演算更新を行うスクリプトです。任意のタイミングで呼び出すことで、物理演算の更新を行うことができます。

物理演算を使ったゲームを制作する場合は、物理演算の更新タイミングや更新の仕様について把握しておかないと厄介なエラーを招く要因になることがあるため注意しましょう。