最終更新:
orika_ex_miyako 2021年12月30日(木) 23:56:05履歴
この機能は Unity の持つ LineRenderer コンポーネントの機能を利用しています。
移動経路の表示中には敵が移動を開始しないように制御処理を加えることも必要になります。
敵の生成→経路用のラインの生成→ラインの削除→敵の移動開始、という流れになりますので、
このロジックを考えて、どのようにすれば実装ができるのか、設計を詳細に練ることが大切です。
<実装動画>
動画ファイルへのリンク
以下の内容で順番に実装を進めていきます。
手順14 ー敵キャラの経路表示の自動生成処理の実装ー
24.経路用の PathLine ゲームオブジェクトを作成する 25.経路に合わせて自動的に PathLine ゲームオブジェクトを作成する処理を実装する
新しい学習内容は、以下の通りです。
・マテリアルの作成 ・LineRenderer コンポーネント ・Tween.Pause メソッド ・Tween.Play メソッド ・Listの使い方� �Add メソッドー ・yield return StartCoroutine メソッドによる待機処理
経路用の表示、といっても、それはゲーム画面でみた場合の動きです。
それを実際にゲームの処理、ロジックとしてどのように考えて実装していけばよいのかを検討します。
このロジックを考える作業が非常に大変なのですが、これがプログラムを行うエンジニアに求められるスキルになります。
プログラマーとは、自分の考えられる引き出しの中から最適解を導きだしてそれをロジックとして設計し、ゲーム内に実装することが職務になります。
非常にクリエイティブかつ、論理的な考えを求められますので、教材を通じてロジカルな思考、発想、考え方を身につけていきましょう。
今回の場合は、経路の矢印を1つのゲームオブジェクトとして作成する設計を検討します。
それを複数生成することによって、スタート地点からゴール地点までの経路をなぞるような演出にします。
経路表示用の素材を用意します。矢印の画像を無料サイトなどから探して、Unity へインポートしてください。
TextureType は Sprite に変更しておきます。背景を透過して利用したいので、画像ファイルの拡張子は png ファイルのものにしてください。
インスペクター画像

続いて、新しくマテリアルを1つ作成します。
Project 内、あるいは任意のフォルダ内で右クリックをしてメニューを開き、Create => Material を選択してください。
名前は PathArrow に変更します。
Shader の設定を LegacyShagers / Particles / Additive に変更します。
画像ファイルを設定できる項目が表示されますので、先ほどインポートした矢印の画像ファイルをドラッグアンドドロップしてアサインしてください。
これで画像を利用したマテリアルが出来上がります。
インスペクター画像

以上でマテリアルは完成です。
PathLine ゲームオブジェクトの LineRenderer コンポーネントの設定を行います。
このコンポーネントは直線の画像を描画する機能を持っていますので、それを利用して矢印の画像を描画するようにします。
Materials の Element 1 に Default-Line がアサインされていますので、この部分に先ほど作成した PathArrow マテリアルをドラッグアンドドロップしてアサインしてください。
続いて、Additional Settings の Sorting Layer を Chara に設定します。これで背景の TileMap よりも優先順位が高くなり画面に表示されます。
インスペクター画像

