private void Start() { #if UNITY_IOS || UNITY_ANDROID mobileControls.SetActive(true); #endif fsm = GetComponent <FloodSoundManager>(); playerCar = player.GetComponent <PlayerCar>(); player.position = startObj.position; referenceGraph = new AdjacencyList <Vector3>(Vector3.zero); pathingGraph = new AdjacencyList <Vector3>(Vector3.zero); for (int i = 0; i < numBlocksHorizontal; i++) { for (int j = 0; j < numBlocksVertical; j++) { Vector3 pos = new Vector3(i * blockDist, 0, j * blockDist); foreach (Vector3 neighbor in GetNeighbors(pos)) { referenceGraph.AddEdge(pos, neighbor); pathingGraph.AddEdge(pos, neighbor); } } } //Remove edges until there is no path found List <KeyValuePair <Vector3, Vector3> > removedEdges = new List <KeyValuePair <Vector3, Vector3> >(); while (AStar(referenceGraph, startObj.position, endObj.position, out List <Vector3> pathIter)) { path = pathIter; Vector3 start = referenceGraph.GetRandomVertex(); List <Vector3> neighbors = referenceGraph.FindNeighbours(start); Vector3 neighbor = neighbors[Random.Range(0, neighbors.Count)]; referenceGraph.RemoveEdge(start, neighbor); removedEdges.Add(new KeyValuePair <Vector3, Vector3>(start, neighbor)); } //Add the last removed edge back in KeyValuePair <Vector3, Vector3> lastEdge = removedEdges.Last(); removedEdges.RemoveAt(removedEdges.Count - 1); referenceGraph.AddEdge(lastEdge.Key, lastEdge.Value); //face the player's car in the direction of the first waypoint float startDir = v3ToInt[(path[1] - path[0]).normalized]; player.eulerAngles = new Vector3(0f, startDir, 0f); List <Vector3> startNeighborsMids = referenceGraph.FindNeighbours(startObj.position).Select(i => (startObj.position + i) / 2).ToList(); //spawn in roadblock prefabs along 3/4s of blocked edges int endIdx = removedEdges.Count * 3 / 4; for (int i = 0; i < endIdx; i++) { KeyValuePair <Vector3, Vector3> edge = removedEdges[i]; GameObject toInstantiate = staticRoadBlockPrefabs[Random.Range(0, staticRoadBlockPrefabs.Count)]; Vector3 midpoint = (edge.Key + edge.Value) / 2; if (startNeighborsMids.Any(x => x == midpoint)) { continue; } Quaternion rot = Quaternion.Euler(0f, Mathf.Abs((edge.Key - edge.Value).x) > 0f ? 90f : 0f, 0f); Instantiate(toInstantiate, midpoint, rot, obstacles.transform); pathingGraph.RemoveEdge(edge.Key, edge.Value); } //spawn in obstacles along valid edges HashSet <Vector3> edgeSet = new HashSet <Vector3>(); //prevent items from spawning on edges surrounding player's spawn point startNeighborsMids.ForEach(i => edgeSet.Add(i)); foreach (Vector3 vertex in referenceGraph.GetAllEdges()) { foreach (Vector3 neighbor in referenceGraph.FindNeighbours(vertex)) { Vector3 mid = (vertex + neighbor) / 2; bool onX = Mathf.Abs((vertex - neighbor).x) > 0; if (!edgeSet.Contains(mid) && Random.Range(0, 2) > 0) { GameObject toInstantiate = roadObstaclePrefabs[Random.Range(0, roadObstaclePrefabs.Count)]; float randStreetOffsetLong = Random.Range(-blockDist / 2, blockDist / 2); float randStreetOffsetWide = Random.Range(-roadWidth / 4, roadWidth / 4); Vector3 boundedRandomPosInStreet = mid; boundedRandomPosInStreet += onX ? new Vector3(randStreetOffsetLong, 0f, randStreetOffsetWide) : new Vector3(randStreetOffsetWide, 0f, randStreetOffsetLong); Quaternion rot = Quaternion.Euler(0f, onX ? Random.Range(60, 120) : Random.Range(-30, 30), 0f); Instantiate(toInstantiate, boundedRandomPosInStreet, rot, obstacles.transform); } if (!edgeSet.Contains(mid) && Random.Range(0, 3) > 0) { GameObject toInstantiate = puddles[Random.Range(0, puddles.Count)]; float randStreetOffsetLong = Random.Range(-blockDist / 2, blockDist / 2); float randStreetOffsetWide = Random.Range(-roadWidth / 4, roadWidth / 4); Vector3 boundedRandomPosInStreet = mid; boundedRandomPosInStreet += onX ? new Vector3(randStreetOffsetLong, 0f, randStreetOffsetWide) : new Vector3(randStreetOffsetWide, 0f, randStreetOffsetLong); Quaternion rot = Quaternion.Euler(0f, Random.Range(0, 360), 0f); Instantiate(toInstantiate, boundedRandomPosInStreet, rot, obstacles.transform); } edgeSet.Add(mid); } } fullPathLength = path.Count; StartCoroutine(UpdatePathOnDelay(pathUpdateDelay)); StartCoroutine(EndGameCheckOnDelay(endGameCheckDelay, endObj.position, new Vector3(roadWidth, roadWidth, roadWidth) / 2f, playerLayer)); }
private static bool AStar(AdjacencyList <Vector3> graph, Vector3 start, Vector3 goal, out List <Vector3> path) { //make sure that the start and end points are valid points in the graph if (!graph.Contains(start) || !graph.Contains(goal)) { path = new List <Vector3>(); return(false); } bool success = false; Dictionary <Vector3, Vector3> from = new Dictionary <Vector3, Vector3>(); HashSet <Vector3> closed = new HashSet <Vector3>(); HashSet <Vector3> open = new HashSet <Vector3> { start }; Dictionary <Vector3, float> gScore = new Dictionary <Vector3, float>(); SimplePriorityQueue <Vector3, float> fScore = new SimplePriorityQueue <Vector3, float>(); gScore.Add(start, 0); fScore.Enqueue(start, Vector3.Distance(start, goal)); while (open.Count > 0) { Vector3 current = fScore.Dequeue(); if (current == goal) { success = true; break; } open.Remove(current); closed.Add(current); foreach (Vector3 neighbor in graph.FindNeighbours(current)) { if (closed.Contains(neighbor)) { continue; } float dist = gScore[current] + Vector3.Distance(current, neighbor); if (!open.Contains(neighbor)) { open.Add(neighbor); } else if (gScore.ContainsKey(neighbor) && dist >= gScore[neighbor]) { continue; } from[neighbor] = current; gScore[neighbor] = dist; fScore.Enqueue(neighbor, dist + Vector3.Distance(neighbor, goal)); } } path = FormPath(from, goal); return(success); }