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

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

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

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

2回答

700閲覧

Unity: Astarアルゴリズムのマス目管理コードに関する質問

Yale

総合スコア23

C#

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

0クリップ

投稿2022/09/11 02:31

前提

この質問で掲載するコードはこちらのブログ運営者様のものです(ソースコードのライセンスはWTFPLです)。
Unityのバージョンは問わず、回答をお待ちしております。
また、本質問はAstarアルゴリズムを使用するために必要となる、マス目の管理に関する質問です。
もし、可能であれば「なぜAstarアルゴリズムではそれが必要か」と言う形で回答いただければ幸いです(必須ではない)。
お手数をおかけしますがよろしくお願い申し上げます。

質問

上記のブログ記事で紹介されているソースコード中、ユーザー定義型の計算周りで不明な点がありました。
operator +(あるいは-)は演算子のオーバーロードであり、ユーザー定義型と組み込み型との計算を可能にするものであるということは検索等で知ったところですが、以下の二行が具体的にどのような計算に用いられているのか(あるいはどこで、どういったタイミングでその計算が行われているのか)分からず困っています。

プログラミング初心者のため、稚拙な質問になってしまい申し訳ございませんが、お教えいただければ幸いです。よろしくお願い申し上げます。

csharp

1 public static Coord operator +(Coord a, Coord b) { return new Coord(a.x + b.x, a.y + b.y); } 2 public static Coord operator -(Coord a, Coord b) { return new Coord(a.x - b.x, a.y - b.y); }

該当のソースコード

csharp

