// (src,target]までRayCastする public override void RaycastCell(Vector2 src, Vector2 target, AstarCell.Type ignore, System.Func <int, int, bool> act) { if (this.UsingUnityRaycast) { var hits = Physics.SphereCastAll(new Vector3(src.x, this.TileSize * 0.6f, src.y), this.RayCastHalfExtents, // this.TileSize * 0.5f, new Vector3(target.x - src.x, 0.0f, target.y - src.y), (target - src).magnitude); foreach (var h in hits) { if (this.DisallowTags.Contains(h.transform.tag)) { continue; } var pos = hits[0].transform.position; int index = this.cellIndex(new Vector2(pos.y, pos.z)); AstarCell cell = null; if (index >= 0 && index < this.cellMapBody.Count()) { cell = this.cellMapBody[index]; } ///act(cell); return; } ///act(this.CellMap(target)); } else { base.RaycastCell(src, target, ignore, act); } }
// 動的なセルの追加(状態変更) public override AstarCell AddCellImmediate(Vector2 pos, AstarCell.Type type) { // グリッドタイプの場合は、既存のセルの属性を変える var cell = CellMap(pos); cell.CellType = type; MakeRelation(cell); return(cell); }
private void setCellType(Vector2 pos, AstarCell.Type cellType) { int ix = (int)((pos.x - this.MapRect.x) / this.TileSize + 0.5f); int iy = (int)((pos.y - this.MapRect.y) / this.TileSize + 0.5f); if (ix < 0 || ix >= this.GridWidth || iy < 0 || iy > this.GridHeight) { Debug.LogError(string.Format("invalid cell position({0},{1})", pos.x, pos.y)); } else { this.cellType[ix, iy] = cellType; } }
public override AstarCell AddCellImmediate(Vector2 pos, AstarCell.Type type) { if (this.GridMode) { return(base.AddCellImmediate(pos, type)); } else { AstarCell cell = null; if (type == AstarCell.Type.Start || type == AstarCell.Type.Goal) { // スタートかゴールがブロックの場合はエラー if (CellMap(pos).CellType == AstarCell.Type.Block) { return(null); } } else { // StartとGoal以外はセルを探す cell = CellMap(pos); } if (cell == null) { cell = new AstarCell(); cell.CellType = type; cell.Position = pos; setCellType(cell); MakeRelation(cell); this.logic.cells.Add(cell); } else { cell.CellType = type; setCellType(cell); MakeRelation(cell); if (!this.logic.cells.Contains(cell)) { this.logic.cells.Add(cell); } } return(cell); } }
// 基本的なAStartでは処理が冗長のため、最適化を行う // 障害物の凸頂点以外のノードを削除する public void MapMake() { foreach (var cell in this.cellMapBody) { if (cell.CellType != AstarCell.Type.Block) { cell.CellType = AstarCell.Type.Empty; } cell.Related.Clear(); } // 8方向全部がEmptyであるセルを削除 var octcells = this.cellMapBody.Where(c => { if (c.CellType != AstarCell.Type.Empty) { return(false); } for (int ix = -1; ix < 2; ++ix) { for (int iy = -1; iy < 2; ++iy) { if (ix == 0 && iy == 0) { continue; } Vector2 ixy = new Vector2(ix * this.TileSize, iy * this.TileSize); if (this.CellType(c.Position + ixy) != AstarCell.Type.Empty) { return(false); } } } return(true); } ).ToList(); foreach (var cell in octcells) { cell.CellType = AstarCell.Type.Removed; } var emptyCells = this.cellMapBody.Where(c => c.CellType == AstarCell.Type.Empty); // 3x3周囲のセル情報をセットする System.Action <Vector2, AstarCell.Type[, ]> set3x3 = (pos, ar) => { for (int ix = -1; ix < 2; ++ix) { for (int iy = -1; iy < 2; ++iy) { if (ix == 0 && iy == 0) { continue; } float x = pos.x + (ix * this.TileSize); float y = pos.y + (iy * this.TileSize); ar[ix + 1, iy + 1] = this.CellType(new Vector2(x, y)); } } }; // 角以外のセルを削除 List <AstarCell> removeList = new List <AstarCell>(); foreach (var cell in emptyCells) { var pos = cell.Position; AstarCell.Type[,] ar = new AstarCell.Type[3, 3]; // check around set3x3(pos, ar); // 縦横3連ブロックチェック for (int inv = 0; inv < 2; ++inv) { // x,yを反転させる System.Func <int, int, AstarCell.Type> m = (x, y) => { return(inv == 0 ? ar[x, y] : ar[y, x]); }; // 両サイド for (int s = 0; s <= 2; s += 2) { int u = 2 - s; // 逆サイド if (m(s, 0) == m(s, 1) && m(s, 1) == m(s, 2) && m(s, 0) == AstarCell.Type.Block) { // サイドがすべてブロック if (m(1, 0) == AstarCell.Type.Empty && m(1, 2) == AstarCell.Type.Empty) { // 上下3連でEmpty if (m(u, 0) != AstarCell.Type.Block && m(u, 1) != AstarCell.Type.Block && m(u, 2) != AstarCell.Type.Block) { removeList.Add(cell); } } if (m(1, 0) == AstarCell.Type.Empty || m(1, 2) == AstarCell.Type.Empty) { // 凹角の判断 if ((m(1, 2) == AstarCell.Type.Block && m(u, 2) == AstarCell.Type.Block && m(u, 0) != AstarCell.Type.Block) || (m(1, 0) == AstarCell.Type.Block && m(u, 0) == AstarCell.Type.Block && m(u, 2) != AstarCell.Type.Block)) { removeList.Add(cell); } } } } } } foreach (var cell in removeList) { cell.CellType = AstarCell.Type.Removed; } removeList.Clear(); if (!this.GridMode) { // グリッドモードでない場合は、さらに最適化を進める foreach (var cell in emptyCells.Where(c => c.CellType == AstarCell.Type.Empty)) { var pos = cell.Position; AstarCell.Type[,] ar = new AstarCell.Type[3, 3]; // check around set3x3(pos, ar); // 90度つず回転する[x,y][y,x][-x,y][x,-y] for (int angle = 0; angle < 8; ++angle) { System.Func <int, int, AstarCell.Type> m = (x, y) => { switch (angle) { default: case 0: return(ar[x, y]); case 1: return(ar[y, 2 - x]); case 2: return(ar[2 - x, 2 - y]); case 3: return(ar[2 - y, x]); case 4: return(ar[y, x]); case 5: return(ar[x, 2 - y]); case 6: return(ar[2 - y, 2 - x]); case 7: return(ar[2 - x, y]); } }; // 角にある3点を1点にする // □ □ □ □ □ □ // □ * * => □ □ * // ? ■ ? ? ■ * if (m(0, 0) == AstarCell.Type.Removed && m(1, 0) == AstarCell.Type.Removed && m(2, 0) == AstarCell.Type.Removed && m(0, 1) == AstarCell.Type.Removed && m(1, 1) == AstarCell.Type.Empty && m(2, 1) == AstarCell.Type.Empty && /*&& m(0,2) == AstarCell.Type.Block*/ m(1, 2) == AstarCell.Type.Block /*&& m(2, 2) == AstarCell.Type.Empty*/) { removeList.Add(cell); } // 冗長な斜めの線を細くする // □ * !□ □ * * // * * ■ => * □ ■ // !□ ■ ■ * ■ ■ if (angle < 4 && m(0, 0) == AstarCell.Type.Removed && m(1, 0) == AstarCell.Type.Empty && m(2, 0) != AstarCell.Type.Removed && m(0, 1) == AstarCell.Type.Empty && m(1, 1) == AstarCell.Type.Empty && m(2, 1) == AstarCell.Type.Block && m(0, 2) != AstarCell.Type.Removed && m(1, 2) == AstarCell.Type.Block && m(2, 2) == AstarCell.Type.Block) { removeList.Add(cell); } // 3連続の中を抜く // ? * ? ? * ? // !* * !* => ? □ ? // ? * ? ? * ? if ((angle == 0 || angle == 4) && m(1, 0) == AstarCell.Type.Empty && m(1, 1) == AstarCell.Type.Empty && m(1, 2) == AstarCell.Type.Empty && (m(0, 1) != AstarCell.Type.Empty && m(2, 1) != AstarCell.Type.Empty) ) { removeList.Add(cell); } // 斜め3連続の中を抜く // !□ ? * □ □ * // □ * □ => □ □ □ // * ? !□ * □ □ if ((angle == 0 || angle == 7) && m(0, 0) != AstarCell.Type.Empty /*&& m(1,0) == AstarCell.Type.Removed */ && m(2, 0) == AstarCell.Type.Empty && /*&& m(0,1) == AstarCell.Type.Removed*/ m(1, 1) == AstarCell.Type.Empty && /*&& m(2,1) == AstarCell.Type.Removed*/ m(0, 2) == AstarCell.Type.Empty /*&& m(1,2) == AstarCell.Type.Removed */ && m(2, 2) != AstarCell.Type.Empty) { removeList.Add(cell); } } } foreach (var cell in removeList) { cell.CellType = AstarCell.Type.Removed; } } // キャッシュ用セルを作成 this.cellType = new AstarCell.Type[this.GridWidth, this.GridHeight]; foreach (var cell in this.cellMapBody) { setCellType(cell); } // 有効なセルの登録 this.logic.cells = this.cellMapBody.Where(c => c.CellType == AstarCell.Type.Empty).Select(c => c as AstarCell).ToList(); // 残ったセルに対して、接続情報をセットする if (this.PreCalculateRelation) { foreach (var cell in this.logic.cells) { setGridRelatedSearchRaycast(cell, true); cell.RelationBuilt = true; } } this.MapReady = true; }
// (src,target] までDDAでトレースする // DDAでレイキャスト // (src,target] までDDAでトレースする public virtual void RaycastCell(Vector2 src, Vector2 target, AstarCell.Type ignore, System.Func <int, int, bool> act) { int ix = (int)((src.x - this.MapRect.x) / this.TileSize + 0.5f); int iy = (int)((src.y - this.MapRect.y) / this.TileSize + 0.5f); int tx = (int)((target.x - this.MapRect.x) / this.TileSize + 0.5f); int ty = (int)((target.y - this.MapRect.y) / this.TileSize + 0.5f); int sx = ix > tx ? -1 : 1; int sy = iy > ty ? -1 : 1; int dx = Mathf.Abs(tx - ix); int dy = Mathf.Abs(ty - iy); if (dx == dy) { //ななめ45度 while (true) { ix += sx; iy += sy; if (--dx < 0) { break; } if (this.cellType[ix, iy] != ignore) { if (act(ix, iy)) { return; } } } } else if (dx > dy) { // 横に長い int r = dx / 2; while (sx > 0 ? ix <tx : ix> tx) { ix += sx; r -= dy; if (r < 0) { r += dx; iy += sy; } if (this.cellType[ix, iy] != ignore) { if (act(ix, iy)) { return; } } } } else { // 縦に長い int r = dy / 2; while (sy > 0 ? iy <ty : iy> ty) { iy += sy; r -= dx; if (r < 0) { r += dy; ix += sx; } if (this.cellType[ix, iy] != ignore) { if (act(ix, iy)) { return; } } } } }
// 動的なセルの追加(状態変更) public abstract AstarCell AddCellImmediate(Vector2 pos, AstarCell.Type type);