【Unity】RPGを作るチュートリアルその35 デバッグ用ログのラッパークラス

【Unity】RPGを作るチュートリアルその35 デバッグ用ログのラッパークラス

シンプルなRPGをUnityで作るチュートリアルシリーズの35回目です。

第34回では以前作成したキャラクター全体の状態を管理するクラスに機能を追加しました。

今回は戦闘機能の作成に入る前に、デバッグ用の機能としてログのラッパークラスを作成したいと思います。UnityのDebugクラスを使う方法も良いかと思いますが、ログのメッセージにプレフィックスをつけることで、Unityデフォルトのログなのか、自分が仕込んだログなのかを区別しやすくしたいと思います。また、一括でログの出力を止める機能もつけたいと思います。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

シンプルなRPGを作る上でどんな作業が必要か、どんな順番で作っていくと良さそうか、別ページで検討しました。基本的にこの流れに沿って進めていきます。

 

チュートリアルの一覧

このシリーズ全体の一覧は以下のページにまとめています。

 

前回の内容

前回は以前作成したキャラクター全体の状態を管理するクラスに機能を追加しました。

 

デバッグ用ログのラッパークラス

開発を進めていくにあたって、システムの内部で起こっていることを把握することが大切です。特にRPGの戦闘システムは複雑になりがちなので、どこで何が起こっているのか、コンソールから確認できるようにすると修正や改善がしやすくなります。

この目的を達成するならUnityのDebug.Logなどを使うというのもひとつの方法です。ただ、任意のタイミングでログの出力を切り替えたり、自分が仕込んだログであることが分かるようにメッセージにプレフィックスをつけて出力したりする機能を追加するなど、ログの出力を自分用に使いやすくすることもできます。

そこで、ラッパークラスを作成し、その中で必要な機能を追加していきたいと思います。ラッパークラスとは、元々存在する機能をそのまま使うのではなく、使いやすい形にするなどして包み込むようなクラスのことを指します。今回のケースですと、ログを出力するだけならDebug.Logを使えばOKですが、より使いやすい機能を加えた上でDebug.Logを呼び出すようなクラスを作ります。

入れたい機能としては、

  • ログ出力を切り替えられる機能
  • ログの本文にプレフィックスを追加する機能

があります。

ログ出力の切り替えをInspectorウィンドウから行いたいので、MonoBehaviourを継承するクラスとして実装します。ただし、毎回GetComponentして使うのはちょっと大変なので、シングルトンのクラスにしてpublicでstaticなフィールドを使ってインスタンスにすぐアクセスできるようにしたいと思います。シングルトン・パターンはそのクラスのインスタンスが1つしかないことを保証するデザインパターンのことです。今回のケースではログ出力のラッパークラスのインスタンスが、シーン内のひとつしかないことを保証するようにします。

1点注意があるとすれば、Unityのコンソールでログをダブルクリックすると該当の行に飛びますが、このラッパークラスがあることでこちらに飛んでしまいます。そのため、コンソールから飛ぶ際にはメッセージの中身にあるリンクから問題の行に飛ぶ必要があります。

 

デバッグ用ログのラッパークラスの実装

上記を踏まえてデバッグ用ログのラッパークラスを実装していきます。Projectウィンドウから「Scripts」のフォルダに移動し、新しいフォルダを作成します。名前は [Debug] にしました。ここにはデバッグ系のスクリプトファイルを入れていきます。

フォルダの作成
フォルダの作成

 

作成した「Debug」フォルダに移動し、MonoBehaviourのスクリプトファイルを作成します。名前は [SimpleLogger] にしました。名前は自分用のログ用クラスだと分かる形にしておくのが良いかと思います。今回は「SimpleRPG」を作っているのでそのロガーとしてこの名前にしてみました。

名前もシンプルに
名前もシンプルに

 

作成した「SimpleLogger」の中身は以下のように記載しました。

「_outputDebugLog」のフィールドはログを出力するかどうかのフラグで、trueの場合に出力します。出力用メソッド3種の中身でそれぞれフラグを確認するようにしました。

