質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1511閲覧

Unity C# 移動中の対象に対する経路探索

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/06/22 11:54

編集2021/06/26 07:27

前提

移動中の対象へ経路探索をしたい

コード

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using System.Linq; 5 6namespace UtilityModule 7{ 8 public class Moving_from_PositionA_to_PositionB : MonoBehaviour 9 { 10 private int map_Width = 100; 11 private int map_Height = 100; 12 private ChessboardPathFinder pathFinder; 13 public List<Vector2> moveList = new List<Vector2>(); 14 private float speed = 2.5f; 15 public bool stoped_Movement; 16 //始動したコルーチンを覚えておくためのフィールドを追加し... 17 private Coroutine movementAction; 18 19 void Awake() 20 { 21 pathFinder = new ChessboardPathFinder(map_Width, map_Height); 22 } 23 24 public bool Find_Path(Vector2Int startPosition,Vector2Int goalPosition) 25 { 26 bool pathFound = pathFinder.FindPath(startPosition, goalPosition); 27 28 return pathFound; 29 } 30 31 public void Start_MovementAction() 32 { 33 //コルーチン始動時にそれを保存 34 movementAction = StartCoroutine(Move()); 35 } 36 37 //そして覚えておいたコルーチンを停止するためのメソッドを用意 38 public void Stop_MovementAction() 39 { 40 if (movementAction != null) 41 { 42 StopCoroutine(movementAction); 43 moveList.Clear(); 44 } 45 } 46 47 IEnumerator Move() 48 { 49 foreach (Vector2Int position in pathFinder.Path.Skip(1)) 50 { 51 Vector2 pos = new Vector3(position.x, position.y); 52 moveList.Add(pos); 53 } 54 55 Vector2 unitPos = new Vector2(gameObject.transform.position.x, gameObject.transform.position.y); 56 if(moveList.Contains(unitPos)) 57 { 58 moveList.Remove(unitPos); 59 } 60 61 int count = 0; 62 63 while (true) 64 { 65 if(stoped_Movement) 66 { 67 break; 68 } 69 70 gameObject.transform.position = Vector2.MoveTowards(gameObject.transform.position, moveList[count], speed * Time.deltaTime); 71 72 if (count < moveList.Count - 1) 73 { 74 count++; 75 } 76 77 if (gameObject.transform.position == (Vector3)moveList[moveList.Count - 1]) 78 { 79 break; 80 } 81 82 yield return null; 83 } 84 } 85 } 86}

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using Module_of_Unit; 5using UtilityModule; 6 7namespace Module_of_Berserkermode 8{ 9 public class Berserkermode : MonoBehaviour 10 { 11 private Unit_RandomWalk unit_RandomWalk; 12 private Unit gameObjectUnit; 13 private Moving_from_PositionA_to_PositionB moving_From_PositionA_To_PositionB; 14 private Unit_RandomWalk unit_RandomWalk_SelectedUnit; 15 private GameObject selectedUnit; 16 private bool get_Distance; 17 private bool switched_Berserkermode; 18 //前回のUpdateで調べたターゲットの位置を保存するためのフィールドを追加 19 private Vector2Int latestTargetPos; 20 21 private void Awake() 22 { 23 unit_RandomWalk = gameObject.GetComponent<Unit_RandomWalk>(); 24 gameObjectUnit = gameObject.GetComponent<Unit>(); 25 moving_From_PositionA_To_PositionB = gameObject.GetComponent<Moving_from_PositionA_to_PositionB>(); 26 } 27 28 public void Action() 29 { 30 //不満値が100%になったら、ランダム移動を停止する 31 unit_RandomWalk.Stop_RandomWalk(); 32 33 Invoke("Go", 1); 34 } 35 36 private void Go() 37 { 38 //ランダムに対象を選択する 39 int random = Random.Range(0, gameObjectUnit.playerOwnedUnits_List.Count); 40 selectedUnit = gameObjectUnit.playerOwnedUnits_List[random]; 41 unit_RandomWalk_SelectedUnit = selectedUnit.GetComponent<Unit_RandomWalk>(); 42 get_Distance = true; 43 switched_Berserkermode = true; 44 45 //対象がいた座標に向かって移動する 46 Go_To_TargetUnit(); 47 } 48 49 private void Update() 50 { 51 if(get_Distance) 52 { 53 //このユニットと対象のユニットの距離が、5タイル以内に入ったら、対象のユニットの移動を停止する 54 float distanse = Vector2.Distance(gameObject.transform.position, selectedUnit.transform.position); 55 if (distanse <= 3) 56 { 57 unit_RandomWalk_SelectedUnit.Stop_RandomWalk(); 58 int x = Mathf.RoundToInt(unit_RandomWalk_SelectedUnit.transform.position.x); 59 int y = Mathf.RoundToInt(unit_RandomWalk_SelectedUnit.transform.position.y); 60 unit_RandomWalk_SelectedUnit.transform.position = new Vector3(x, y, 0); 61 } 62 } 63 64 //対象のユニットが存在していた座標に到達したら、また移動する 65 /* 66 if (switched_Berserkermode && gameObject.transform.position == (Vector3)moving_From_PositionA_To_PositionB.moveList[moving_From_PositionA_To_PositionB.moveList.Count - 1]) 67 { 68 Go_To_TargetUnit(); 69 } 70 */ 71 72 if (switched_Berserkermode) 73 { 74 //現在のターゲットの位置を調べ... 75 Vector2Int targetPos = new Vector2Int((int)selectedUnit.transform.position.x, (int)selectedUnit.transform.position.y); 76 77 //敵の位置に変化があったら... 78 if (targetPos != latestTargetPos) 79 { 80 //現在動作中の移動コルーチンは中止し、目的地への経路を再計算 81 latestTargetPos = targetPos; 82 Stop_Movement(); 83 Go_To_TargetUnit(); 84 } 85 } 86 } 87 88 void Stop_Movement() 89 { 90 moving_From_PositionA_To_PositionB.Stop_MovementAction(); 91 } 92 93 void Go_To_TargetUnit() 94 { 95 //moving_From_PositionA_To_PositionB.moveList.Clear(); 96 97 Vector2Int startPos = new Vector2Int((int)gameObject.transform.position.x, (int)gameObject.transform.position.y); 98 Vector2Int goalPos = new Vector2Int((int)selectedUnit.transform.position.x, (int)selectedUnit.transform.position.y); 99 100 Vector2Int up = new Vector2Int(goalPos.x, goalPos.y + 1); 101 Vector2Int down = new Vector2Int(goalPos.x, goalPos.y - 1); 102 Vector2Int right = new Vector2Int(goalPos.x + 1, goalPos.y); 103 Vector2Int left = new Vector2Int(goalPos.x - 1, goalPos.y); 104 105 float up_Distance = Vector2.Distance(startPos, up); 106 float down_Distance = Vector2.Distance(startPos, down); 107 float right_Distance = Vector2.Distance(startPos, right); 108 float left_Distance = Vector2.Distance(startPos, left); 109 110 float min = Mathf.Min(up_Distance, down_Distance, right_Distance, left_Distance); 111 112 if(min == up_Distance) 113 { 114 goalPos = up; 115 } 116 117 if (min == down_Distance) 118 { 119 goalPos = down; 120 } 121 122 if (min == right_Distance) 123 { 124 goalPos = right; 125 } 126 127 if (min == left_Distance) 128 { 129 goalPos = left; 130 } 131 132 if (moving_From_PositionA_To_PositionB.Find_Path(startPos, goalPos)) 133 { 134 moving_From_PositionA_To_PositionB.Start_MovementAction(); 135 } 136 } 137 } 138}

試したこと

![イメージ説明

【回答を追記・編集しました】
ユニットはランダムに移動しているのですが、ユニットの「不満値」というパラメータが100になると、他のユニットの隣接に移動して、攻撃する、という実装にしようと思っていました。
ユニットが移動するスクリプトはUnit_RandomWalk.csというスクリプトです。すべてのユニットにこのスクリプトがアタッチされています。
目的のユニットが移動するたびに経路が再計算されるため、上記の図のように、ぐらぐらと揺れながら移動してしまっています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ご提示のスクリプト以外にもご質問者さんオリジナルのスクリプトがいくつかあるようですので、私の方での動作確認はちょっと難しく手探りになってしまいすみませんが、まずMoving_from_PositionA_to_PositionBStart_MovementAction周辺を下記のようにしておいて...

lang

1 //始動したコルーチンを覚えておくためのフィールドを追加し... 2 private Coroutine movementAction; 3 4 public void Start_MovementAction() 5 { 6 //コルーチン始動時にそれを保存 7 movementAction = StartCoroutine(Move()); 8 } 9 10 //そして覚えておいたコルーチンを停止するためのメソッドを用意 11 public void Stop_MovementAction() 12 { 13 if (movementAction != null) 14 { 15 StopCoroutine(movementAction); 16 } 17 }

そしてBerserkermode側のUpdate周辺は...

lang

1 //前回のUpdateで調べたターゲットの位置を保存するためのフィールドを追加 2 private Vector2Int latestTargetPos; 3 4 private void Update() 5 { 6 if(get_Distance) 7 { 8 float distanse = Vector2.Distance(gameObject.transform.position, selectedUnit.transform.position); 9 if (distanse <= 3) 10 { 11 unit_RandomWalk_SelectedUnit.stoped_RandomWalk = true; 12 int x = Mathf.RoundToInt(unit_RandomWalk_SelectedUnit.transform.position.x); 13 int y = Mathf.RoundToInt(unit_RandomWalk_SelectedUnit.transform.position.y); 14 unit_RandomWalk_SelectedUnit.transform.position = new Vector3(x, y, 0); 15 } 16 } 17 18 //対象のユニットが存在していた座標に到達したら、ではなく... 19 /* 20 if (switched_Berserkermode && gameObject.transform.position == (Vector3)moving_From_PositionA_To_PositionB.moveList[moving_From_PositionA_To_PositionB.moveList.Count - 1]) 21 { 22 Go_To_TargetUnit(); 23 } 24 */ 25 26 if (switched_Berserkermode) 27 { 28 //現在のターゲットの位置を調べ... 29 Vector2Int targetPos = new Vector2Int((int)selectedUnit.transform.position.x, (int)selectedUnit.transform.position.y); 30 31 //敵の位置に変化があったら... 32 if (targetPos != latestTargetPos) 33 { 34 //現在動作中の移動コルーチンは中止し、目的地への経路を再計算 35 latestTargetPos = targetPos; 36 moving_From_PositionA_To_PositionB.Stop_MovementAction(); 37 Go_To_TargetUnit(); 38 } 39 } 40 }

とするのはどうでしょうか?

すみませんが上記のコードは実験が不十分ですので、そのままではうまくいくかどうか不確かです。意図としては要するに、ターゲットが動くたびに経路を再計算する必要があるんじゃないか...ということでして、ご質問者さんのスタイルに合わせて自由に書き換えてしまってください。

何度も再計算するのは重そうに見えるかもしれませんが、経路がよっぽど長くなる...たとえば複雑な迷路状のマップで、ターゲットにたどり着くにはかなりの回り道をしなければいけない状況が頻発するとかでなければ、案外問題ないんじゃないかという気がします。
これだと計算量が多すぎるようでしたら、「Unity A*(A-Star)アルゴリズム 挙動がおかしくなる」のコメントで申し上げたような、非同期化して他の処理へのインパクトを抑制するみたいな対策が必要かもしれませんね。

私の場合の実装例

まず、ご質問者さんのUnit_RandomWalkの代用品として下記のようなスクリプトを用意しました。これを各ユニットにアタッチして徘徊させます。

lang

1using System.Collections; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5 6public class RandomWalk : MonoBehaviour 7{ 8 private static readonly Vector2[] Directions = {Vector2.up, Vector2.right, Vector2.down, Vector2.left}; 9 10 [SerializeField][Min(0.0f)] private float idleDuration = 1.0f; 11 [SerializeField][Min(0.0f)] private float walkDuration = 0.5f; 12 13 private Coroutine randomWalkCoroutine; 14 15 private void Start() 16 { 17 Physics2D.queriesStartInColliders = false; 18 StartRandomWalk(); 19 } 20 21 public void StartRandomWalk() 22 { 23 StopRandomWalk(); 24 randomWalkCoroutine = StartCoroutine(RandomWalkLogic()); 25 } 26 27 public void StopRandomWalk() 28 { 29 if (randomWalkCoroutine == null) 30 { 31 return; 32 } 33 34 StopCoroutine(randomWalkCoroutine); 35 randomWalkCoroutine = null; 36 } 37 38 private IEnumerator RandomWalkLogic() 39 { 40 WaitForSeconds wait = new WaitForSeconds(idleDuration); 41 List<Vector2> randomizedDirections = new List<Vector2>(4); 42 while (true) 43 { 44 yield return wait; 45 46 Vector2 currentPosition = this.transform.position; 47 randomizedDirections.Clear(); 48 randomizedDirections.AddRange(Directions.Where(d => !Physics2D.Raycast(currentPosition, d, 1.0f))); 49 if (randomizedDirections.Count > 0) 50 { 51 Vector2 randomDirection = randomizedDirections[Random.Range(0, randomizedDirections.Count)]; 52 Vector3 velocity = randomDirection / this.walkDuration; 53 float t = 0.0f; 54 while (true) 55 { 56 transform.Translate(velocity * Time.deltaTime); 57 t += Time.deltaTime; 58 if (t >= walkDuration) 59 { 60 break; 61 } 62 yield return null; 63 } 64 transform.position = currentPosition + randomDirection; 65 } 66 } 67 } 68}

そしてMoving_from_PositionA_to_PositionBですが、後述しますがBerserkermode側で移動動作を行わせようと思った都合から、下記のように変更を加えました。思考の整理上(そして字数の節約上)すみませんが大部分を削除してしまいましたので、必要な部分までなくなってしまっている可能性があります。あくまでも参考ということでご容赦ください。

lang

1using System.Collections.ObjectModel; 2using UnityEngine; 3 4namespace UtilityModule 5{ 6 public class Moving_from_PositionA_to_PositionB : MonoBehaviour 7 { 8 private readonly int map_Height = 250; 9 private readonly int map_Width = 250; 10 private ChessboardPathFinder pathFinder; 11 12 public ReadOnlyCollection<Vector2Int> Path => pathFinder.Path; 13 14 private void Awake() 15 { 16 pathFinder = new ChessboardPathFinder(map_Width, map_Height); 17 } 18 19 public bool Find_Path(Vector2Int startPosition, Vector2Int goalPosition) 20 { 21 bool pathFound = pathFinder.FindPath(startPosition, goalPosition); 22 return pathFound; 23 } 24 } 25}

Berserkermodeは下記のようにしました。これも同様にちょっと作りが変わってしまいましたので、参考として割り切っていただけるとありがたいです。

lang

1using System.Collections; 2using System.Linq; 3using UnityEngine; 4using UtilityModule; 5 6namespace Module_of_Berserkermode 7{ 8 public class Berserkermode : MonoBehaviour 9 { 10 [SerializeField] private Material berserkerModeMaterial; 11 [SerializeField] private Material nonBerserkerModeMaterial; 12 [SerializeField][Min(0.0f)] private float walkDuration = 0.25f; 13 14 private Moving_from_PositionA_to_PositionB moving_From_PositionA_To_PositionB; 15 private Coroutine berserkerModeCoroutine; 16 private bool needsStopBerserkerMode; 17 private RandomWalk randomWalk; 18 private new Renderer renderer; 19 20 private bool IsBerserkerMode => berserkerModeCoroutine != null; 21 22 private void Awake() 23 { 24 moving_From_PositionA_To_PositionB = gameObject.GetComponent<Moving_from_PositionA_to_PositionB>(); 25 randomWalk = GetComponent<RandomWalk>(); 26 renderer = GetComponent<Renderer>(); 27 } 28 29 private void Update() 30 { 31 // 実験目的ということで単純化し、不満値は設けずに 32 // スペースキーでバーサーカーモードを始動するようにした 33 if (Input.GetKeyDown(KeyCode.Space)) 34 { 35 if (IsBerserkerMode) 36 { 37 StopBerserkerMode(); 38 randomWalk.StartRandomWalk(); 39 } 40 else 41 { 42 StartBerserkerMode(); 43 } 44 } 45 } 46 47 private void StartBerserkerMode() 48 { 49 StopBerserkerMode(); 50 51 // 視覚的にわかりやすくするため、バーサーカーモード用のマテリアル(赤色)に切り替える 52 renderer.material = berserkerModeMaterial; 53 54 // ランダム移動を停止、バーサーカーモードコルーチンを始動する 55 randomWalk.StopRandomWalk(); 56 berserkerModeCoroutine = StartCoroutine(BerserkerModeLogic()); 57 } 58 59 private void StopBerserkerMode() 60 { 61 if (berserkerModeCoroutine == null) 62 { 63 return; 64 } 65 66 // ユニットがタイル間を移動中の可能性があるので、次のタイルに到達するまでは待つことにする 67 StartCoroutine(WaitForStopBerserkerMode()); 68 } 69 70 private IEnumerator WaitForStopBerserkerMode() 71 { 72 if (!IsBerserkerMode) 73 { 74 yield break; 75 } 76 needsStopBerserkerMode = true; 77 yield return berserkerModeCoroutine; 78 berserkerModeCoroutine = null; 79 needsStopBerserkerMode = false; 80 81 // 視覚的にわかりやすくするため、徘徊モード用のマテリアル(緑色)に切り替える 82 renderer.material = nonBerserkerModeMaterial; 83 84 // ランダム移動を再開 85 randomWalk.StartRandomWalk(); 86 } 87 88 private IEnumerator BerserkerModeLogic() 89 { 90 while (true) 91 { 92 // まず、一番近いユニットをターゲットとして選択する 93 Transform targetTransform = GameObject.FindGameObjectsWithTag("Target") 94 .Select(target => (target.transform, Vector2.Distance(target.transform.position, transform.position))) 95 .OrderBy(pair => pair.Item2) 96 .Select(pair => pair.transform) 97 .FirstOrDefault(); 98 99 // ターゲットの上下左右4タイルのうち、一番近いタイルを目的地として採用する 100 Vector2Int cellPosition = Vector2Int.RoundToInt(transform.position); 101 Vector2Int targetCellPosition = Vector2Int.RoundToInt(targetTransform.position); 102 Vector2Int destinationCellPosition = GetNearestNeighborCellPosition(cellPosition, targetCellPosition); 103 104 // パス探索を行う 105 // パスが見つからなかった場合はバーサーカーモードを終了する 106 if (!moving_From_PositionA_To_PositionB.Find_Path(cellPosition, destinationCellPosition) || (moving_From_PositionA_To_PositionB.Path.Count < 2)) 107 { 108 break; 109 } 110 111 // 探索された経路を確認する目的で、シーンビュー上に黄色い線を引く 112 for (int i = 1; i < moving_From_PositionA_To_PositionB.Path.Count; i++) 113 { 114 Debug.DrawLine( 115 (Vector2)moving_From_PositionA_To_PositionB.Path[i], 116 (Vector2)moving_From_PositionA_To_PositionB.Path[i - 1], 117 Color.yellow); 118 } 119 120 // 経路上の次のタイルに向かって移動する 121 Vector3 nextTilePosition = (Vector3)(Vector2)moving_From_PositionA_To_PositionB.Path[1]; 122 Vector3 velocity = (nextTilePosition - transform.position) / walkDuration; 123 float t = 0.0f; 124 while (true) 125 { 126 transform.Translate(velocity * Time.deltaTime); 127 t += Time.deltaTime; 128 if (t >= walkDuration) 129 { 130 break; 131 } 132 yield return null; 133 } 134 transform.position = nextTilePosition; 135 136 // バーサーカーモード終了要求が来ていたらループを終える 137 if (needsStopBerserkerMode) 138 { 139 break; 140 } 141 } 142 StopBerserkerMode(); 143 } 144 145 private static Vector2Int GetNearestNeighborCellPosition(Vector2Int origin, Vector2Int target) 146 { 147 int deltaX = Mathf.Clamp(origin.x - target.x, -1, 1); 148 int deltaY = Mathf.Abs(deltaX) > 0 ? 0 : Mathf.Clamp(origin.y - target.y, -1, 1); 149 return new Vector2Int(target.x + deltaX, target.y + deltaY); 150 } 151 } 152}

動きは下図のようになりました。

図1

くの字の経路になってしまい、見苦しくてすみません。一応あれでもチェス盤空間においては最短経路の一つのはずですが、遠回りしているように感じます。「Unity A*(A-Star)アルゴリズム 挙動がおかしくなる」では、経路の評価に使う情報としては浮動小数点数の計算が必要なユークリッド距離よりも、チェス盤ならチェビシェフ距離を使って経路を評価した方がいいんじゃないかと思っていたのですが、こういった見苦しさにつながる可能性は失念していました。

ユークリッド距離を使うと縦横の経路の方が斜めの経路よりも高評価になりますので、下図のように見苦しさが低減するかと思います。こちらの方がお好みでしたらChessboardPathFinderを適宜書き換えてしまってください。

図2

投稿2021/06/23 18:54

編集2021/06/27 00:13
Bongo

総合スコア10811

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/06/25 18:04 編集

回答ありがとうございます。 ターゲットが動くたびに再計算することはできたのですが、座標が変更されるたびに再計算し移動するせいで、移動するユニットがぐらぐら揺れながら移動するようになってしまいました。
Bongo

2021/06/25 21:07

なるほど...経路を更新した場合、経路の最初の地点は現在のユニットの位置を整数に切り捨てた位置になるわけですから、最初にそこへ向かおうとしてガクガクしてしまうのかもしれませんね。 となると、泥縄的ですみませんがMoving_from_PositionA_to_PositionBスクリプトのMoveの冒頭にある... foreach (Vector2Int position in pathFinder.Path) { Vector2 pos = new Vector3(position.x, position.y); moveList.Add(pos); } を... foreach (Vector2Int position in pathFinder.Path.Skip(1)) { Vector2 pos = new Vector3(position.x, position.y); moveList.Add(pos); } としてみるとどうでしょうか。つまり最初の地点は経路から捨ててしまおうと思ったのです(ちなみに、Skipを使うにはスクリプトの冒頭に using System.Linq; が必要になるかと思います)。 これで何かしら改善が見られればいいのですが、ダメならちょっと模擬シーンを作って本腰入れて検討してみたいところです。その場合、スクリーンショットだとかのご質問者さんのシーンの作りがイメージできるような参考情報を追記いただけるとありがたいです。また、ユニットの動き方についてうかがいますが、求めた経路を折れ線の道筋で辿るのではなく、なめらかにカーブを描いて目的地へ向かう方が好ましいでしょうか?
退会済みユーザー

退会済みユーザー

2021/06/26 07:29

スクリプトを編集し、スクリーンショットを追加致しました。 イメージとしては、折れ線の道筋を辿っていくことを考えていました。
退会済みユーザー

退会済みユーザー

2021/06/26 07:31

Unit_RandomWalk.csというスクリプトは、ユニットの半径6マス以内をランダムに移動するだけの単純なのものです。文字数制限があるため、コードは記載しませんでした。
Bongo

2021/06/27 00:13

ちょっと模擬シーンを作って検討してみました。ご参考になれば幸いです。 投稿字数制限はやっかいですね。私もあの回答文の分量でほぼ使い切ってしまっています。ちょっとコードを載せればすぐオーバーしてしまいますし、もう少し緩和していただければうれしいんですがね...
退会済みユーザー

退会済みユーザー

2021/06/27 05:27

回答ありがとうございます。実装することはできたのですが、自分の環境だとバーサーカーモードになったユニットの移動速度が通常よりも速い気がするのですが、気のせいでしょうか?斜め移動だから移動速度が速いように見えるだけなのでしょうか?
Bongo

2021/06/27 08:56

すみません。RandomWalkやBerserkermodeにwalkDurationという名称のフィールドがありますが、これが1タイル移動するのにかかる時間を表しており、提示しましたコードにあるようにデフォルト値はRandomWalkが0.5秒、Berserkermodeが0.25秒となっています。 バーサーカーモードだと怒りながら早歩きで獲物に向かっていくのかな...と思ってそうしたのですが、バーサーカーモードの動きが速すぎると、肝心の「動く獲物に対してその都度経路を再計算して接近している」ということを図示しにくかったため、インスペクター上でBerserkermodeのwalkDurationを1秒に変更したのを申し上げ忘れていました。 ご質問者さんの場合はここの設定はどうなっていますでしょうか?
退会済みユーザー

退会済みユーザー

2021/06/27 12:11

walkDurationという変数が1タイル移動するのに必要な時間を意味していたのですね。分かりました。丁寧な回答、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問