以上で設定は完了です。
Line Renderer (ラインレンダラー) コンポーネントは、空間の2つ以上の点の配列をとることで、それぞれの間に直線を描きます。
公式サイトには 3D とありますが、2Dでも応して活用していくことが可能です。
参考サイト
Unity 公式マニュアル
LineRenderer
https://docs.unity3d.com/ja/current/Manual/class-L...
Unity 公式スクリプトリファレンス
LineRenderer
https://docs.unity3d.com/jp/current/ScriptReferenc...
今回実装している変数やメソッドについてまとめておきます。
必ず自分でも調べて、自分の知識として吸収しておいてください。
LineRenderer で描画するラインの幅のスタートのサイズを設定することができる変数です。
参考サイト
Unity 公式スクリプトリファレンス
LineRenderer.startWidth
https://docs.unity3d.com/jp/current/ScriptReferenc...
LineRenderer で描画するラインの幅の最後のサイズを設定することができる変数です。
参考サイト
Unity 公式スクリプトリファレンス
LineRenderer.endWidth
https://docs.unity3d.com/jp/current/ScriptReferenc...
これらの他にも、色を変更する変数や、曲線を描くための変数なども用意されています。
LineRenderer で描画するラインの頂点数を設定したり、参照したりすることができる変数です。
// 生成するラインの頂点数を設定(今回は始点と終点を1つずつ) lineRenderer.positionCount = drawPaths.Length;
今回は代入処理を行い、頂点数の設定を行っています。drawPaths.Length の値は 2 ですので、ラインを生成するための頂点数を 2 に設定します。
つまり、始点と終点になります。この2つの頂点を結ぶことでラインを生成します。ここではそのための準備をしています。
参考サイト
Unity 公式スクリプトリファレンス
LineRenderer.positionCount
https://docs.unity3d.com/jp/current/ScriptReferenc...
ラインの頂点の位置をすべて設定するメソッドです。この処理によって描画処理が実行されます。
SetPosition メソッドという処理も用意されていますが、リファレンスにもあるように、複数のラインを描画する場合にはこちらの処理の利用するようにしてください。
lineRenderer.SetPositions(drawPaths);
参考サイト
Unity 公式スクリプトリファレンス
LineRenderer.SetPositions
https://docs.unity3d.com/jp/current/ScriptReferenc...
そのほかの活用事例を紹介しているサイトもたくさんありますので、自分でも検索してみてください。
参考サイト
はなちるのマイノート 様
【Unity】LineRendererをスクリプトから自由自在に操る
https://www.hanachiru-blog.com/entry/2020/10/05/12...
ヒエラルキーにある PathLine ゲームオブジェクトに、作成した DrawPathLine スクリプトをドラッグアンドドロップしてアタッチします。
アタッチした際には必ず対象のゲームオブジェクトのインスペクターを確認して、アタッチできているかを確認します。
DrawPathLine スクリプトには設定項目は2か所ありますが、スクリプト内で初期値を設定しているため、特に設定しなくても問題ありません。
この値は、実際に矢印の描画が行われた際に調整する部分です。自分の用意した画像との兼ね合いで適宜変更してください。
インスペクター画像

以上で設定は完了し、PathLine ゲームオブジェクトは完成です。
完成した PathLine ゲームオブジェクトをプレファブにします。
Prefabs フォルダへドラッグアンドドロップしてプレファブにしてください。
プレファブになったら、ヒエラルキーにある PathLine ゲームオブジェクトは削除してください。
1つのラインを作成して、曲がり角を用意して生成する方法と、複数の直線のラインを作成して、それをつなげていく方法があります。
1つのラインで作成をすると、画像が伸びてしまうため、今回は複数の直線のラインを作成する方法で実装を検討します。
ヒエラルキー画像

SceneビューとGameビュー画像

プレファブにした PathLine ゲームオブジェクトをコーナーのたびに生成し、複数のラインを作っていることがわかります。
今回はこのラインの生成処理と、PathTranSet ゲームオブジェクトの移動経路の情報とを連動させて、A の位置から B の位置までを1つのラインとして、それを経路の順番ごとに生成処理する機能を実装します。
この処理は PathTranSet ゲームオブジェクトにアタッチされている PathData スクリプトの移動経路の情報である PathTranArray 変数が配列で管理されているため、それを上手く組み合せてロジックを組みます。
具体的には、StartTran ゲームオブジェクトの地点から PathTran ゲームオブジェクトの地点までに1つのラインを作成します。
これは PathTranArray 配列の Element 0 => Element 1 に対してラインを作っています。
それが完成したら、次は、Element 1 => Element 2 に対してラインを作成します。
これを最後のゴール地点になるまで繰り返すことによって、上記の画像のように複数のラインを作成して経路表示を実装しています。
<PathTranArray 変数の情報を活用する>

