【Unity/C#】必要に応じてアタッチしないクラスも作ると吉
Unityでゲームを作る時にはスクリプトファイルを作ってMonoBehaviourを継承したクラスを作ることが多いかと思います。
……おっと、なんだか物騒な名前のスクリプトの画像になってしまいました。
スクリプトをゲームオブジェクトにアタッチして使用する機会は多く、このやり方はぜひマスターしておきたいところですが、ゲームオブジェクトにアタッチしないクラスも作っておくと便利なことがあります。
必要に応じてアタッチしないクラスも作ると吉
Unity的にはMonoBehaviourを継承したスクリプトを使うことが多いのですが、C#的な使い方も織り交ぜていくと柔軟にコーディングができます。
C#的な使い方というと、
- 都度オブジェクトをインスタンス化して使う
- staticなクラスにしてゲーム全体から値を使う
といった方法があります。(ここで挙げたものは一部です)
MonoBehaviourを継承したスクリプトを使う際は、ゲームオブジェクトへの参照を取得して、GetComponentでスクリプトへの参照を取得してから使う、みたいな感じになるかと思います。
シーン内のオブジェクトに関係のあるスクリプトならこのようにするべきですが、シーン内のオブジェクトの値を使わない処理等はC#的なオブジェクトをnewしてインスタンス化して使った方が簡単だったりします。
また、定数を保持するクラスなどをstaticなクラスとして作っておくと便利です。ゲーム内で一貫して使いたい文字列や値をstaticなクラスに記載しておくことで、ゲームオブジェクトに依存しない形でどこからでも参照できます。
都度オブジェクトをインスタンス化して使う
なんらかのデータを計算時に保持するようなクラスも便利です。MonoBehaviourを継承しない、通常のC#のクラスを作るイメージです。例えばこんな感じ。
別のスクリプトからnewしてインスタンスを作成することで、publicなメソッドを使うことができます。
Unityでコーディングするからといって全てのスクリプトをゲームオブジェクトにアタッチしないといけない! ……なんてことはないので、こんな感じでゲームオブジェクトの情報を使わないクラスも使ってみると良いでしょう。
いきなり自分でクラスを作ってサンプルを紹介してみましたが、newしてインスタンス化するのは実はよくやっていることかもしれません。
Listを使うときにインスタンスを作ったり、Dictionaryを使うときにインスタンスを作ったりするときにはnewしています。Listクラスはゲームオブジェクトにアタッチして使わないので、この形式には実は慣れ親しんでいたかもしれません。
自分でクラスを作るときにはスクリプトファイルを作成したときにデフォルトでMonoBehaviourを継承しているので、プログラミングに慣れていないと「これ消してもいいのかな?」と不安になるかもしれませんが、どのクラスも継承しないクラスを作るのはよくあることなので大丈夫です。
以前リリースしたアプリではアイテムのデータや実績のデータをセーブファイルに保存するクラスを作ったことがあります。staticでも実装できますが、使用時にインスタンスを作ることで多少メモリ使用量も減らせるかも、という目論見がありました。
どこからも参照されなくなったインスタンスはガベージコレクション(GC: ごみ収集)の対象となり、メモリから掃除されます。ずっとメモリを使い続けてメモリを圧迫してしまった! なんてことを防いでくれるので、その場で機能を使えばOKなクラスだったらnewしてインスタンスを作るとメリットが大きいかもしれません。
staticなクラスにしてゲーム全体から値を使う
publicでstaticなクラスにすることで、コードを書いている人がインスタンス化しなくてもシステム側でインスタンスを作ってくれて、そのまま使えるクラスになります。システム側でインスタンスを作るので、newしようとすると怒られます。
staticなクラスではフィールドもstaticにします。これらのフィールドはインスタンス化せずにアクセスできます。
例えば以下のような感じでstaticなクラスを作成します。
staticにしているフィールド(name)を作ってみました。
単にstaticにしているフィールドの場合は、他のクラスから値をセットすることができます。ダイレクトに値を変えられてしまうと、どこで値が変わったのか追跡しにくくなるので、多くの場合フィールド自体はprivateにして、プロパティのgetter/setterを使ってアクセスします。
以下の例では別のクラスからstaticなクラスの値を参照しています。
Debug.Logを使ってstaticなクラスのフィールドの中身を表示する動きですが、上の例と異なりnewしないでそのまま使えます。
staticなクラスはゲーム全体で使う定義値などを記載しておく場所として使えます。例えば通常の文字色、警告文の文字色、といった形でColorクラスの設定値を記載しておくこともできます。const(コンパイル時定数)にするか、またはstatic readonly(実行時定数)にすると、値を変更できなくなるのでどこかで値が変わってしまう心配がなくなります。
こうした設定値は使う場所で文字列や値を直接書いてしまうと、修正が入った時に全部を検索して対応しないといけなくなり、とても大変になるんですよねぇ……(遠い目)
また、ゲーム内の進行状況などもstaticなクラスで管理する選択肢もあります。
staticなクラスはゲームの実行中ずっと生存しているため、別のシーンを読み込んだ時にもデータを保持することができます。
ゲームオブジェクトにアタッチしたオブジェクトの場合、シーンを切り替えると破棄されるのでそこにアタッチしたスクリプトも破棄されます。スコアを次のステージに持ち越したい場合にはstaticなクラスに保持しておくといいかもしれません。
staticなクラスで設定値を持つ際にconstを使うかreadonlyを使うかについて以下の記事でも触れているのでよかったらこちらもご覧くださいな。
まとめ
UnityではC#を使った実装方法として、通常のC#のコーディングに加えてUnity独自のゲームオブジェクトにアタッチする形式があるので、可能なら両方を使えるようにするとより柔軟にシステムを作っていくことができます。
役割分担に応じてクラスを分けることで依存度を下げることができます。依存度が下がるということは再利用しやすくなるということで、次のゲームを作る時にもクラスを使いまわしたりもできます。
そうすると開発時間を短縮できるかもしれません。開発時間が短縮されればたくさんゲームを作ることができて……と夢のような世界が待っています。
というわけでゲームオブジェクトにアタッチしないクラスを使ってみることも検討してみてください。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【Unity】TerrainのHeightMap(ハイトマップ)を生成するエディタ拡張のサンプル 2021.01.08
-
次の記事
【Unity/C#】const(コンパイル時定数)とreadonly(実行時定数)の違いを知る 2021.01.10
コメントを書く