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

205 lines
7.6 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class astar_vertex : MonoBehaviour
{
public Transform VertexGroup;
[SerializeField]
public List<Vertex> nodes;
Vertex startNode;
Vertex endNode;
public Transform startVisualizer;
public Transform endVisualizer;
public PathWalker walker;
public List<Vertex> finalPath;
void Start()
{
finalPath = new List<Vertex>();
nodes = new List<Vertex>();
foreach(Vertex vertex in VertexGroup.GetComponentsInChildren<Vertex>()){
NodeData nodeData = vertex.gameObject.AddComponent(typeof(NodeData)) as NodeData;
nodes.Add(vertex);
}
}
// Update is called once per frame
void Update()
{
if(startNode != null){Debug.DrawLine(startVisualizer.position, startNode.transform.position);}
if(endNode != null){Debug.DrawLine(endVisualizer.position, endNode.transform.position);}
if(Input.GetKeyDown(KeyCode.E)){
Vector2 startPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
startVisualizer.position = startPos;
//get closest and reachable node to this location
float minDist = Mathf.Infinity;
foreach(Vertex node in nodes){
if(Physics2D.Linecast(startPos, node.transform.position)){}else{
float distToNode = Vector2.Distance(node.transform.position, startPos);
if(distToNode < minDist){
minDist = distToNode;
startNode = node;
}
}
}
}else if(Input.GetKeyDown(KeyCode.F)){
Vector2 endPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
endVisualizer.position = endPos;
//get closest and reachable node to this location
float minDist = Mathf.Infinity;
foreach(Vertex node in nodes){
if(Physics2D.Linecast(endPos, node.transform.position)){}else{
float distToNode = Vector2.Distance(node.transform.position, endPos);
if(distToNode < minDist){
minDist = distToNode;
endNode = node;
}
}
}
}else if(Input.GetKeyDown(KeyCode.Return)){
//Start Calculation
StartCoroutine(Calculate());
}else if(Input.GetKeyDown(KeyCode.I)){
Recalculate();
}else if(Input.GetKeyDown(KeyCode.S)){
Recalculate();
walker.pathNodes = new List<Transform>();
walker.curIndex = 0;
walker.pathNodes.Add(startNode.transform);
for(int i = finalPath.Count-1; i >=0; i--){
walker.pathNodes.Add(finalPath[i].transform);
}
walker.pathNodes.Add(endVisualizer);
}
if(finalPath.Count > 1){
for(int i = 1; i < finalPath.Count; i++){
Debug.DrawLine(finalPath[i].transform.position, finalPath[i-1].transform.position, Color.green);
}
}
}
public void Recalculate(){
DateTime startTime = DateTime.Now;
foreach(Vertex node in nodes){
node.GetComponent<NodeData>().Reset();
}
List<Vertex> open = new List<Vertex>();
List<Vertex> close = new List<Vertex>();
open.Add(startNode);
bool foundPath = false;
while(!foundPath){
Vertex current = null;
float lowestF = Mathf.Infinity;
foreach(Vertex cell in open){
if(cell.GetComponent<NodeData>().fCost < lowestF){
lowestF = cell.GetComponent<NodeData>().fCost;
current = cell;
}
}
open.Remove(current);
close.Add(current);
if(current == endNode){foundPath=true; continue;}
foreach(Vertex neighbour in current.neighbours){
if(close.Contains(neighbour)){continue;}
bool hasThisNeighbour = open.Contains(neighbour);
if(neighbour.GetComponent<NodeData>().fCost < lowestF || !hasThisNeighbour){
calculateCellCost(neighbour.GetComponent<NodeData>());
if(neighbour.GetComponent<NodeData>().fCost < lowestF || neighbour.GetComponent<NodeData>().parent==null){ neighbour.GetComponent<NodeData>().parent = current;}
if(!hasThisNeighbour){open.Add(neighbour);}
}
}
// yield return new WaitForSeconds(0.05f);
}
//sort
bool pathCleared = false;
Vertex parentCell = endNode;
finalPath= new List<Vertex>();
while(!pathCleared){
if(parentCell == startNode){pathCleared=true; break;}
finalPath.Add(parentCell);
parentCell = parentCell.GetComponent<NodeData>().parent;
// yield return new WaitForSeconds(0.1f);
}
Debug.Log("Calculation finished in " + (DateTime.Now - startTime).TotalMilliseconds + "ms");
}
IEnumerator Calculate(){
DateTime startTime = DateTime.Now;
foreach(Vertex node in nodes){
node.GetComponent<NodeData>().Reset();
}
List<Vertex> open = new List<Vertex>();
List<Vertex> close = new List<Vertex>();
open.Add(startNode);
bool foundPath = false;
while(!foundPath){
Vertex current = null;
float lowestF = Mathf.Infinity;
foreach(Vertex cell in open){
if(cell.GetComponent<NodeData>().fCost < lowestF){
lowestF = cell.GetComponent<NodeData>().fCost;
current = cell;
}
}
open.Remove(current);
close.Add(current);
if(current == endNode){foundPath=true; continue;}
foreach(Vertex neighbour in current.neighbours){
if(close.Contains(neighbour)){continue;}
bool hasThisNeighbour = open.Contains(neighbour);
if(neighbour.GetComponent<NodeData>().fCost < lowestF || !hasThisNeighbour){
calculateCellCost(neighbour.GetComponent<NodeData>());
if(neighbour.GetComponent<NodeData>().fCost < lowestF || neighbour.GetComponent<NodeData>().parent==null){ neighbour.GetComponent<NodeData>().parent = current;}
if(!hasThisNeighbour){open.Add(neighbour);}
}
}
// yield return new WaitForSeconds(0.05f);
}
//sort
bool pathCleared = false;
Vertex parentCell = endNode;
finalPath= new List<Vertex>();
while(!pathCleared){
if(parentCell == startNode){pathCleared=true; break;}
finalPath.Add(parentCell);
parentCell = parentCell.GetComponent<NodeData>().parent;
yield return new WaitForSeconds(0.1f);
}
Debug.Log("Calculation finished in " + (DateTime.Now - startTime).Milliseconds + "ms");
}
bool calculateCellCost(NodeData cell){
if((int)cell.fCost!=0){return false;}
cell.hCost = Vector2.Distance(cell.transform.position, endNode.transform.position);
cell.gCost = Vector2.Distance(cell.transform.position, startNode.transform.position);
cell.fCost = cell.hCost + cell.gCost;
return true;
}
void OnValidate(){
if(VertexGroup !=null && VertexGroup.GetComponentInChildren<Vertex>()==null){VertexGroup = null; Debug.LogError("Please assigna a vertex group with vertecies as children");}
}
}