示例#1
0
        public void OnPickStart(Topology.Face pickedFace, int button)
        {
            if (_moving || pickedFace.isExternal)
            {
                return;
            }

            if (button == 0)
            {
                if (_selectedFace && _selectedFace != pickedFace)
                {
                    Deselect(_selectedFace);
                    _selectedFace = Topology.Face.none;
                }

                if (_faceUnits[pickedFace] != null)
                {
                    Select(pickedFace);
                    _selectedFace = pickedFace;
                }
            }
            else if (button == 1)
            {
                if (_selectedFace && _selectedFace != pickedFace && pickedFace.isInternal)
                {
                    _path = _pathFinder.FindPath(_selectedFace, pickedFace, CostHeuristic, Cost, _path);

                    if (_path.Count > 0)
                    {
                        StartCoroutine(MoveUnitAlongPath(_path));
                    }
                }
            }
        }
示例#2
0
 private void BlockPathFaces(IFaceEdgePath path)
 {
     foreach (var face in path.AsFacePath())
     {
         _faceBlockedStates[face] = true;
         _dynamicMesh.RebuildFace(face, _triangulationBlocked);
     }
 }
示例#3
0
        public void OnPickChange(Topology.Face oldFace, Topology.Face newFace)
        {
            if (_startFace)
            {
                ClearPreviousPickState();

                if (newFace == _startFace || newFace.isExternal || _faceBlockedStates[_startFace] == true || _faceBlockedStates[newFace] == true)
                {
                    _path = null;
                }
                else
                {
                    _path = _pathFinder.FindPath(_startFace, newFace, CostHeuristic, Cost, _path);
                }

                DrawCurrentPickState(newFace);
                _dynamicMesh.RebuildMesh(DynamicMesh.VertexAttributes.Normal | DynamicMesh.VertexAttributes.Color);
            }
        }
示例#4
0
        public void OnPickEnd(Topology.Face face, int button)
        {
            if (button == 0 && _startFace)
            {
                ClearPreviousPickState();

                if (face == _startFace)
                {
                    ClearBlockedFaces(_startFace);
                }
                else if (_path != null && _path.Count > 0)
                {
                    BlockPathFaces(_path);
                }

                _path      = null;
                _startFace = Topology.Face.none;
                _dynamicMesh.RebuildMesh(DynamicMesh.VertexAttributes.Normal | DynamicMesh.VertexAttributes.Color);
            }
        }
