예제 #1
0
        /// <summary>
        /// Tests if a line can be traveled from input.Offset to input.Offset + input.Direction * input.Length
        /// </summary>
        /// <param name="input">Param for PathTester</param>
        /// <param name="proximity">How close the ship would come to an obstruction.</param>
        /// <returns>True iff the segment can be traveled by the ship.</returns>
        private bool CanTravelSegment(ref PathTester.TestInput input, out float proximity)
        {
            Profiler.StartProfileBlock();

            Log.DebugLog(input.ToString());
            MyCubeBlock ignoreBlock = NavSet.Settings_Current.DestinationEntity as MyCubeBlock;

            proximity = float.MaxValue;

            if (m_checkVoxel)
            {
                //Log.DebugLog("raycasting voxels");
                PathTester.VoxelTestResult result;
                if (m_tester.RayCastIntersectsVoxel(ref input, out result))
                {
                    //Log.DebugLog("Obstructed by voxel " + hitVoxel + " at " + hitPosition, Logger.severity.DEBUG, condition: hitVoxel != m_obstructingEntity.Entity);
                    Profiler.EndProfileBlock();
                    return(false);
                }
                if (result.Proximity < proximity)
                {
                    proximity = result.Proximity;
                }
            }

            //Log.TraceLog("checking " + m_entitiesPruneAvoid.Count + " entites - voxels");

            if (m_entitiesPruneAvoid.Count != 0)
            {
                for (int i = m_entitiesPruneAvoid.Count - 1; i >= 0; i--)
                {
                    MyEntity entity = m_entitiesPruneAvoid[i];
                    if (entity is MyVoxelBase)
                    {
                        // already checked
                        continue;
                    }
                    //Log.DebugLog("checking: " + entity.nameWithId());
                    PathTester.GridTestResult result;
                    if (m_tester.ObstructedBy(entity, ignoreBlock, ref input, out result))
                    {
                        //Log.DebugLog("Obstructed by " + entity.nameWithId() + "." + obstructBlock, Logger.severity.DEBUG, condition: entity != m_obstructingEntity.Entity);
                        Profiler.EndProfileBlock();
                        return(false);
                    }
                    if (result.Proximity < proximity)
                    {
                        proximity = result.Proximity;
                    }
                }
            }

            //Log.DebugLog("No obstruction. Start: " + (m_currentPosition + offset) + ", finish: " + (m_currentPosition + offset + (line.To - line.From)));
            Profiler.EndProfileBlock();
            return(true);
        }
예제 #2
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);
        }