218 lines
8.5 KiB
C#
218 lines
8.5 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class astar : MonoBehaviour
|
|
{
|
|
[Header("Grid Information")]
|
|
public int cellDensity = 1;
|
|
public float width;
|
|
public float height;
|
|
public Color gridBoundsVisualizeColor = Color.red;
|
|
public GameObject cellGameObject;
|
|
public Transform cellsParent;
|
|
public cellData[,] cells;
|
|
public cellData targetCell;
|
|
public cellData startCell;
|
|
void Start()
|
|
{
|
|
StartCoroutine(generateCells());
|
|
}
|
|
|
|
IEnumerator generateCells(){
|
|
//Generate cells in grid
|
|
float cellSize = cellGameObject.transform.localScale.x / (float)cellDensity;
|
|
Vector2 cellStartPosition = new Vector2( transform.position.x - width /2f, transform.position.y - height /2f)
|
|
+ new Vector2(cellSize/2f, cellSize/2f);
|
|
|
|
|
|
|
|
int horizontalCellCount = (int)(width / cellSize);
|
|
int verticalCellCount = (int)(height / cellSize);
|
|
cells = new cellData[horizontalCellCount,verticalCellCount];
|
|
// cellData[,] cellMatrix = new cellData[horizontalCellCount, verticalCellCount];
|
|
|
|
for(int x= 0; x < horizontalCellCount; x++){
|
|
for(int y = 0; y < verticalCellCount; y++){
|
|
Vector2 cellSpawnPos = cellStartPosition + new Vector2(cellSize * x, cellSize *y );
|
|
GameObject cell = Instantiate(cellGameObject, cellSpawnPos , Quaternion.identity);
|
|
cell.transform.localScale = cell.transform.localScale / (float)cellDensity;
|
|
cell.GetComponent<cellData>().x = x;
|
|
cell.GetComponent<cellData>().y = y;
|
|
cell.transform.parent = cellsParent;
|
|
cell.transform.name = "cell["+x+","+y+"]";
|
|
//isObstacle?
|
|
cell.GetComponent<cellData>().setObstacle(Physics2D.BoxCast(cell.transform.position, cell.transform.localScale/2f, 0 ,Vector2.zero));
|
|
//cell.GetComponent<cellData>().setObstacle(Physics2D.CircleCast(cellSpawnPos,cellSize /2f,Vector2.zero));
|
|
|
|
//cells.Add(cell.GetComponent<cellData>());
|
|
cells[x,y] = cell.GetComponent<cellData>();
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
}
|
|
//Add neighbours
|
|
|
|
for(int x= 0; x < horizontalCellCount; x++){
|
|
for(int y = 0; y < verticalCellCount; y++){
|
|
for(int h = -1; h <= 1; h++){
|
|
for(int v = -1; v <= 1; v++){
|
|
if(h == 0 && v ==0){continue;}//I'm not a neighbour of me right?
|
|
int targetX = x + h;
|
|
int targetY = y + v;
|
|
|
|
if(targetY <0 || targetY > verticalCellCount-1 || targetX < 0 || targetX > horizontalCellCount-1){continue;}
|
|
if(cells[targetX,targetY].isObstacle){continue;}
|
|
cells[x,y].neighbours.Add(cells[targetX,targetY]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update is called once per frame
|
|
Coroutine calculator = null;
|
|
void Update()
|
|
{
|
|
if(Input.GetKeyDown(KeyCode.E)){
|
|
Vector2 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
|
|
|
cellData closestCell = getClosestCell(worldPos);
|
|
if(startCell!=null){startCell.setObstacle(startCell.isObstacle);}
|
|
startCell = closestCell;
|
|
startCell.GetComponent<SpriteRenderer>().color = Color.green;
|
|
}else if(Input.GetKeyDown(KeyCode.F)){
|
|
Vector2 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
|
if(targetCell!=null){targetCell.setObstacle(targetCell.isObstacle);}
|
|
cellData closestCell = getClosestCell(worldPos);
|
|
targetCell = closestCell;
|
|
targetCell.GetComponent<SpriteRenderer>().color = Color.blue;
|
|
}else if(Input.GetKeyDown(KeyCode.Return)){
|
|
if(calculator != null){StopCoroutine(calculator); resetCellsCost();}
|
|
Debug.Log("Starting calculation");
|
|
calculator = StartCoroutine(Calculate());
|
|
}
|
|
}
|
|
|
|
public cellData getClosestCell(Vector2 worldPos){
|
|
float minDist = Mathf.Infinity;
|
|
cellData closestCell = null;
|
|
foreach(cellData cell in cells){
|
|
if(cell.isObstacle){continue;}
|
|
float DistToCell = Vector3.Distance(worldPos, cell.transform.position);
|
|
if(DistToCell < minDist){
|
|
minDist = DistToCell;
|
|
closestCell = cell;
|
|
}
|
|
}
|
|
|
|
return closestCell;
|
|
}
|
|
|
|
|
|
void OnDrawGizmos(){
|
|
//Gizmos.Color = gridBoundsVisualizeColor;
|
|
Gizmos.color = gridBoundsVisualizeColor;
|
|
Gizmos.DrawWireCube(transform.position, new Vector3(width, height, 0));
|
|
}
|
|
List<cellData> calculatedCells = new List<cellData>();
|
|
List<cellData> openCells = new List<cellData>();
|
|
IEnumerator Calculate(){
|
|
// calculatedCells = new List<cellData>();
|
|
// bool foundPath = false;
|
|
// openCells=new List<cellData>();
|
|
// openCells.Add(startCell);
|
|
// while(!foundPath){
|
|
// cellData closeCell = null;
|
|
// float lowestFcost = Mathf.Infinity;
|
|
// foreach(cellData cell in openCells){
|
|
// if(cell.fCost < lowestFcost){
|
|
// closeCell=cell;
|
|
// lowestFcost=cell.fCost;
|
|
// }
|
|
// }
|
|
|
|
// if(closeCell == targetCell){Debug.Log("GOT THE TARGET!"); foundPath=true;}
|
|
// openCells.Remove(closeCell);
|
|
// calculateCellCost(closeCell);
|
|
// // if(! calculateCellCost(closeCell)){Debug.Log("YOU DUMB!");yield return new WaitForSeconds(0.01f);continue;}
|
|
// calculatedCells.Add(closeCell);
|
|
// closeCell.setClose(true);
|
|
|
|
// float minDist = Mathf.Infinity;
|
|
// cellData nextCloseCell = null;
|
|
// foreach(cellData cell in closeCell.neighbours){
|
|
// if(cell == null){continue;}
|
|
// if(cell.isClose){continue;}
|
|
// calculateCellCost(cell);
|
|
// if(cell.fCost < lowestFcost){
|
|
// openCells.Add(cell);
|
|
// }
|
|
// }
|
|
// if(nextCloseCell!=null){
|
|
|
|
// }else{
|
|
// Debug.Log("Hit a deadend, backtracking?");
|
|
// }
|
|
// // cellsToCalculate.Remove(cell);
|
|
// yield return new WaitForSeconds(0.1f);
|
|
// }
|
|
|
|
List<cellData> open = new List<cellData>();
|
|
List<cellData> close = new List<cellData>();
|
|
open.Add(startCell);
|
|
bool foundPath = false;
|
|
while(!foundPath){
|
|
cellData current = null;
|
|
float lowestF = Mathf.Infinity;
|
|
foreach(cellData cell in open){
|
|
if(cell.fCost < lowestF){
|
|
lowestF = cell.fCost;
|
|
current = cell;
|
|
}
|
|
}
|
|
open.Remove(current);
|
|
close.Add(current);
|
|
current.setClose(true);
|
|
|
|
if(current == targetCell){foundPath=true; continue;}
|
|
foreach(cellData neighbour in current.neighbours){
|
|
if(close.Contains(neighbour)){continue;}
|
|
bool hasThisNeighbour = open.Contains(neighbour);
|
|
if(neighbour.fCost < lowestF || !hasThisNeighbour){
|
|
calculateCellCost(neighbour);
|
|
if(neighbour.fCost < lowestF || neighbour.parent==null){ neighbour.parent = current;}
|
|
if(!hasThisNeighbour){open.Add(neighbour);}
|
|
}
|
|
}
|
|
yield return new WaitForSeconds(0.05f);
|
|
}
|
|
|
|
//sort
|
|
bool pathCleared = false;
|
|
cellData parentCell = targetCell;
|
|
while(!pathCleared){
|
|
|
|
if(parentCell == startCell){pathCleared=true; break;}
|
|
parentCell.GetComponent<SpriteRenderer>().color =Color.blue;
|
|
parentCell = parentCell.parent;
|
|
yield return new WaitForSeconds(0.1f);
|
|
}
|
|
}
|
|
|
|
bool calculateCellCost(cellData cell){
|
|
if((int)cell.fCost!=0){Debug.Log("already calculated, skipping");return false;}
|
|
float hCost = Vector2.Distance(cell.transform.position, targetCell.transform.position);
|
|
float gCost = Vector2.Distance(cell.transform.position, startCell.transform.position);
|
|
float fCost = hCost + gCost;
|
|
|
|
cell.setCellCost(gCost, hCost, fCost);
|
|
return true;
|
|
}
|
|
|
|
public void resetCellsCost(){
|
|
foreach(cellData cell in cells){
|
|
cell.resetCost();
|
|
}
|
|
}
|
|
}
|