示例#5
0
        /// <summary>
        /// Finds the shortest or otherwise least costly path from the specified source face to
        /// the specified target face, using the A* algorithm and the supplied heuristic and cost
        /// delegates to measure costs between faces and over face edges.
        /// </summary>
        /// <param name="source">The source face from which the path should start.</param>
        /// <param name="target">The target face that the path should attempt to reach.</param>
        /// <param name="costHeuristic">Delegate for estimating the cost of the path from the specified source face to the specified target face.</param>
        /// <param name="cost">Delegate for determining the actual cost of the path along the specified face edge, from its near vertex to its far face.</param>
        /// <param name="path">An optional existing path created by an earlier call to one of the <seealso cref="O:MakeIt.Tile.PathFinder.FindPath"/> functions, which will be overwritten with the new path data.</param>
        /// <returns>A face edge path instance describing the path found from source to target, or an incomplete object if no path was found.</returns>
        /// <remarks><para>The optional <paramref name="path"/> parameter is useful for reducing allocation activity
        /// and pressure on the garbage collector.  Reusing an existing path object will not require an additional
        /// allocation to store the path as long as the new path fits inside the capacity already available in the
        /// existing path.</para></remarks>
        public IFaceEdgePath FindPath(Topology.Face source, Topology.Face target, FaceCostHeuristicDelegate costHeuristic, FaceCostDelegate cost, IFaceEdgePath path = null)
        {
            if (!source)
            {
                throw new ArgumentException("The source face must be a valid face.", "source");
            }
            if (!target)
            {
                throw new ArgumentException("The target face must be a valid face.", "target");
            }
            if (source.topology != target.topology)
            {
                throw new ArgumentException("The target face must belong to the same topology as the source face.", "target");
            }

            var concretePath = path as FaceEdgePath;

            if (concretePath == null)
            {
                if (path != null)
                {
                    throw new ArgumentException("The provided pre-allocated path was not an instance of the necessary underlying type recognized by this path finder.", "path");
                }
                concretePath = new FaceEdgePath();
            }

            var topology = source.topology;

            if (source == target)
            {
                return(concretePath.Rebuild(source, target));
            }

            if (_queue == null)
            {
                _queue     = new DelegateOrderedPriorityQueue <Node>(Node.AreOrdered, Mathf.CeilToInt(Mathf.Sqrt(source.topology.faces.Count)));
                _openSet   = new Dictionary <int, Node>();
                _closedSet = new Dictionary <int, Node>();
            }
            else
            {
                _queue.Clear();
                _openSet.Clear();
                _closedSet.Clear();
            }

            _queue.Push(new Node(0f, 0f, costHeuristic(source, target, 0), source.index, -1, -1, 0));
            _openSet.Add(source.index, _queue.front);

            while (_queue.Count > 0)
            {
                var node = _queue.front;
                _queue.Pop();

                if (node._elementIndex == target.index)
                {
                    return(concretePath.Rebuild(source, target, node, _closedSet));
                }

                _closedSet.Add(node._elementIndex, node);
                var face = new Topology.Face(topology, node._elementIndex);

                foreach (var edge in face.edges)
                {
                    if (_closedSet.ContainsKey(edge.face.index))
                    {
                        continue;
                    }

                    var g = node._g + cost(edge, node._length);

                    if (!float.IsPositiveInfinity(g))
                    {
                        Node neighborNode;
                        if (!_openSet.TryGetValue(edge.face.index, out neighborNode))
                        {
                            var h = costHeuristic(edge.face, target, node._length);
                            neighborNode = new Node(g + h, g, h, edge.face.index, edge.index, node._elementIndex, node._length + 1);
                            _queue.Push(neighborNode);
                            _openSet.Add(edge.face.index, neighborNode);
                        }
                        else if (g < neighborNode._g)
                        {
                            var h = costHeuristic(edge.face, target, node._length);
                            neighborNode = new Node(g + h, g, h, edge.face.index, edge.index, node._elementIndex, node._length + 1);
                            _openSet[edge.face.index] = neighborNode;
                            _queue.Reprioritize(neighborNode);
                        }
                    }
                }
            }

            return(concretePath.Rebuild(source, target));
        }
示例#6
0
 /// <summary>
 /// Finds the shortest or path from the specified source face to the specified target face,
 /// using the A* algorithm and the supplied face positions to measure spherical arc distance
 /// between faces and over face edges.
 /// </summary>
 /// <param name="source">The source face from which the path should start.</param>
 /// <param name="target">The target face that the path should attempt to reach.</param>
 /// <param name="surface">The surface describing the overall shape of the spherical manifold.</param>
 /// <param name="facePositions">The three dimensional positions of each face in the world.</param>
 /// <param name="path">An optional existing path created by an earlier call to one of the <seealso cref="O:MakeIt.Tile.PathFinder.FindPath"/> functions, which will be overwritten with the new path data.</param>
 /// <returns>A face edge path instance describing the path found from source to target, or an incomplete object if no path was found.</returns>
 /// <remarks><para>The optional <paramref name="path"/> parameter is useful for reducing allocation activity
 /// and pressure on the garbage collector.  Reusing an existing path object will not require an additional
 /// allocation to store the path as long as the new path fits inside the capacity already available in the
 /// existing path.</para></remarks>
 public IFaceEdgePath FindSphericalEuclideanPath(Topology.Face source, Topology.Face target, SphericalSurface surface, IFaceAttribute <Vector3> facePositions, IFaceEdgePath path = null)
 {
     return(FindPath(source, target,
                     (Topology.Face s, Topology.Face t, int pathLength) =>
     {
         var sourcePosition = facePositions[s];
         var targetPosition = facePositions[t];
         return Geometry.SphericalArcLength(sourcePosition, targetPosition, surface.radius);
     },
                     (Topology.FaceEdge edge, int pathLength) =>
     {
         if (edge.isOuterBoundary)
         {
             return float.PositiveInfinity;
         }
         var sourcePosition = facePositions[edge.nearFace];
         var targetPosition = facePositions[edge.farFace];
         return Geometry.SphericalArcLength(sourcePosition, targetPosition, surface.radius);
     },
                     path));
 }
