Astar_demo/Assets/astar.cs
2023-11-28 11:29:52 +05:30

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();
}
}
}