今回は途中で何度か Start メソッドを別のメソッドに作り変えて、外部のスクリプトから呼び出して実行する処理に変更しました。
現在のスクリプトを確認してもらうと分かりますが、
Start メソッドが記述されているのは GameManager スクリプトただ1つです。
見直してみてください。
これはどういうことかというと、ゲームを実行した際に最初に実行される Start メソッドが1つだけ存在していることになりますので、
常に、
この GameManager スクリプトの Start メソッドからゲームの処理が開始される、ということになります。つまり、そういった設計を
意図して作っています。
複数のスクリプトに Start メソッドが記述されている場合、Unity では、どのスクリプトの Start メソッドを実行する、という保証がありません。
例えば、A 〜 D までの4つのスクリプトにそれぞれ Start メソッドがあった場合、最初にゲームを実行した際には A のスクリプトの Start メソッドが実行されたものの、
次にゲームを実行した際には C のスクリプトの Start メソッドが実行された、というように、
Start メソッドを実行するタイミングは同じであっても
処理される順番が完全に Unity 側に依存した処理になります。そのため、
こちらが考えている順番通りに毎回 Start メソッドが実行されることはありません。
これを、すべてのスクリプトを見た時に、B のスクリプトにだけ Start メソッドがあったとしたら、いかがでしょうか。
1つしかないので、必ず、
この Start メソッドが一番に実行されることが確定されます。
そしてこれは設計を行う際に検討しておくことで、こういった処理になるように、こちらで考えながら作り上げていくことが出来ます。
Start メソッドが1つだけ、という状態を作りだすことが出来れば、常にゲームを実行した際にはこの Start メソッドから処理が開始されることになります。
そのため、
自分が考えた順番で Start メソッド内に処理を記述することで、必ずその順番で処理が実行されることも確定されます。
現在の GameManager スクリプトの Start メソッドを確認してみてください。
<GameManager スクリプトの Startメソッド>
void Start() {
// ゲームの進行状態を準備中に設定
SetGameState(GameState.Preparate);
// TODO ゲームデータを初期化
// TODO ステージの設定 + ステージごとの PathData を設定
// キャラ配置用ポップアップの生成と設定
StartCoroutine(charaGenerator.SetUpCharaGenerator(this)); // このメソッドの中で、キャラ配置用のポップアップが生成される
// TODO 拠点の設定
// TODO オープニング演出再生
isEnemyGenerate = true;
// ゲームの進行状態をプレイ中に変更
SetGameState(GameState.Play);
// 敵の生成準備開始
StartCoroutine(enemyGenerator.PreparateEnemyGenerate(this));
// カレンシーの自動獲得処理の開始
StartCoroutine(TimeToCurrency());
}
いかがでしょうか。ゲームの実行に必要な処理を順序立てて、1つずつ順番に処理が実行されていることが分かります。
そのため、この順番に処理が実行されていくことが確定していますので、複数の Start メソッドがあったときのように、
どの処理が先に実行されるか、そういった心配は全くありません。
自分のイメージ通りの処理が実際に処理されていることになります。
こういった設計にして処理を記述できる利点は、こちらが考えた処理通りに実行されていくという以外にもいくつかあります。
1つは
エラーを発見しやすくなる、ということです。
例えば、StartCoroutine(enemyGenerator.PreparateEnemyGenerate(this)); というメソッドが実行された際にエラーが出たとします。
その場合、この処理以前の処理はすべて問題なく動いていることが判明します。
何故ならば、途中で処理が止まることがなかったのでこのメソッドまで実行された、ということが確定しているからです。
つまり、このメソッド以前の処理に問題がない、ということがわかれば問題の切り分けが出来ていますので、エラーの原因となる場所の特定が容易になります。
もう1つは、
処理の順番を組み立てやすくなる、ということです。
ゲームを実行すると Start メソッドの順番通りに処理が動いていく、ということは
処理が終了した時点の情報を確認しながら、どの処理の後にこの処理を入れたい、というイメージがわきやすく、
実際に記述する際にも、記述する対象となる場所の把握が容易になります。
今回のケースであれば、Start メソッドの最初と最後に SetGameState メソッドを実行して、ゲームの進行状態を制御しています。
この進行状態を利用して、各クラスが制御されるように設計を行っているため、SetGameState メソッドでゲームの状態を Preparate の状態にし、
必要な情報が設定されてから再度 SetGameState メソッドを実行してゲームの状態を Play に変更しています。
このようにすることで、プログラムの設計者が意図している順番通りに処理が動く、ということが分かります。
とはいえ、最初からこのように組み立てられた設計が行えるわけではありません。
ですが、かといって、
考えずにいてはいつまでたってもこういった設計方法を構築することが出来ません。
少しずつ、処理の内容を理解しながら、処理全体の流れを確認して、どうしたら上手く処理を設計できるのか、
そういう意識を常に持ってロジックを考えていくようにしてください。
学習時間は非常にかかりますが、
ロジックの構築や設計を行うことがエンジニアの仕事になりますので、
毎日の学習を、こういった点に意識を向けて繰り返し行うことによって、着実に自分のスキルとして培っていきましょう。
また Start メソッド自体が悪いものであることはありません。
そのため、必ずしも Start メソッドを持つクラスが2つ以上あるとしても、それがゲームの設計上問題をもたらすものでなければ問題になりません。
処理の順番を考えた際、その処理通りに動かないと意図した制御にならない、あるいは不具合が出てしまうようなケースにおいて、このような設計を考えるといいでしょう。