示例#7
0
 /// <summary>
 /// Finds the shortest or path from the specified source face to the specified target face,
 /// using the A* algorithm and the supplied face positions to measure standard Euclidean
 /// distance between faces and over face edges.
 /// </summary>
 /// <param name="source">The source face from which the path should start.</param>
 /// <param name="target">The target face that the path should attempt to reach.</param>
 /// <param name="facePositions">The three dimensional positions of each face in the world.</param>
 /// <param name="path">An optional existing path created by an earlier call to one of the <seealso cref="O:MakeIt.Tile.PathFinder.FindPath"/> functions, which will be overwritten with the new path data.</param>
 /// <returns>A face edge path instance describing the path found from source to target, or an incomplete object if no path was found.</returns>
 /// <remarks><para>The optional <paramref name="path"/> parameter is useful for reducing allocation activity
 /// and pressure on the garbage collector.  Reusing an existing path object will not require an additional
 /// allocation to store the path as long as the new path fits inside the capacity already available in the
 /// existing path.</para></remarks>
 public IFaceEdgePath FindEuclideanPath(Topology.Face source, Topology.Face target, IFaceAttribute <Vector3> facePositions, IFaceEdgePath path = null)
 {
     return(FindPath(source, target,
                     (Topology.Face s, Topology.Face t, int pathLength) =>
     {
         return (facePositions[s] - facePositions[t]).magnitude;
     },
                     (Topology.FaceEdge edge, int pathLength) =>
     {
         if (edge.isOuterBoundary)
         {
             return float.PositiveInfinity;
         }
         return (facePositions[edge.nearFace] - facePositions[edge.farFace]).magnitude;
     },
                     path));
 }
示例#8
0
        private IEnumerator MoveUnitAlongPath(IFaceEdgePath path)
        {
            _moving = true;

            var edge     = path[0];
            var prevFace = edge.nearFace;
            var nextFace = edge.farFace;

            var unit = _faceUnits[prevFace];

            if (_selectedFace != prevFace)
            {
                if (_selectedFace)
                {
                    _dynamicMesh.RebuildFace(_selectedFace, _faceTriangulation);
                }
                _selectedFace = prevFace;
                _dynamicMesh.RebuildFace(_selectedFace, _selectedFaceTriangulation);
                _dynamicMesh.RebuildMesh(DynamicMesh.VertexAttributes.UV2);
            }

            var accumulatedTime = 0f;
            var pathIndex       = 0;

            var effectiveMovementDuration = movementDuration * Cost(edge, pathIndex);

            while (pathIndex < path.Count)
            {
                yield return(null);

                accumulatedTime += Time.deltaTime;

                var stepProgress = accumulatedTime / effectiveMovementDuration;

                bool rebuildMesh = false;

                do
                {
                    if (stepProgress >= 0.5f && _selectedFace == prevFace)
                    {
                        UpdateUnitFace(unit, prevFace, nextFace);
                        rebuildMesh = true;
                    }

                    if (accumulatedTime >= effectiveMovementDuration)
                    {
                        accumulatedTime -= effectiveMovementDuration;
                        ++pathIndex;

                        if (pathIndex == path.Count)
                        {
                            var endPosition = _facePositions[_selectedFace];
                            unit.position = endPosition + _surface.GetNormal(endPosition) * 0.15f;

                            _moving = false;
                            yield break;
                        }
                        else
                        {
                            edge     = path[pathIndex];
                            prevFace = edge.nearFace;
                            nextFace = edge.farFace;
                            effectiveMovementDuration = movementDuration * Cost(edge, pathIndex);
                            stepProgress = accumulatedTime / effectiveMovementDuration;
                        }
                    }
                } while ((stepProgress >= 0.5f && _selectedFace == prevFace) || (accumulatedTime >= effectiveMovementDuration));

                if (rebuildMesh)
                {
                    _dynamicMesh.RebuildMesh(DynamicMesh.VertexAttributes.UV2);
                }

                var position = Vector3.Slerp(_facePositions[prevFace], _facePositions[nextFace], (-2f * stepProgress + 3f) * stepProgress * stepProgress);
                unit.position = position + _surface.GetNormal(position) * 0.15f;
            }
        }