「LogPrefix」のフィールドはログを出力する際のメッセージの先頭につける文字列で、自分が仕込んだログであることを分かるようにしておくと良いかと思います。今回はシンプルに[Debug]にしました。プロジェクト名を入れておくとよりわかりやすくなるかもしれません。また、色をつけたり、太字にするタグを入れておくのも見分けやすくて良いかと思います。

「Instance」のプロパティでは、「_instance」のフィールドがnullだったらシーン内のコンポーネントを探すようにします。それでも見つからない場合はAddComponentして追加するようにしています。今回の運用ではシーン内に配置する予定なので、うっかり消さない限りはAwake()内の代入処理で参照される想定です。

Awake()では、「_instance」のフィールドがnullだったら自身への参照を代入し、nullではなかったら自分自身のゲームオブジェクトをDestroyします。nullではないということは、他のインスタンスが存在するということなので、シングルトン・パターンに沿ってひとつのインスタンスが存在する状態にします。作り出して目覚めたら既に自分と同じクラスのインスタンスがいて、後から起きた方は自分で自分をDestroyする……なんという世紀末な倫理観でしょうか。

他の3つのメソッドは、Debugクラスでよく使う3種のメッセージレベルに合わせて名前をつけています。メソッド内でメッセージを生成するときにはプレフィックスをつけてからDebugクラスのメソッドに渡すようにしています。

 

ゲームオブジェクトの作成

作成したスクリプトファイルを保存したら、シーン内にゲームオブジェクトを作成してスクリプトをアタッチします。Hierarchyウィンドウから空のゲームオブジェクトを作成します。名前は [SimpleLogger] にしました。デバッグ系のクラスでまとめることも考えましたが、「DontDestroyOnLoad」を使っていることからシーンのルートレベルに配置します。

ラッパークラス用のゲームオブジェクト
ラッパークラス用のゲームオブジェクト

 

作成した「SimpleLogger」のゲームオブジェクトを選択し、Inspectorウィンドウから [SimpleLogger] をアタッチします。

スクリプトのアタッチ
スクリプトのアタッチ

 

動作確認

既存のクラス、あるいはテスト用に作ったクラスのStart()などにログ出力の処理を記載して、ゲームを実行してみます。私は「PlayerMover」にStart()を用意して処理を書きました。これは後ほど消すので、githubのリポジトリでは含まれていないはず……!

呼び出す場合は、<クラス名>.<インスタンスのフィールド名>.<メソッド>のように記載します。クラス自体がstaticな時とは異なり、staticなフィールドを挟んでいます。

テスト用にログを出力
テスト用にログを出力

 

ゲームを実行するとStart()のタイミングで以下のように出力されます。Debugクラスのログレベルと合っているかを確認しましょう。フッター部分に表示される1行についても、色がついて表示されます。中身でDebugクラスのメソッドを呼んでいるので同じになるのは当然っちゃ当然ではありますね。

ログの出力を確認
ログの出力を確認

 

ログの出力を確認できたら今回の作業は完了です。

 

今回のブランチ

 

まとめ

今回は戦闘機能の作成に入る前に、デバッグ用の機能としてログのラッパークラスを作成しました。通常通りUnityのDebugクラスを使うのもいいですし、必要に応じて機能を追加できるようにラッパークラスを追加するのも良いかと思いますので、両方試してみるのが良いかと思います。私はラッパークラスを作って色々足してログの把握をしやすくする派です。

次回はゲーム内のキー入力を検知するためのラッパークラスを追加します。PC向けのゲームの場合、決定キーやキャンセルキーの役割を担うキーが複数あったりするので、その部分をまとめて検知する仕組みを用意したいと思います。

 

     

ゲーム開発の攻略チャートを作りました!

CTA-IMAGE

「ゲームを作ってみたいけど、何から手を付けていいか分からない!」


そんなお悩みをお持ちの方向けに、todoがアプリをリリースした経験を中心に、ゲーム作りの手順や考慮すべき点をまとめたe-bookを作成しました。ゲーム作りはそれ自体がゲームのように楽しいプロセスなので、「攻略チャート」と名付けています。


ゲームを作り始めた時にぶつかる壁である「何をしたら良いのか分からない」という悩みを吹き飛ばしましょう!