Ejemplo n.º 1
0
 /// <summary>
 /// Moves over an off-mesh connection.
 /// </summary>
 /// <remarks>
 /// <para>
 /// This method is minimally tested and documented.
 /// </para>
 /// </remarks>
 /// <param name="connectionRef">The connection polygon reference.</param>
 /// <param name="endpointRefs">Polygon endpoint references. [Length: 2]</param>
 /// <param name="startPosition">The start position.</param>
 /// <param name="endPosition">The end position.</param>
 /// <returns>True if the operation succeeded.</returns>
 public bool MoveOverConnection(uint connectionRef, uint[] endpointRefs
                                , Vector3 startPosition, Vector3 endPosition)
 {
     return(PathCorridorEx.dtpcMoveOverOffmeshConnection(mRoot
                                                         , connectionRef, endpointRefs, ref startPosition, ref endPosition, ref mPosition
                                                         , mQuery.root));
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Moves the position and target from their curent locations to the desired locations.
 /// </summary>
 /// <remarks>
 /// <para>
 /// Performs an aggregrate operation in the following order:
 /// </para>
 /// <ol>
 /// <li><see cref="MoveTarget"/></li>
 /// <li><see cref="MovePosition"/></li>
 /// </ol>
 /// <para>
 /// See the documentation of the related functions for details on behavior.
 /// </para>
 /// <para>
 /// This method is more efficient than calling the other methods individually.
 /// </para>
 /// </remarks>
 /// <param name="desiredPosition">The desired position.</param>
 /// <param name="desiredTarget">The desired target.</param>
 public void Move(Vector3 desiredPosition, Vector3 desiredTarget)
 {
     mCorners.cornerCount = PathCorridorEx.dtpcMove(mRoot
                                                    , ref desiredPosition, ref desiredTarget, ref mPosition, ref mTarget
                                                    , mCorners.verts, mCorners.flags, mCorners.polyRefs, mCorners.polyRefs.Length
                                                    , mQuery.root, mFilter.root);
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Finds the corners in the corridor from the position toward the target.
        /// (The straightened path.)
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method can be used to do corner searches that exceed the capacity of the
        /// corridor's normal corner buffers.
        /// </para>
        /// <para>
        /// This method performs essentially the same function as
        /// <see cref="NavmeshQuery.GetStraightPath"/>.
        /// </para>
        /// <para>
        /// Due to internal optimizations, the actual maximum number of corners returned
        /// will be <c>(buffer.MaxCorners - 1)</c>
        /// </para>
        /// <para>
        /// If the target is within range, it will be the last corner and have a polygon
        /// reference of zero.
        /// </para>
        /// <para>
        /// Behavior is undefined if the buffer structure is malformed. E.g. The flag and polygon
        /// buffers are different sizes.
        /// </para>
        /// </remarks>
        /// <param name="buffer">The buffer to load the results into. [Length: >= 2]</param>
        /// <returns>The number of corners returned in the buffers.</returns>
        public int FindCorners(CornerData buffer)
        {
            buffer.cornerCount = PathCorridorEx.dtpcFindCorners(mRoot
                                                                , buffer.verts, buffer.flags, buffer.polyRefs, buffer.polyRefs.Length
                                                                , mQuery.root, mFilter.root);

            return(buffer.cornerCount);
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Immediately frees all unmanaged resources allocated by the object.
 /// </summary>
 public void RequestDisposal()
 {
     if (!IsDisposed)
     {
         PathCorridorEx.dtpcFree(mRoot);
         mRoot = IntPtr.Zero;
     }
 }
Ejemplo n.º 5
0
 /// <summary>
 /// Loads a new path and target into the corridor.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The current position is expected to be within the first
 /// polygon in the path.  The target is expected to be in the last
 /// polygon.
 /// </para>
 /// </remarks>
 /// <param name="target">The target location within the last polygon of the path.</param>
 /// <param name="path">
 /// The path corridor. [(polyRef) * <paramref name="pathCount"/>]
 /// </param>
 /// <param name="pathCount">
 /// The number of polygons in the path.
 /// [Limits: 0 &lt;= value &lt;= <see cref="MaxPathSize"/>]
 /// </param>
 public void SetCorridor(Vector3 target
                         , uint[] path
                         , int pathCount)
 {
     mCorners.cornerCount = PathCorridorEx.dtpcSetCorridor(mRoot
                                                           , ref target, path, pathCount, ref mTarget
                                                           , mCorners.verts, mCorners.flags, mCorners.polyRefs, mCorners.polyRefs.Length
                                                           , mQuery.root, mFilter.root);
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Moves the target from its curent location to the desired location, adjusting the
        /// corridor as needed to reflect the change.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Behavior:
        /// </para>
        /// <ul>
        /// <li>The movement is constrained to the surface of the navigation mesh.</li>
        /// <li>The corridor is automatically adjusted (shorted or lengthened) and
        /// <see cref="Corners"/> updated in order to remain valid.</li>
        /// <li>The new position will be located in the adjusted corridor's last polygon.</li>
        /// </ul>
        /// <para>
        /// The expected use case: The desired target will be 'near' the corridor. What is
        /// considered 'near' depends on local polygon density, query search extents, etc.
        /// </para>
        /// <para>
        /// The resulting target will differ from the desired target if the desired target is
        /// not on the navigation mesh, or it can't be reached using a local search.
        /// </para>
        /// </remarks>
        /// <param name="desiredTarget">The desired target.</param>
        /// <returns>The result of the move.</returns>
        public NavmeshPoint MoveTarget(Vector3 desiredTarget)
        {
            mCorners.cornerCount = PathCorridorEx.dtpcMoveTargetPosition(mRoot
                                                                         , ref desiredTarget, ref mTarget
                                                                         , mCorners.verts, mCorners.flags, mCorners.polyRefs, mCorners.polyRefs.Length
                                                                         , mQuery.root, mFilter.root);

            return(mTarget);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Resets the corridor to the specified position.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method sets the position and target to the specified location, and reduces the
        /// corridor to the location's polygon. (Path size = 1)
        /// </para>
        /// <para>
        /// This method does not perform any validation of the input data.
        /// </para>
        /// </remarks>
        /// <param name="position">The position of the client.</param>
        public void Reset(NavmeshPoint position)
        {
            PathCorridorEx.dtpcReset(mRoot, position);

            mPosition = position;
            mTarget   = position;

            mCorners.cornerCount = 1;
            mCorners.verts[0]    = position.point;
            mCorners.flags[0]    = WaypointFlag.Start | WaypointFlag.End;
            mCorners.polyRefs[0] = position.polyRef;
        }
Ejemplo n.º 8
0
 /// <summary>
 /// Attempts to optimize the path using a local area search.
 /// (Partial replanning.)
 /// </summary>
 /// <remarks>
 /// <para>
 /// Improves pathfinding appearance in crowded areas and for complex meshes.
 /// </para>
 /// <para>
 /// The only time <paramref name="updateCorners"/> should be set to false is if a move or
 /// another optimization method is to be called next. Otherwise the corner data may
 /// become invalid.
 /// </para>
 /// <para>
 /// Inaccurate locomotion or dynamic obstacle avoidance can force the client position
 /// significantly outside the original corridor. Over time this can result in the
 /// formation of a non-optimal corridor.  This method will use a local area path search
 /// to try to re-optimize the corridor.
 /// </para>
 /// <para>
 /// The more inaccurate the client movement, the more beneficial this method becomes.
 /// Simply adjust the frequency of the call to match the needs to the client.
 /// </para>
 /// <para>
 /// This is a local optimization.  It usually doesn't effect the entire corridor
 /// through to the goal.  It should normally be called based on a time increment rather
 /// than movement events. I.e. Call once a second.
 /// </para>
 /// </remarks>
 /// <param name="updateCorners">True if the corners data should be refreshed.</param>
 public void OptimizePathTopology(bool updateCorners)
 {
     if (updateCorners)
     {
         mCorners.cornerCount = PathCorridorEx.dtpcOptimizePathTopologyExt(mRoot
                                                                           , mCorners.verts, mCorners.flags, mCorners.polyRefs, mCorners.polyRefs.Length
                                                                           , mQuery.root, mFilter.root);
     }
     else
     {
         PathCorridorEx.dtpcOptimizePathTopology(mRoot, mQuery.root, mFilter.root);
     }
 }
Ejemplo n.º 9
0
 /// <summary>
 /// Attempts to optimize the path if the specified point is visible from the current
 /// position.
 /// </summary>
 /// <remarks>
 /// <para>
 /// Improves pathfinding appearance when using meshes that contain non-border.
 /// vertices.  (E.g. Tiled meshes and meshes constructed using multiple areas.)
 /// </para>
 /// <para>
 /// The only time <paramref name="updateCorners"/> should be set to false is if a move
 /// or other optimization method is to be called next. Otherwise the corner data may
 /// become invalid.
 /// </para>
 /// <para>
 /// Inaccurate locomotion or dynamic obstacle avoidance can force the agent position
 /// significantly outside the original corridor. Over time this can result in the
 /// formation of a non-optimal corridor. A non-optimal corridor can also form near
 /// non-border vertices.  (I.e. At tile corners or area transitions.)
 /// </para>
 /// <para>
 /// This function uses an efficient local visibility search to try to optimize the corridor
 /// between the current position and <paramref name="next"/>.
 /// </para>
 /// <para>
 /// The corridor will change only if <paramref name="next"/> is visible from the
 /// current position and moving directly toward the point is better than following the
 /// existing path.
 /// </para>
 /// <para>
 /// The more inaccurate the client movement, the more beneficial this method becomes.
 /// Simply adjust the frequency of the call to match the needs to the client.
 /// </para>
 /// <para>
 /// This method is not suitable for long distance searches.
 /// </para>
 /// </remarks>
 /// <param name="next">The point to search toward.</param>
 /// <param name="optimizationRange">The maximum range to search. [Limit: > 0]</param>
 /// <param name="updateCorners">True if the corners data should be refreshed.</param>
 public void OptimizePathVisibility(Vector3 next, float optimizationRange
                                    , bool updateCorners)
 {
     if (updateCorners)
     {
         mCorners.cornerCount = PathCorridorEx.dtpcOptimizePathVisibilityExt(mRoot
                                                                             , ref next, optimizationRange
                                                                             , mCorners.verts, mCorners.flags, mCorners.polyRefs, mCorners.polyRefs.Length
                                                                             , mQuery.root, mFilter.root);
     }
     else
     {
         PathCorridorEx.dtpcOptimizePathVisibility(
             mRoot, ref next, optimizationRange, mQuery.root, mFilter.root);
     }
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <remarks>
        /// <para>
        /// <b>Important:</b> The <see cref="Reset"/> method must be called before the corridor
        /// can be used. (That is how the position is set.)
        /// </para>
        /// <para>
        /// Due to internal optimizations, the maximum number of detectable corners will be
        /// <c>(<paramref name="maxCorners"/> - 1)</c>.
        /// </para>
        /// <para>The query and filter parameters can be set to null.  This supports the ability
        /// to create pools of re-usable path corridor objects.  But it means that care needs to
        /// be taken not to use the corridor until query and filter objects have been set.
        /// See <see cref="ReleaseLocals"/> and <see cref="LoadLocals"/> for pool related utility
        /// functions.
        /// </para>
        /// </remarks>
        /// <param name="maxPathSize">
        /// The maximum path size that can be handled by the object. [Limit: >= 1]
        /// </param>
        /// <param name="maxCorners">
        /// The maximum number of corners the corner buffer can hold. [Limit: >= 2]
        /// </param>
        /// <param name="query">The query to be used by the corridor.</param>
        /// <param name="filter">The query filter to be used by the corridor.</param>
        public PathCorridor(int maxPathSize, int maxCorners
                            , NavmeshQuery query, NavmeshQueryFilter filter)
        {
            maxPathSize = Math.Max(1, maxPathSize);

            mRoot = PathCorridorEx.dtpcAlloc(maxPathSize);

            if (mRoot == IntPtr.Zero)
            {
                mMaxPathSize = 0;
                return;
            }

            mQuery       = query;
            mFilter      = filter;
            mMaxPathSize = maxPathSize;
            mCorners     = new CornerData(Math.Max(2, maxCorners));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Loads the corridor data into the provided <see cref="PathCorridorData"/> buffer.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Make sure the buffer is sized to hold the entire result.
        /// (See: <see cref="GetPathCount"/> and <see cref="MaxPathSize"/>.)
        /// </para>
        /// </remarks>
        /// <param name="buffer">
        /// The buffer to load the data into.
        /// [Length: Maximum Path Size >= <see cref="GetPathCount"/>]
        /// </param>
        /// <returns>False if the operation failed.</returns>
        public bool GetData(PathCorridorData buffer)
        {
            // Only performs a partial parameter validation.
            if (buffer == null || buffer.path == null || buffer.path.Length < 1)
            {
                return(false);
            }

            if (buffer.path.Length == PathCorridorData.MarshalBufferSize)
            {
                return(PathCorridorEx.dtpcGetData(mRoot, buffer));
            }

            buffer.pathCount = GetPath(buffer.path);
            buffer.position  = mPosition.point;
            buffer.target    = mTarget.point;

            return(true);
        }
Ejemplo n.º 12
0
 /// <summary>
 /// Checks the corridor path to see if its polygon references remain valid.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The path can be invalidated if there are structural changes to the underlying
 /// navigation mesh, or the state of a polygon within the path changes resulting in it
 /// being filtered out. (E.g. An exclusion or inclusion flag changes.)
 /// </para>
 /// </remarks>
 /// <param name="maxLookAhead">
 /// The number of polygons from the beginning of the corridor to search.
 /// </param>
 /// <returns>True if the seached portion of the path is still valid.</returns>
 public bool IsValid(int maxLookAhead)
 {
     return(PathCorridorEx.dtpcIsValid(mRoot, maxLookAhead, mQuery.root, mFilter.root));
 }
Ejemplo n.º 13
0
 /// <summary>
 /// The number of polygons in the corridor path.
 /// </summary>
 /// <returns>The number of polygons in the corridor path.
 /// </returns>
 public int GetPathCount()
 {
     return(PathCorridorEx.dtpcGetPathCount(mRoot));
 }
Ejemplo n.º 14
0
 /// <summary>
 /// Obtains a copy of the corridor path.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The buffer should be sized to hold the entire path.
 /// (See: <see cref="GetPathCount"/> and <see cref="MaxPathSize"/>.)
 /// </para>
 /// </remarks>
 /// <param name="buffer">The buffer to load with the result. [(polyRef) * pathCount]</param>
 /// <returns>The number of polygons in the path.</returns>
 public int GetPath(uint[] buffer)
 {
     return(PathCorridorEx.dtpcGetPath(mRoot, buffer, buffer.Length));
 }