private static void SetOriginOpenListForCanonicalDijkstra(FastPriorityQueue <PathNode> openList, MapColliderInfo map, int2 origin, int2 dir) { int2 next = origin + dir; if (MapColliderUtils.UnReachable(map, next.x, next.y)) { return; } float cost = 1f; if (dir.x != 0 && dir.y != 0) { if (MapColliderUtils.UnReachable(map, origin + new int2(dir.x, 0)) && MapColliderUtils.UnReachable(map, origin + new int2(0, dir.y))) { return; } cost = 1.5f; } map.IntegrationField[next.x, next.y] = cost; openList.Enqueue(new PathNode(next, dir), cost); }
private void CreateBarrier(MapColliderInfo colliderMap, MapTerrainInfo terrainMap, int x, int y) { if (MapColliderUtils.UnReachable(colliderMap, x, y)) { return; } for (int y2 = -1 + y; y2 < (1 + y); y2++) { for (int x2 = -1 + x; x2 < (1 + x); x2++) { MapColliderUtils.AddCost(colliderMap, x2, y2, 3); } } MapColliderUtils.SetCostValue(colliderMap, x, y, 255); // Instantiate a barrier on (x, y) var barrierRenderer = EntityPrefabContainer.BarrierRenderer; var drawPos = barrierRenderer.GetComponent <Position2DComponent> ().Value.Offset; drawPos += new float2(x, y); var heading = barrierRenderer.GetComponent <Heading2DComponent> ().Value.Value; PostUpdateCommands.CreateEntity(EntityPrefabContainer.BarrierArchetype); PostUpdateCommands.SetComponent(new Position2D() { Value = new float2(x, y), Offset = drawPos - new float2(x, y) }); PostUpdateCommands.SetComponent(new Heading2D() { Value = heading }); PostUpdateCommands.SetComponent(new TransformMatrix { Value = MathUtils.GetTransformMatrix(drawPos, heading) }); PostUpdateCommands.SetComponent( barrierRenderer.GetComponent <BarrierComponent> ().Value ); PostUpdateCommands.SetSharedComponent( barrierRenderer.GetComponent <TerrainRendererComponent> ().Value ); var barrierColPos = new Vector3(x, 0, y); var barrierCol = Object.Instantiate(EntityPrefabContainer.BarrierColliderPrefab, barrierColPos, Quaternion.identity); terrainMap.Terrains[x, y] |= TerrainType.Barrier; MapTerrainUtils.AddCollider(terrainMap, barrierCol); }
/// <summary> /// If node is a jump point, return the new direction. Otherwise return int2(0,0) /// </summary> private static int2 IsJumpPoint(MapColliderInfo map, int2 child, int2 dir) { int2 parent = child - dir; int2 falseReval = new int2(0, 0); if (dir.x == 0 && dir.y != 0) { if (parent.x > 0) { if (MapColliderUtils.IsWall(map, parent.x - 1, parent.y) && !MapColliderUtils.IsWall(map, child.x - 1, child.y)) { return(new int2(-1, dir.y)); } } if (parent.x < (map.MapWidth - 1)) { if (MapColliderUtils.IsWall(map, parent.x + 1, parent.y) && !MapColliderUtils.IsWall(map, child.x + 1, child.y)) { return(new int2(1, dir.y)); } } } else if (dir.x != 0 && dir.y == 0) { if (parent.y > 0) { if (MapColliderUtils.IsWall(map, parent.x, parent.y - 1) && !MapColliderUtils.IsWall(map, child.x, child.y - 1)) { return(new int2(dir.x, -1)); } } if (parent.y < (map.MapHeight - 1)) { if (MapColliderUtils.IsWall(map, parent.x, parent.y + 1) && !MapColliderUtils.IsWall(map, child.x, child.y + 1)) { return(new int2(dir.x, 1)); } } } return(falseReval); }
/// <summary> /// Use the uniform cost field to generate the integration field. /// It is more efficient than <see cref = "GenerateDijkstraIntegratField" /> /// </summary> public static void GenerateCanonicalDijkstraIntegratField(MapColliderInfo map, int2 target) { if (MapColliderUtils.UnReachable(map, target.x, target.y)) { return; } float maxValue = float.MaxValue; int mapWidth = map.MapWidth; int mapHeight = map.MapHeight; float[, ] inteField = map.IntegrationField; IntegrateFlag[, ] inteInfos = map.IntegrateInfos; for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { inteField[x, y] = maxValue; inteInfos[x, y] &= ~IntegrateFlag.Visited; // Init all field visited flag to false } } FastPriorityQueue <PathNode> openList = new FastPriorityQueue <PathNode> (mapWidth * mapHeight / 10); // Origin inteField[target.x, target.y] = 0; inteInfos[target.x, target.y] |= IntegrateFlag.Visited; SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(1, 0)); SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(1, 1)); SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(0, 1)); SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(-1, 1)); SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(-1, 0)); SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(-1, -1)); SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(0, -1)); SetOriginOpenListForCanonicalDijkstra(openList, map, target, new int2(1, -1)); while (openList.Count > 0) { var bestNode = openList.Dequeue(); CanonicalOrdering(openList, map, bestNode.Node, bestNode.Dir, inteField[bestNode.Node.x, bestNode.Node.y]); } }
private static void MoveDiagonal(FastPriorityQueue <PathNode> openList, MapColliderInfo map, int2 start, int2 dir, float cost) { if (dir.x == 0 || dir.y == 0) { return; } while (!MapColliderUtils.UnReachable(map, start.x, start.y)) { IntegrateFlag integrateFlag = map.IntegrateInfos[start.x, start.y]; if (integrateFlag.HasFlag(IntegrateFlag.Visited)) { if (map.IntegrationField[start.x, start.y] > cost) { map.IntegrationField[start.x, start.y] = cost; } else { return; } } else { map.IntegrateInfos[start.x, start.y] |= IntegrateFlag.Visited; map.IntegrationField[start.x, start.y] = cost; } MoveCardinal(openList, map, start, new int2(dir.x, 0), cost); MoveCardinal(openList, map, start, new int2(0, dir.y), cost); if (!MapColliderUtils.UnReachable(map, start + new int2(dir.x, 0)) || !MapColliderUtils.UnReachable(map, start + new int2(0, dir.y))) { start += dir; cost += 1.5f; } else { return; } } }
private static void MoveCardinal(FastPriorityQueue <PathNode> openList, MapColliderInfo map, int2 start, int2 dir, float cost) { start += dir; cost += 1; while (!MapColliderUtils.UnReachable(map, start.x, start.y)) { IntegrateFlag integrateFlag = map.IntegrateInfos[start.x, start.y]; if (integrateFlag.HasFlag(IntegrateFlag.Visited)) { if (map.IntegrationField[start.x, start.y] > cost) { map.IntegrationField[start.x, start.y] = cost; } else { return; } } int2 newdir = IsJumpPoint(map, start, dir); if (newdir.x != 0 || newdir.y != 0) { if (integrateFlag.HasFlag(IntegrateFlag.Visited)) { map.IntegrateInfos[start.x, start.y] &= ~IntegrateFlag.Visited; } map.IntegrationField[start.x, start.y] = math.min(map.IntegrationField[start.x, start.y], cost); openList.Enqueue(new PathNode(start, newdir), cost); return; } else { map.IntegrateInfos[start.x, start.y] |= IntegrateFlag.Visited; map.IntegrationField[start.x, start.y] = cost; start += dir; cost += 1; } } }
public static void GenerateFlowField(MapColliderInfo map, int2 target) { float[] neighboers = new float[8]; bool[] blocks = new bool[8]; float[, ] inteField = map.IntegrationField; FlowFieldDir[, ] flowField = map.FlowField; float maxValue = float.MaxValue; for (int y = 0; y < (map.MapHeight); y++) { for (int x = 0; x < (map.MapWidth); x++) { if (MapColliderUtils.UnReachable(map, x, y)) { flowField[x, y] = FlowFieldDir.None; continue; } blocks[0] = MapColliderUtils.UnReachable(map, x - 1, y + 1); blocks[1] = MapColliderUtils.UnReachable(map, x, y + 1); blocks[2] = MapColliderUtils.UnReachable(map, x + 1, y + 1); blocks[3] = MapColliderUtils.UnReachable(map, x - 1, y); blocks[4] = MapColliderUtils.UnReachable(map, x + 1, y); blocks[5] = MapColliderUtils.UnReachable(map, x - 1, y - 1); blocks[6] = MapColliderUtils.UnReachable(map, x, y - 1); blocks[7] = MapColliderUtils.UnReachable(map, x + 1, y - 1); neighboers[0] = (blocks[0] || (blocks[3] && blocks[1])) ? maxValue : inteField[x - 1, y + 1]; neighboers[1] = (blocks[1]) ? maxValue : inteField[x, y + 1]; neighboers[2] = (blocks[2] || (blocks[1] && blocks[4])) ? maxValue : inteField[x + 1, y + 1]; neighboers[3] = (blocks[3]) ? maxValue : inteField[x - 1, y]; neighboers[4] = (blocks[4]) ? maxValue : inteField[x + 1, y]; neighboers[5] = (blocks[5] || (blocks[3] && blocks[6])) ? maxValue : inteField[x - 1, y - 1]; neighboers[6] = (blocks[6]) ? maxValue : inteField[x, y - 1]; neighboers[7] = (blocks[7] || (blocks[4] && blocks[6])) ? maxValue : inteField[x + 1, y - 1]; int minIdx = 0; for (int i = 1; i < 8; i++) { if (neighboers[i] < neighboers[minIdx]) { minIdx = i; } } switch (minIdx) { case 0: flowField[x, y] = FlowFieldDir.Deg135; break; case 1: flowField[x, y] = FlowFieldDir.Deg90; break; case 2: flowField[x, y] = FlowFieldDir.Deg45; break; case 3: flowField[x, y] = FlowFieldDir.Deg180; break; case 4: flowField[x, y] = FlowFieldDir.Deg0; break; case 5: flowField[x, y] = FlowFieldDir.Deg225; break; case 6: flowField[x, y] = FlowFieldDir.Deg270; break; case 7: flowField[x, y] = FlowFieldDir.Deg315; break; } } } flowField[target.x, target.y] = FlowFieldDir.None; }
public static void GenerateDijkstraIntegratField(MapColliderInfo map, int2 target) { float maxValue = float.MaxValue; int mapWidth = map.MapWidth; int mapHeigth = map.MapHeight; byte[, ] costField = map.CostField; float[, ] inteField = map.IntegrationField; for (int y = 0; y < mapHeigth; y++) { for (int x = 0; x < mapWidth; x++) { inteField[x, y] = maxValue; } } inteField[target.x, target.y] = 0; Queue <int2> openList = new Queue <int2> (mapWidth * mapHeigth / 10); openList.Enqueue(target); int2[] neighborIds = new int2[4]; while (openList.Count > 0) { int2 cur = openList.Dequeue(); float endCost = 0; int neighborLength = 0; if (cur.y > 0) { neighborIds[neighborLength++] = new int2(cur.x, cur.y - 1); } if (cur.y < (mapHeigth - 1)) { neighborIds[neighborLength++] = new int2(cur.x, cur.y + 1); } if (cur.x > 0) { neighborIds[neighborLength++] = new int2(cur.x - 1, cur.y); } if (cur.x < (mapWidth - 1)) { neighborIds[neighborLength++] = new int2(cur.x + 1, cur.y); } int2 neighborId; for (int i = 0; i < neighborLength; i++) { neighborId = neighborIds[i]; if (MapColliderUtils.UnReachable(map, neighborId.x, neighborId.y)) { continue; } endCost = inteField[cur.x, cur.y] + costField[neighborId.x, neighborId.y] + 1; if (endCost < inteField[neighborId.x, neighborId.y]) { if (!openList.Contains(neighborId)) { openList.Enqueue(neighborId); } inteField[neighborId.x, neighborId.y] = endCost; } } } }
protected override void OnUpdate() { if (_camera == null) { _camera = Camera.main; } Ray ray = _camera.ScreenPointToRay(Input.mousePosition); float t = -ray.origin.y / ray.direction.y; Vector3 pos = ray.GetPoint(t); int x = (int)pos.x; int y = (int)pos.z; var colliderMap = MapColliderInfo.GameMap; var terrainMap = MapTerrainInfo.GameMap; var pathController = GameObject.FindObjectOfType(typeof(SimplePathGenerator)) as SimplePathGenerator; if (!_InitBoundary) { colliderMap = MapColliderInfo.GameMap; terrainMap = MapTerrainInfo.GameMap; for (int i = 0; i < GameSetting.MAP_WIDTH; i++) { CreateBarrier(colliderMap, terrainMap, i, 0); } for (int i = 0; i < GameSetting.MAP_WIDTH; i++) { CreateBarrier(colliderMap, terrainMap, i, GameSetting.MAP_HEIGHT - 1); } for (int i = 0; i < GameSetting.MAP_HEIGHT; i++) { CreateBarrier(colliderMap, terrainMap, 0, i); } for (int i = 0; i < GameSetting.MAP_HEIGHT; i++) { CreateBarrier(colliderMap, terrainMap, GameSetting.MAP_WIDTH - 1, i); } _InitBoundary = true; } // Add block if (Input.GetMouseButton(0)) { CreateBarrier(colliderMap, terrainMap, x, y); pathController.Generate(); return; } // Remove block if (Input.GetMouseButton(1)) { if (terrainMap.Terrains[x, y].HasFlag(TerrainType.Barrier)) { for (int y2 = -1 + y; y2 < (1 + y); y2++) { for (int x2 = -1 + x; x2 < (1 + x); x2++) { MapColliderUtils.SubtracCost(colliderMap, x2, y2, 3); } } MapColliderUtils.SetCostValue(colliderMap, x, y, 0); for (int i = 0; i < _barries.Length; i++) { int2 floorPos = new int2(_barries.Positions[i].Value); if (floorPos.x == x && floorPos.y == y) { PostUpdateCommands.DestroyEntity(_barries.Entities[i]); } } MapTerrainUtils.RemoveColliders(terrainMap, new float2(pos.x, pos.z), true); } pathController.Generate(); return; } if (Input.GetMouseButtonDown(2)) { pathController.Target = new int2(x, y); pathController.Generate(); return; } // Make unit nav if (Input.GetKeyDown(KeyCode.N)) { for (int i = 0; i < _navUnits.Length; i++) { var oldMov = _navUnits.MoveData[i]; if (oldMov.IsMoving) { oldMov.StopMoving(); } else { oldMov.StartMoving(); } oldMov.Target = pathController.Target; EntityManager.SetComponentData(_navUnits.Entities[i], oldMov); } } }