この処理の実装には、敵キャラの移動処理にも大きくかかわっています。
どういうことかというと、ラインの表示が行われている間は、敵キャラの移動を一時的に停止しておくようにしないと、
ラインの表示中に敵キャラが移動をしてしまうことになるためです。
タワーディフェンスゲームでは事前に敵の移動経路の情報をプレイヤーに提供し、それを元にプレイヤーは考える時間を作ります。
その後に敵キャラが実際に移動を開始するという流れになっていますので、これを実現するためには、ラインの生成処理だけではなく、
敵キャラの移動の制御処理も一緒に実装を行う必要があります。
実際のラインの生成処理については、敵を生成する機能を持つスクリプトで制御する方法と、各敵キャラごとラインを生成する方法が考えられます。
今回は敵を生成する EnemyGenerator スクリプト側でラインを生成するように設計します。
これは、ライン用のゲームオブジェクトをプレファブとして登録することを考えてのことです。
EnemyGenerator スクリプトであれば1つ登録すれば済みますが、敵キャラに設定するとなると、すべての敵キャラごとにライン用のゲームオブジェクトのプレファブを登録する必要が生まれます。
10体いれば、10回アサインが必要です。もしもアサイン漏れがあればゲームが停止してしまう恐れもあります。
そういった観点から考えて、今回は1回のアサインで済むように EnemyGenerator スクリプト内で、敵の生成に合わせて、その敵の移動経路の情報を利用して
ラインを生成するという制御で設計を考えていきます。
DOTween の Tween 処理を変数に代入しておくことにより、Kill メソッドの他にも制御を行うことが出来ます。
Pause メソッドは Tween の処理を一時停止する命令です。この処理を行うことにより、Tween 型の変数内に代入されている実行中の DOTween の処理を一時停止出来ます。
private Tween tween;
// 各地点に向けて移動
tween = transform.DOPath(paths, 1000 / moveSpeed).SetEase(Ease.Linear).OnWaypointChange(ChangeAnimeDirection);
// 処理を一時停止
PauseMove();
/// <summary>
/// 移動を一時停止
/// </summary>
public void PauseMove() {
tween.Pause();
}
一時停止している DOTween の処理は2つの方法で再開可能です。つまり、上手く使い分ける必要があります。
1つは今回利用している Play メソッドです。この命令では、一時停止して中断している DOTween の処理の続きから処理を再開できます。
もう1つは Restart メソッドです。この命令では続きからではなく、最初から処理の再生をやり直します。
ロジックとしては、移動経路のラインを表示している間は Pause メソッドで移動の処理を一時停止しておいて、
ラインの表示が終了したタイミングでこの Play メソッドで移動を再開しています。
<EnemyGenerator.cs>
/// <summary>
/// ライン生成の準備
/// </summary>
private IEnumerator PreparateCreatePathLine(Vector3[] paths, EnemyController enemyController) {
// ラインの生成と削除。この処理が終了するまでは、この処理より下の処理は実行されない
yield return StartCoroutine(CreatePathLine(paths));
// 敵の移動を再開
enemyController.ResumeMove();
}
<EnemyController.cs>
/// <summary>
/// 移動再開
/// </summary>
public void ResumeMove() {
tween.Play();
}
ラインの生成処理については敵を生成する際に一緒に生成するよう設計しました。
それをロジックを考えてスクリプトを修正していきましょう。
移動経路についてはラインの生成の際にも利用しますので、以前は EnemyController スクリプト内で経路情報を作成していましたが、
その処理を EnemyGenerator スクリプト側に移動し、作成した経路情報を EnemyController スクリプト側へ引数を通じて渡すようにロジックを考えてみてください。
新しくメソッドを2つ作成しています。CreatePathLine メソッドの処理を自分でコメントを書いてみてください。
EnemyGenerator.cs
スクリプトを修正したらセーブします。
List クラスは <T> にジェネリック型(任意の型)を指定して、同じデータ型をまとめて管理するコレクション機能を持つクラスです。
配列と異なり、要素を自由に追加・削除できます。(要素数が可変する)
List を利用するには宣言に合わせて初期化の処理が必要になります。
// List の宣言と初期化 List<DrawPathLine> drawPathLinesList = new List<DrawPathLine>();
Listの末尾に引数で指定した要素(データ)を追加します。
引数が T 型となっていますが、これは List を宣言した際に使った型が自動的に入ります。
今回は DrawPathLine 型の List を宣言していますので、Add メソッドの引数には DrawPathLine 型のみ指定できます。
そのため、Listで宣言している型と同じ型であれば Add メソッドで List に要素を追加することが出来ます。
DrawPathLine drawPathLine = Instantiate(pathLinePrefab, transform.position, Quaternion.identity); drawPathLinesList.Add(drawPathLine);
追加された要素は、自動的に List の最後に順番に追加されていきます。
例えば、drawPathLinesList がまだ1つも要素がなければ、drawPathLinesList[0] として1つ目に要素が追加されます。
そのあとに Add メソッドが実行された場合には、drawPathLinesList[1] として2つ目に要素が追加されます。
コルーチン(Coroutine)とは一定の時間や条件をもとに、処理を中断・再開・終了させることができる処理のことで、非同期処理と呼ばれます。
コルーチンについての詳細な説明は割愛します。こちらの記事や、サイトで広く情報を取得できますので、そちらを参考にしてください。
XR-HU3様
【Unity】コルーチンで処理を中断・再開・停止させる方法を学ぶ
https://xr-hub.com/archives/20368
コルーチンメソッド内には、yield を利用した処理を記述することができます。
例えば、数秒間の遅延処理や、条件達成までメインスレッドの処理を一時中断して待機させる処理などを、この yield を利用すると実装できます。
/// <returns></returns>
private IEnumerator PreparateCreatePathLine(Vector3[] paths) {
// ラインの生成と削除。この処理が終了するまでは、この処理より下の処理は実行されない
yield return StartCoroutine(CreatePathLine(paths));
// 敵の移動を再開
enemyController.ResumeMove();
}
通常のコルーチンメソッドの呼び出しと違いまして、呼び出す前に yield return があります。
この場合、呼び出されたコルーチンメソッドの処理がすべて終了するまで、ここでプログラムを一時中断して待機させる、という処理が実行されます。
呼び出すコルーチンメソッドの処理は、
「EnemyGenerator スクリプトにある CreatePathLine メソッドを実行する。そのメソッドの処理がすべて終了するまで、プログラムを一時中断させる」
という内容です。
その結果、ラインの生成と削除が終了してから、はじめて次の処理(敵の移動を再開)が行われるという処理が実装されています。
これは特に、CreatePathLine メソッドのようにコルーチンメソッドでの非同期処理を行う場合に効果的です。
通常のプログラムは同期処理ですのでその処理がすべて実行されてから次の処理に移行します。
ですが、今回の CreatePathLine メソッドはコルーチンメソッドですので、その処理の実行有無を判定して次に進む処理が行えません。
そのため非同期処理が終了するのを待機するようにしないとラインの生成と削除の処理が終わってから次の処理に移行する、という手順でプログラムが進みません。
プログラムは上から下へと流れて処理されていきますが、このような非同期処理の場合には、中断処理を挟むことによってゲームの流れを制御しています。
敵の生成速度が速いとライン表示が重なってしまうため、GameManager ゲームオブジェクトの GenerateIntervalTime 変数を調整して適宜な間隔で生成されるようにする部分がポイントです。
300 〜 500 前後で試してみるといいでしょう。
デバッグを行う際には、自分で調整を行って、なるべく簡単に繰り返しデバッグが出来るようにしておくことが大切です。
これは今回の処理に限らず、すべてのデバッグに共通することですので、色々とやりやすい方法を考えておく必要があります。
移動経路のラインがスタート地点から1つずつ順番に表示されて、しばらくしてからまた、スタート地点から1つずつ順番に削除されていれば制御成功です。
Sceneビューを見ながら、生成された敵がすぐに移動を開始せずに、移動経路のライン表示が終了してから移動を開始していることを確認してください。
<実装動画>
動画ファイルへのリンク
以上でこの手順は終了です。
次は 手順15 −異なる生成地点での敵キャラの自動生成処理の実装− です。








コメントをかく