예제 #1
0
        /// <summary>
        /// Called when a node is reached. Tests against targets and creates new nodes.
        /// </summary>
        /// <param name="pnSet">The active set.</param>
        /// <param name="currentNode">The node that was reached.</param>
        /// <param name="input">Param for CanTravelSegment, Offset and Direction should be correct.</param>
        /// <param name="proximity">Result from CanTravelSegment, how close the ship would come to an entity when traveling to this node from its parent.</param>
        private void ReachedNode(FindingSet pnSet, ref PathNode currentNode, ref PathTester.TestInput input, float proximity)
        {
            // impose a penalty for going near entities, this does not affect this node but will affect its children
            // this really helps prevent pathfinder getting stuck but the penalty might be too high
            float penalty = 10f * (100f - MathHelper.Clamp(proximity, 0f, 100f));

            Log.DebugLog(SetName(pnSet) + " Reached node: " + ReportRelativePosition(currentNode.Position) + " from " + ReportRelativePosition(pnSet.m_reachedNodes[currentNode.ParentKey].Position) +
                         ", reached: " + pnSet.m_reachedNodes.Count + ", open: " + pnSet.m_openNodes.Count + ", proximity: " + proximity + ", penalty: " + penalty);
            currentNode.DistToCur += penalty;
            long cNodePosHash = currentNode.Key;

            pnSet.m_reachedNodes.Add(cNodePosHash, currentNode);

            if (!m_canChangeCourse)
            {
                // test from current node position to destination
                Log.DebugLog(SetName(pnSet) + " Running backwards search", Logger.severity.ERROR, condition: pnSet != m_forward);
                Vector3D.Subtract(ref m_currentPosition, ref pnSet.m_referencePosition, out input.Offset);
                input.Length = (float)Vector3D.Distance(currentNode.Position, pnSet.m_referencePosition);
                if (CanTravelSegment(ref input, out proximity))
                {
                    Log.DebugLog(SetName(pnSet) + " Reached destination from node: " + ReportRelativePosition(currentNode.Position));
                    Log.DebugLog("Backwards start is not reference position", Logger.severity.ERROR, condition: m_backwardList[0].m_startPosition != pnSet.m_referencePosition);
                    BuildPath(cNodePosHash, m_backwardList[0], pnSet.m_referencePosition.GetHash());
                    return;
                }
#if SHOW_REACHED
                ShowPosition(currentNode, SetName(pnSet));
#endif
                return;
            }

            foreach (PathNodeSet target in pnSet.m_targets)
            {
                if (target.HasReached(cNodePosHash))
                {
                    Log.DebugLog(SetName(pnSet) + " Opposite set has same position");
                    if (pnSet == m_forward)
                    {
                        BuildPath(cNodePosHash, target, cNodePosHash);
                    }
                    else
                    {
                        BuildPath(cNodePosHash, pnSet, cNodePosHash);
                    }
                    return;
                }
            }

            Vector3D        obstructPosition = m_obstructingEntity.GetPosition();
            Vector3D        currentNodeWorld; Vector3D.Add(ref obstructPosition, ref currentNode.Position, out currentNodeWorld);
            BoundingSphereD sphere = new BoundingSphereD()
            {
                Center = currentNodeWorld, Radius = m_autopilotShipBoundingRadius + 100f
            };
            m_entitiesRepulse.Clear();             // use repulse list as prune/avoid is needed for CanTravelSegment
            MyGamePruningStructure.GetAllTopMostEntitiesInSphere(ref sphere, m_entitiesRepulse);
            if (m_entitiesRepulse.Count == 0 && BlueSkyReached(pnSet, currentNode, ref currentNodeWorld))
            {
                return;
            }

#if SHOW_REACHED
            ShowPosition(currentNode, SetName(pnSet));
#endif

            if (pnSet.NodeDistance < FindingSet.DefaultNodeDistance && pnSet.m_reachedNodes.Count % 10 == 0 && pnSet.m_openNodes.Count > 100)
            {
                Log.DebugLog("Reached: " + pnSet.m_reachedNodes.Count + ", trying with higher node distance");
                pnSet.ChangeNodeDistance(false, m_canChangeCourse);
                return;
            }

            pnSet.CreatePathNode(ref currentNode, m_canChangeCourse);
        }
예제 #2
0
        /// <summary>
        /// Continues pathfinding.
        /// </summary>
        /// <param name="pnSet">The active set.</param>
        private void ContinuePathfinding(FindingSet pnSet)
        {
            //PathNodeSet pnSet = isForwardSet ? m_forward : m_backward;

            Log.DebugLog(SetName(pnSet) + " m_obstructingEntity == null", Logger.severity.ERROR, condition: m_obstructingEntity.Entity == null);

            if (pnSet.m_openNodes.Count == 0)
            {
                OutOfNodes(pnSet);
                return;
            }

            PathNode currentNode = pnSet.m_openNodes.RemoveMin();

            if (currentNode.DistToCur == 0f)
            {
                Log.DebugLog(SetName(pnSet) + " first node: " + ReportRelativePosition(currentNode.Position));
                pnSet.CreatePathNode(ref currentNode, m_canChangeCourse);
                return;
            }

            if (pnSet.HasReached(currentNode.Position.GetHash()))
            {
                //Log.DebugLog("Already reached: " + ReportRelativePosition(currentNode.Position), secondaryState: SetName(direction));
                return;
            }

            FillEntitiesLists();
            Vector3 repulsion;

            CalcRepulsion(false, out repulsion);
            Log.DebugLog(SetName(pnSet) + " Calculated repulsion for some reason: " + repulsion, Logger.severity.WARNING, condition: repulsion != Vector3.Zero);

            PathNode parent;

            if (!pnSet.m_reachedNodes.TryGetValue(currentNode.ParentKey, out parent))
            {
                Log.DebugLog("Failed to get parent", Logger.severity.ERROR);
                return;
            }
            Vector3D worldParent;
            Vector3D obstructPosition = m_obstructingEntity.GetPosition();

            Vector3D.Add(ref obstructPosition, ref parent.Position, out worldParent);
            PathTester.TestInput input;
            Vector3D.Subtract(ref worldParent, ref m_currentPosition, out input.Offset);
            input.Direction = currentNode.DirectionFromParent;
            input.Length    = currentNode.DistToCur - parent.DistToCur;

            float proximity;

            if (!CanTravelSegment(ref input, out proximity))
            {
#if PROFILE
                pnSet.m_unreachableNodes++;
#endif
                //Log.DebugLog("Not reachable: " + ReportRelativePosition(currentNode.Position), secondaryState: SetName(pnSet));
                return;
            }
            ReachedNode(pnSet, ref currentNode, ref input, proximity);
        }