1using System.Collections.Generic; 2using UnityEngine; 3 4[System.Serializable] 5public class AStarGrid 6{ 7 public enum GroundType 8 { 9 NotRoad, 10 Road, 11 } 12 13 /// <summary> 14 /// 座標 15 /// </summary> 16 [System.Serializable] 17 public struct Coord 18 { 19 public int x; 20 public int y; 21 22 public static Coord zero = new Coord(){ x = 0, y = 0 }; 23 public static Coord one = new Coord(){ x = 1, y = 1 }; 24 public static Coord left = new Coord(){ x = -1, y = 0 }; 25 public static Coord up = new Coord(){ x = 0, y = 1 }; 26 public static Coord right = new Coord(){ x = 1, y = 0 }; 27 public static Coord down = new Coord(){ x = 0, y = -1 }; 28 public static Coord operator +(Coord a, Coord b) { return new Coord(a.x + b.x, a.y + b.y); } 29 public static Coord operator -(Coord a, Coord b) { return new Coord(a.x - b.x, a.y - b.y); } 30 31 public float SqrMagnitude { get { return x * x + y * y; } } 32 public float Magnitude { get { return Mathf.Sqrt(SqrMagnitude); } } 33 34 public Coord(int x, int y) 35 { 36 this.x = x; 37 this.y = x; 38 } 39 } 40 41 /// <summary> 42 /// セル 43 /// </summary> 44 [System.Serializable] 45 public class Cell 46 { 47 public Coord coord; 48 public GroundType groundType; 49 } 50 51 [SerializeField] 52 private List<Cell> _cells; 53 public List<Cell> Cells { get { return _cells; } } 54 [SerializeField] 55 private int _columnCount; 56 public int ColumnCount { get { return _columnCount; } } 57 [SerializeField] 58 private int _rowCount; 59 public int RowCount { get { return _rowCount; } } 60 [SerializeField] 61 private Coord _startCellCoord; 62 public Cell StartCell { get { return GetCell(_startCellCoord); } set { _startCellCoord = value.coord; } } 63 [SerializeField] 64 private Coord _goalCellCoord; 65 public Cell GoalCell { get { return GetCell(_goalCellCoord); } set { _goalCellCoord = value.coord; } } 66 67 public AStarGrid(int columnCount, int rowCount) 68 { 69 _columnCount = columnCount; 70 _rowCount = rowCount; 71 _cells = new List<Cell>(); 72 for (int i = 0; i < columnCount * rowCount; i++) { 73 var column = Mathf.FloorToInt(i / rowCount); 74 var row = i % rowCount; 75 var coord = new Coord(){ x = column, y = row }; 76 _cells.Add(new Cell(){ coord = coord }); 77 } 78 } 79 80 /// <summary> 81 /// セルを取得する 82 /// </summary> 83 public Cell GetCell(Coord coord){ 84 return GetCell(coord.x, coord.y); 85 } 86 87 /// <summary> 88 /// セルを取得する 89 /// </summary> 90 public Cell GetCell(int x, int y) 91 { 92 if (IsValidCoord(x, y)) { 93 var index = x * _rowCount + y; 94 return _cells[index]; 95 } 96 else { 97 return null; 98 } 99 } 100 101 /// <summary> 102 /// 存在するセルか 103 /// </summary> 104 public bool IsValidCoord(int x, int y) 105 { 106 return x >= 0 && x < _columnCount && y >= 0 && y < _rowCount; 107 } 108 109 /// <summary> 110 /// 隣接するセルを取得する 111 /// </summary> 112 public List<Cell> GetAdjacences(int x, int y) 113 { 114 var adjacences = new List<Cell>(); 115 var offsets = new Coord[] { Coord.left, Coord.up, Coord.right, Coord.down }; 116 for (int i = 0; i < offsets.Length; i++) { 117 var cell = GetCell(x + offsets[i].x, y + offsets[i].y); 118 if (cell != null) { 119 adjacences.Add(cell); 120 } 121 } 122 return adjacences; 123 } 124}

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

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

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

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

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

YAmaGNZ

2022/09/11 02:58

提示されているコードとは別のコードで使ってたりしませんか?
Yale

2022/09/11 05:47

こちらがそのほかのコードです。 using System.Collections.Generic; using System.Linq; public class AStar { private class AStarInfo { public AStarGrid.Cell cell; public AStarInfo previous; public float step; public float distance; public float Weight { get { return step + distance; } } } private AStarGrid _grid; public AStar(AStarGrid grid) { _grid = grid; } /// <summary> /// 最短距離を取得する /// StartとGoalのセルを含む /// </summary> public List<AStarGrid.Cell> GetShortestWay(AStarGrid.Cell StartCell, AStarGrid.Cell GoalCell) { var res = new List<AStarGrid.Cell>(); var passedCells = new List<AStarGrid.Cell>(); var recentTargets = new List<AStarInfo>(); passedCells.Add(StartCell); recentTargets.Add(GetAStarInfo(StartCell, GoalCell, null)); AStarInfo goalInfo = null; while (true) { // recentTargetsのうちweightが最も低いものを計算対象とする var currentTarget = recentTargets .OrderBy(info => info.Weight) .FirstOrDefault(); // ターゲットの隣接セルのAStarInfoを取得する var adjacentInfos = _grid.GetAdjacences(currentTarget.cell.coord.x, currentTarget.cell.coord.y) .Where(cell => { // タイプが道でもなくゴールのセルでもない場合は対象外 if (cell.groundType != AStarGrid.GroundType.Road && cell != GoalCell) { return false; } // 計算済みのセルは対象外 if (passedCells.Contains(cell)) { return false; } return true; }) .Select(cell => GetAStarInfo(cell, GoalCell, currentTarget)) .ToList(); // recentTargetsとpassedCellsを更新 recentTargets.Remove(currentTarget); recentTargets.AddRange(adjacentInfos); passedCells.Add(currentTarget.cell); // ゴールが含まれていたらそこで終了 goalInfo = adjacentInfos.FirstOrDefault(info => info.cell == GoalCell); if (goalInfo != null) { break; } // recentTargetsがゼロだったら行き止まりなので終了 if (recentTargets.Count == 0) { break; } } // ゴールが結果に含まれていない場合は最短経路が見つからなかった if (goalInfo == null) { return res; } // Previousを辿ってセルのリストを作成する res.Add(goalInfo.cell); AStarInfo current = goalInfo; while(true){ if (current.previous != null) { res.Add(current.previous.cell); current = current.previous; } else { break; } } return res; } private AStarInfo GetAStarInfo(AStarGrid.Cell targetCell, AStarGrid.Cell goalCell, AStarInfo previousInfo) { var result = new AStarInfo(); result.cell = targetCell; result.previous = previousInfo; result.step = previousInfo == null ? 0 : previousInfo.step + 1; result.distance = (goalCell.coord - targetCell.coord).Magnitude; return result; } } ------------------ #if UNITY_EDITOR using System.Collections.Generic; using UnityEngine; using System.Linq; using UnityEditor; [ExecuteInEditMode] public class AStarSample : MonoBehaviour { private const int COLUMN_COUNT = 10; private const int ROW_COUNT = 10; private const float CELL_SIZE = 1.0f; [SerializeField] private AStarGrid _grid = null; private AStar _aStar; private List<AStarGrid.Cell> _shortestWay = new List<AStarGrid.Cell>(); private void OnEnable() { if (_grid == null) { _grid = new AStarGrid(COLUMN_COUNT, ROW_COUNT); _grid.StartCell = _grid.GetCell(0, 0); _grid.GoalCell = _grid.GetCell(COLUMN_COUNT - 1, ROW_COUNT - 1); } _aStar = new AStar(_grid); } private void OnDrawGizmos() { Tools.current = Tool.None; var preColor = Gizmos.color; var preMatrix = Gizmos.matrix; Gizmos.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * CELL_SIZE); // クリック判定 if(Event.current != null && Event.current.type == EventType.MouseUp){ // レイを取得する var clickedPosition = Event.current.mousePosition; clickedPosition.y = SceneView.currentDrawingSceneView.camera.pixelHeight - clickedPosition.y; var clickRay = SceneView.currentDrawingSceneView.camera.ScreenPointToRay(clickedPosition); // レイとy=0の平面との交点を求める var scale = Mathf.Abs(clickRay.origin.y / clickRay.direction.y); var intersection = clickRay.origin + clickRay.direction * scale; // 選択されたセルを編集するメニューを描画 intersection /= CELL_SIZE; var selectedColumn = Mathf.FloorToInt(intersection.x); var selectedRow = Mathf.FloorToInt(intersection.z); if (selectedColumn >= 0 && selectedColumn < COLUMN_COUNT && selectedRow >= 0 && selectedRow < ROW_COUNT) { GenericMenu menu = new GenericMenu(); // CellType変更メニュー var cell = _grid.GetCell(selectedColumn, selectedRow); menu.AddItem(new GUIContent ("Set Type > Not Road"), cell.groundType == AStarGrid.GroundType.NotRoad, () => { Undo.RecordObject(this, "Set Type > Not Road"); cell.groundType = AStarGrid.GroundType.NotRoad; EditorUtility.SetDirty(this); }); menu.AddItem(new GUIContent ("Set Type > Road"), cell.groundType == AStarGrid.GroundType.Road, () => { Undo.RecordObject(this, "Set Type > Road"); cell.groundType = AStarGrid.GroundType.Road; EditorUtility.SetDirty(this); }); menu.AddItem(new GUIContent ("Set Type > Start"), _grid.StartCell == cell, () => { Undo.RecordObject(this, "Set Type > Start"); _grid.StartCell = cell; EditorUtility.SetDirty(this); }); menu.AddItem(new GUIContent ("Set Type > Goal"), _grid.GoalCell == cell, () => { Undo.RecordObject(this, "Set Type > Goal"); _grid.GoalCell = cell; EditorUtility.SetDirty(this); }); menu.AddItem(new GUIContent ("Show Shortest Way"), false, () => { _shortestWay = _aStar.GetShortestWay(_grid.StartCell, _grid.GoalCell); }); menu.ShowAsContext(); } } // セルを描画 System.Action<AStarGrid.Cell> drawCell = cell => { Gizmos.DrawWireCube(new Vector3(cell.coord.x + 0.5f, 0.0f, cell.coord.y + 0.5f), new Vector3(1.0f, 0.0f, 1.0f)); }; Gizmos.color = Color.green; foreach (var item in _grid.Cells.Where(cell => cell.groundType == AStarGrid.GroundType.NotRoad)) { drawCell(item); } Gizmos.color = Color.yellow; foreach (var item in _grid.Cells.Where(cell => cell.groundType == AStarGrid.GroundType.Road)) { drawCell(item); } Gizmos.color = Color.blue; if (_grid.StartCell != null) { drawCell(_grid.StartCell); } Gizmos.color = Color.red; if (_grid.GoalCell != null) { drawCell(_grid.GoalCell); } Gizmos.color = Color.red; foreach (var item in _shortestWay) { Gizmos.DrawSphere(new Vector3(item.coord.x + 0.5f, 0.0f, item.coord.y + 0.5f), 0.2f); } Gizmos.color = preColor; Gizmos.matrix = preMatrix; } } #endif
YAmaGNZ

2022/09/11 06:01

質問がはっきりしませんが、演算子をオーバーロードしているのが必要かという話であれば「必要」ではないでしょう。 オーバーロードしないで、加算や減算をする関数AddCoord等を作ればいいだけですし。 パッと見、減算は2点の距離を求める際に使っているようです。
Yale

2022/09/11 06:05

ありがとうございました。
guest

回答2

0

自己解決

この質問はひとまず閉じます。

投稿2022/09/11 10:08

Yale

総合スコア23

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

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

0

operator +(あるいは-)は演算子のオーバーロードであり...以下の二行が具体的にどのような計算に用いられているのか(あるいはどこで、どういったタイミングでその計算が行われているのか)分からず困っています。

その二行をコメントアウトしてコンパイルしてみては?
(ふたつの Coord を加算する箇所でエラーとなるはず)

投稿2022/09/11 02:50

編集2022/09/11 02:52
episteme

総合スコア16614

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

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

Yale

2022/09/11 06:06

ありがとうございました。
episteme

2022/09/11 06:34

...解決したの?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問