前回の記事では敵をマップに配置し移動できるようにしました。
さらに、プレイヤーと敵ターンの概念を導入し、お互いが交互に動けるようにC#スクリプトを作成しました。
前回の記事:
今回の記事では、敵がプレイヤーを見つけたら追いかけてくるように経路探索アルゴリズムを実装してみましょう!
経路探索アルゴリズムには色々な方法が存在していますが、ここでは単純に敵キャラクターに視野を持たせてその範囲にプレイヤーがいたらそちらへ移動するという比較的簡単な方法を採用しています。
経路探索のアルゴリズムを作成する
それでは敵が早速プレイヤーを追いかける処理を作っていきましょう!
経路探索の処理は「Enemy」コンポーネントに実装していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
//Move()を次のように変更 public virtual void MoveStart() { var player = Object.FindObjectOfType<Player>(); if(!MoveToFollow(player)) { MoveFree(); } } //次のものを追加 [System.Serializable] public class Scope { //South方向 [TextArea(3, 10)] public string Area = "" + "111\n" + "111\n" + "111"; public bool IsInArea(Vector2Int target, Vector2Int startPos, Direction dir) { var relativePos = target - startPos; switch(dir) { case Direction.North: relativePos.x *= -1; relativePos.y *= -1; break; case Direction.South: break; case Direction.East: var tmp = relativePos.x; relativePos.x = -relativePos.y; relativePos.y = tmp; break; case Direction.West: tmp = relativePos.x; relativePos.x = relativePos.y; relativePos.y = -tmp; break; } var lines = Area.Split('\n'); var width = lines.Select(_l => _l.Length).FirstOrDefault(); if(!lines.All(_l => _l.Length == width)) { throw new System.Exception("Areaの各行にサイズが異なるものが存在しています。"); } var left = -width / 2; var right = left + width; if(left <= relativePos.x && relativePos.x < right) { if(1 <= relativePos.y && relativePos.y <= lines.Length) { var offsetX = relativePos.x - left; if('1' == lines[relativePos.y-1][offsetX]) { return true; } } } return false; } } public bool IsChasing = false; public Scope VisibleArea; protected bool MoveToFollow(MapObjectBase target) { if (VisibleArea.IsInArea(target.Pos, Pos, Forward)) { Move(Forward); IsChasing = true; return true; } if(IsChasing) { var left = Map.TurnLeftDirection(Forward); if (VisibleArea.IsInArea(target.Pos, Pos, left)) { Move(Forward); Forward = left; IsChasing = true; return true; } var right = Map.TurnRightDirection(Forward); if (VisibleArea.IsInArea(target.Pos, Pos, right)) { Move(Forward); Forward = right; IsChasing = true; return true; } } IsChasing = false; return false; } |
コンパイルに成功したら、再生して実際にプレイヤーの方に向かってくるか確認してください。
上のコードでは視野を表す「VisibleArea」フィールドの中にプレイヤーがいたら追いかけ始めるようになっています。(追いかける状態だと「IsChasing」フィールドがtrueになります。)
「VisibleArea」フィールドの内容を変更すると敵の視野が変わるので、適当に変更してみるのもいいでしょう。
また、「IsChasing」フィールドがtrueになった時にプレイヤーが視野の範囲外に行ってしまった時は現在の前方向からの左右を確認し、その中にプレイヤーがいるか判定するようにしています。
この処理は追跡処理をより良くするためのものになりますが、なくても大丈夫です。
興味がある方は左右確認の処理をコメントアウトしてみて動作を確認するのもいいでしょう。
上の画像ではマップデータはこうなっています。
1 2 3 4 5 |
000P0 0+++0 0E000 0+++0 G0000 |
まとめ
今回の記事ではプレイヤーを追いかけてくる敵のスクリプト処理を追加しました。
今回の記事で実装したものは敵の前方向にプレイヤーが存在しているか確認し、存在していたらその方向へ移動するものになります。
ある程度それっぽくはなりますが、マップの状態によっては完全にプレイヤーを追いかけることができなくなるかもしれませんよね。改良の余地はまだまだあります。
記事では改良の一環としてプレイヤーが見えなくなったら左右を確認する工夫を取り込んでいますが、それでも追いかけきれないパターンが発生するかもしれません。
ぜひ余力があれば改造・改良にも挑戦してみてください。
プレイヤーを絶対に追いかけるようにするには経路探索アルゴリズムで調べると色々な方法が既に先人たちによって考案されているので、そういったアルゴリズムを実装するのもいいでしょう。
また、この記事で追加した「Enemy.Scope」クラスは視野以外にも攻撃範囲などにも利用できるので、テクニックとして身に着けておくといいかもしれないです。
それでは次の記事に行ってみましょう。
コメント