private static bool IsNavigableGridIndex(GridBitfield blockedTerrain, int2 coords) { return (coords.x >= 0 && coords.y >= 0 && coords.x < Grid.NumCells.x && coords.y < Grid.NumCells.y && !blockedTerrain[coords.x, coords.y]); }
//bool first = true; protected override unsafe void OnUpdate() { var entityManager = World.Active.GetOrCreateManager <EntityManager>(); for (int danglingEnemyIndex = 0; danglingEnemyIndex < m_DanglingEnemyData.Length; ++danglingEnemyIndex) { m_PathManager.RemovePath(m_DanglingEnemyData.EnemyStates[danglingEnemyIndex].PathId); PostUpdateCommands.RemoveComponent <EnemyState>(m_DanglingEnemyData.Entities[danglingEnemyIndex]); } s_Start = m_SpawnPointData.SpawnPoint[0].GridIndex; s_Goal = m_GoalPointData.GoalPoint[0].GridIndex; s_BlockedTerrainCardinal = new GridBitfield(); s_BlockedTerrainIntercardinal = new GridBitfield(); for (int turretIndex = 0; turretIndex < m_TurretData.Length; ++turretIndex) { int2 turretGridCoords = Grid.ConvertToGridIndex(m_TurretData.Positions[turretIndex].Value); s_BlockedTerrainCardinal[turretGridCoords] = true; s_BlockedTerrainIntercardinal[turretGridCoords] = true; if (turretGridCoords.x > 0) { s_BlockedTerrainIntercardinal[turretGridCoords.x - 1, turretGridCoords.y] = true; } if (turretGridCoords.x < Grid.NumCells.x - 1) { s_BlockedTerrainIntercardinal[turretGridCoords.x + 1, turretGridCoords.y] = true; } if (turretGridCoords.y > 0) { s_BlockedTerrainIntercardinal[turretGridCoords.x, turretGridCoords.y - 1] = true; } if (turretGridCoords.y < Grid.NumCells.y - 1) { s_BlockedTerrainIntercardinal[turretGridCoords.x, turretGridCoords.y + 1] = true; } } // clear out all previous paths to force path-recompute if the tower layour has changed if (m_PreviousBlockedTerrain != null && m_PreviousBlockedTerrain != s_BlockedTerrainCardinal) { m_PathManager.ForcePathRecompute(); } m_PreviousBlockedTerrain = s_BlockedTerrainCardinal; for (int trackedEnemyIndex = 0; trackedEnemyIndex < m_TrackedEnemyData.Length; ++trackedEnemyIndex) { float3 currentPos = m_TrackedEnemyData.Positions[trackedEnemyIndex].Value; int2 currentGridIndex = Grid.ConvertToGridIndex(currentPos); float3 target = HandleLiveEnemy(currentGridIndex, m_TrackedEnemyData.EnemyStates[trackedEnemyIndex]); if (currentPos.Equals(target)) { List <float3> path = m_PathManager.GetPath(m_TrackedEnemyData.EnemyStates[trackedEnemyIndex].PathId); path.RemoveAt(path.Count - 1); target = HandleLiveEnemy(currentGridIndex, m_TrackedEnemyData.EnemyStates[trackedEnemyIndex]); } float3 delta = Time.deltaTime * m_TrackedEnemyData.Enemies[trackedEnemyIndex].Speed * math.normalize(target - currentPos); while (WouldDeltaJumpTarget(currentPos, delta, target)) { float3 toTarget = target - currentPos; float magDelta = math.length(delta); float normalizedTimeUsed = math.length(toTarget) / magDelta; float distanceLeft = (1.0f - normalizedTimeUsed) * magDelta; List <float3> path = m_PathManager.GetPath(m_TrackedEnemyData.EnemyStates[trackedEnemyIndex].PathId); path.RemoveAt(path.Count - 1); if (path.Count == 0) { if (m_PlayerData.Player[0].gameState.Equals(GameState.PLAYING)) { for (int i = 0; i < m_PlayerData.Player.Length; i++) { var playerData = m_PlayerData.Player[i]; playerData.Health--; m_PlayerData.Player[i] = playerData; } } PostUpdateCommands.DestroyEntity(m_TrackedEnemyData.Entities[trackedEnemyIndex]); return; } currentPos = target; target = path[path.Count - 1]; delta = distanceLeft * math.normalize(target - currentPos); } m_TrackedEnemyData.Positions[trackedEnemyIndex] = new Position { Value = currentPos + delta }; } for (int newEnemyIndex = 0; newEnemyIndex < m_NewEnemyData.Length; ++newEnemyIndex) { EnemyState enemyState = new EnemyState { PathId = m_PathManager.AddPath() }; PostUpdateCommands.AddComponent(m_NewEnemyData.Entities[newEnemyIndex], enemyState); } }
private static bool TryFindPath(int2 currentGridIndex, out Dictionary <int2, int2> cameFrom, int2?blocker) { GridBitfield closedSet = new GridBitfield(); // TODO: clean up the terrible perf incurred from just using an array here List <int2> openSet = new List <int2>(); openSet.Add(currentGridIndex); cameFrom = new Dictionary <int2, int2>(); // nodes have a default value of infinity Dictionary <int2, float> gScore = new Dictionary <int2, float>(); gScore[currentGridIndex] = 0.0f; // nodes have a default value of infinity Dictionary <int2, float> fScore = new Dictionary <int2, float>(); fScore[currentGridIndex] = CalcHeurisitic(currentGridIndex, s_Goal); while (openSet.Count > 0) { int bestIndex = 0; for (int b = 1; b < openSet.Count; ++b) { if (CmpNodes(fScore, openSet[bestIndex], openSet[b]) > 0) { bestIndex = b; } } int2 currentNode = openSet[bestIndex]; if (s_Goal.Equals(currentNode)) { return(true); } openSet.RemoveAt(bestIndex); closedSet[currentNode] = true; int2[] neighbors = new int2[8]; int numNeighbors = 0; int blockedCardinalFlags = 0; for (int neighborIndex = 0; neighborIndex < s_NeighborOffsetsCardinal.Length; ++neighborIndex) { int2 neighbor = currentNode + s_NeighborOffsetsCardinal[neighborIndex]; if (!IsNavigableGridIndex(s_BlockedTerrainCardinal, neighbor) || blocker != null && neighbor.Equals(blocker)) { blockedCardinalFlags |= 1 << neighborIndex; continue; } neighbors[numNeighbors] = neighbor; ++numNeighbors; } for (int neighborIndex = 0; neighborIndex < s_NeighborOffsetsIntercardinal.Length; ++neighborIndex) { int adjacentCardinalFlags = (1 << neighborIndex) | (1 << ((neighborIndex + 1) % 4)); if (adjacentCardinalFlags == (adjacentCardinalFlags & blockedCardinalFlags)) { continue; } int2 neighbor = currentNode + s_NeighborOffsetsIntercardinal[neighborIndex]; if (!IsNavigableGridIndex(s_BlockedTerrainIntercardinal, neighbor)) { continue; } neighbors[numNeighbors] = neighbor; ++numNeighbors; } for (int neighborIndex = 0; neighborIndex < numNeighbors; ++neighborIndex) { if (closedSet[neighbors[neighborIndex]]) { continue; } // why doesn't Contains do what it's supposed to...? bool exists = false; foreach (int2 iv in openSet) { if (neighbors[neighborIndex].Equals(iv)) { exists = true; break; } } if (!exists) { openSet.Add(neighbors[neighborIndex]); } float tentativeScoreFromStart = gScore[currentNode] + math.length(currentNode - neighbors[neighborIndex]); float scoreFromStartToNeighbor = float.MaxValue; if (gScore.ContainsKey(neighbors[neighborIndex])) { scoreFromStartToNeighbor = gScore[neighbors[neighborIndex]]; } if (tentativeScoreFromStart >= scoreFromStartToNeighbor) { continue; } cameFrom[neighbors[neighborIndex]] = currentNode; gScore[neighbors[neighborIndex]] = tentativeScoreFromStart; fScore[neighbors[neighborIndex]] = tentativeScoreFromStart + CalcHeurisitic(neighbors[neighborIndex], s_Goal); } } return(false); }