Permalink
Browse files

Added rudimentary Vector3Pathway

Mostly derived from the old AngryAntPathway, which will be updated
to descend from this class.  Currently disregarding the IsCyclic
property for testing purposes. It's likely that we'll just handle
that on the path follower.

TODO:
- Clean up Vector3Pathway
- Make AngryAntPathway subclass it
- Improve SteerToFollowPath. Currently it moves to the closest element
  on the path, without actually following others.  This means it's
  likely to take shortcuts we don't want.
  • Loading branch information...
1 parent a5a9834 commit f38ace45a28ad5e0a730712c9c9963693fa93ef2 @ricardojmendez committed Oct 30, 2010
Showing with 285 additions and 7 deletions.
  1. +9 −6 Behaviors/SteerToFollowPath.cs
  2. +14 −1 PathWay.cs
  3. +260 −0 Vector3Pathway.cs
  4. +2 −0 Vector3Pathway.cs.meta
@@ -67,7 +67,7 @@ public class SteerToFollowPath : Steering
/// </returns>
protected override Vector3 CalculateForce ()
{
- if (_path == null)
+ if (_path == null || _path.SegmentCount < 2)
return Vector3.zero;
// our goal will be offset from our path distance by this amount
@@ -87,24 +87,27 @@ protected override Vector3 CalculateForce ()
// XXX need to improve calling sequence, maybe change to return a
// XXX special path-defined object which includes two Vector3s and a
// XXX bool (onPath,tangent (ignored), withinPath)
- mapReturnStruct tStruct = new mapReturnStruct ();
+ var tStruct = new mapReturnStruct ();
_path.MapPointToPath (futurePosition, ref tStruct);
// no steering is required if (a) our future position is inside
// the path tube and (b) we are facing in the correct direction
- if ((tStruct.outside < 0) && rightway) {
+ if ((tStruct.outside < 0) && rightway)
+ {
// all is well, return zero steering
return Vector3.zero;
- } else {
+ } else
+ {
// otherwise we need to steer towards a target point obtained
// by adding pathDistanceOffset to our current path position
float targetPathDistance = nowPathDistance + pathDistanceOffset;
- Vector3 target = _path.MapPathDistanceToPoint (targetPathDistance);
+ var target = _path.MapPathDistanceToPoint (targetPathDistance);
// return steering to seek target on path
- return Vehicle.GetSeekVector(target);
+ var seek = Vehicle.GetSeekVector(target);
+ return seek;
}
}
}
View
@@ -45,7 +45,7 @@ public struct mapReturnStruct
public Vector3 tangent;
}
- public class Pathway
+ public abstract class Pathway
{
private bool _isCyclic;
@@ -86,6 +86,14 @@ public Vector3 LastPoint
return GetLastPoint();
}
}
+
+ public int SegmentCount
+ {
+ get
+ {
+ return GetSegmentCount();
+ }
+ }
// Returns the total path length. It's expected to be overriden by the
@@ -116,6 +124,11 @@ protected virtual Vector3 GetLastPoint()
{
return Vector3.zero;
}
+
+ protected virtual int GetSegmentCount()
+ {
+ return 0;
+ }
// Given an arbitrary point ("A"), returns the nearest point ("P") on
// this path. Also returns, via output arguments, the path tangent at
View
@@ -0,0 +1,260 @@
+// ----------------------------------------------------------------------------
+//
+// Written by Ricardo J. Mendez http://www.arges-systems.com/ based on
+// OpenSteer's PolylinePathway.
+//
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+//
+// ----------------------------------------------------------------------------
+using UnityEngine;
+using C5;
+
+namespace UnitySteer
+{
+ /// <summary>
+ /// Represents a Pathway created from a list of Vector3s
+ /// </summary>
+ public class Vector3Pathway : Pathway
+ {
+ private IList<Vector3> _path;
+ private float _totalPathLength;
+
+ private IList<float> _lengths;
+ private IList<Vector3> _normals;
+ private IList<Vector3> _points;
+
+ /// <summary>
+ /// Minimum radius along the path.
+ /// </summary>
+ private float _radius = 0.5f;
+
+
+ public IList<Vector3> Path {
+ get {
+ return _path;
+ }
+ }
+
+
+ public Vector3Pathway () {
+ _points = new ArrayList<Vector3>(10);
+ _lengths = new ArrayList<float>(10);
+ _normals = new ArrayList<Vector3>(10);
+ }
+
+
+ /// <summary>
+ /// Constructs a PolylinePathway given an array of points and a path radius
+ /// </summary>
+ /// <param name="path">
+ /// List of ConnectionAsset returned from Path <see cref="ConnectionAsset"/>
+ /// </param>
+ /// <param name="radius">
+ /// Radius to use for the connections <see cref="System.Single"/>
+ /// </param>
+ /// <param name="cyclic">
+ /// Is the path cyclic? <see cref="System.Boolean"/>
+ /// </param>
+ /// <remarks>The current implementation assumes that all pathways will
+ /// have the same radius. The connection radius could be taken from the
+ /// NetworkAssets in Path, which should be what we do in future implementations.
+ /// </remarks>
+ public Vector3Pathway (IList<Vector3> path, float radius, bool cyclic)
+ {
+ Initialize(path, radius, cyclic);
+ }
+
+ protected override Vector3 GetFirstPoint()
+ {
+ return _points.First;
+ }
+
+ protected override Vector3 GetLastPoint()
+ {
+ return _points.Last;
+ }
+
+ protected override float GetTotalPathLength()
+ {
+ return _totalPathLength;
+ }
+
+ protected override int GetSegmentCount()
+ {
+ return _points.Count;
+ }
+
+ /// <summary>
+ /// Constructs the Pathway from a list of ConnectionAssets
+ /// </summary>
+ /// <param name="path">
+ /// A list of ConnectionAssets as returned by Path <see cref="ConnectionAsset"/>
+ /// </param>
+ /// <param name="radius">
+ /// Radius to use for the connections<see cref="System.Single"/>
+ /// </param>
+ /// <param name="cyclic">
+ /// Is the path cyclic?
+ /// </param>
+ public void Initialize (IList<Vector3> path, float radius, bool cyclic)
+ {
+ this._path = path;
+ this._radius = radius;
+ // TODO: Disregard cyclic, acquire quick test
+ this.IsCyclic = false;
+
+ // set data members, allocate arrays
+ int pointCount = path.Count;
+ _totalPathLength = 0;
+ if (cyclic)
+ {
+ pointCount++;
+ }
+ _points = new ArrayList<Vector3>(pointCount);
+ _lengths = new ArrayList<float>(pointCount);
+ _normals = new ArrayList<Vector3>(pointCount);
+
+ // loop over all points
+ for (int i = 0; i < pointCount; i++)
+ {
+ AddPoint(path[i]);
+ }
+ }
+
+ public void AddPoint(Vector3 point)
+ {
+ if (_points.Count > 0)
+ {
+ // compute the segment length
+ var normal = point - _points.Last;
+ var length = normal.magnitude;
+ _lengths.Add(length);
+ _normals.Add(normal / length);
+ // keep running total of segment lengths
+ _totalPathLength += length;
+ }
+ else
+ {
+ _normals.Add(Vector3.zero);
+ _lengths.Add(0);
+ }
+ _points.Add(point);
+ }
+
+ public override Vector3 MapPointToPath(Vector3 point, ref mapReturnStruct tStruct)
+ {
+ float d;
+ float minDistance = float.MaxValue;
+ Vector3 onPath = Vector3.zero;
+
+ // loop over all segments, find the one nearest to the given point
+ for (int i = 1; i < _points.Count; i++)
+ {
+ float segmentLength = _lengths[i];
+ Vector3 segmentNormal = _normals[i];
+ Vector3 chosenPoint = Vector3.zero;
+ d = OpenSteerUtility.PointToSegmentDistance(point, _points[i-1], _points[i],
+ segmentNormal, segmentLength,
+ ref chosenPoint);
+ if (d < minDistance)
+ {
+ minDistance = d;
+ onPath = chosenPoint;
+ tStruct.tangent = segmentNormal;
+ }
+ }
+
+ // measure how far original point is outside the Pathway's "tube"
+ tStruct.outside = (onPath - point).magnitude - _radius;
+
+ // return point on path
+ return onPath;
+ }
+
+ public override float MapPointToPathDistance(Vector3 point)
+ {
+ if (_points.Count < 2)
+ return 0;
+
+
+ float d;
+ float minDistance = float.MaxValue;
+ float segmentLengthTotal = 0;
+ float pathDistance = 0;
+
+ for (int i = 1; i < _points.Count; i++)
+ {
+ float segmentProjection = 0;
+ float segmentLength = _lengths[i];
+ Vector3 segmentNormal = _normals[i];
+ d = OpenSteerUtility.PointToSegmentDistance(point, _points[i-1], _points[i],
+ segmentNormal, segmentLength,
+ ref segmentProjection);
+ if (d < minDistance)
+ {
+ minDistance = d;
+ pathDistance = segmentLengthTotal + segmentProjection;
+ }
+ segmentLengthTotal += segmentLength;
+ }
+
+ // return distance along path of onPath point
+ return pathDistance;
+ }
+
+ public override Vector3 MapPathDistanceToPoint(float pathDistance)
+ {
+ // clip or wrap given path distance according to cyclic flag
+ float remaining = pathDistance;
+ if (IsCyclic)
+ {
+ remaining = pathDistance - (_totalPathLength * Mathf.Floor(pathDistance / _totalPathLength));
+ }
+ else
+ {
+ if (pathDistance < 0)
+ return _points.First;
+ if (pathDistance >= _totalPathLength)
+ return _points.Last;
+ }
+
+ // step through segments, subtracting off segment lengths until
+ // locating the segment that contains the original pathDistance.
+ // Interpolate along that segment to find 3d point value to return.
+ Vector3 result = Vector3.zero;
+ for (int i = 1; i < _points.Count; i++)
+ {
+ float segmentLength = _lengths[i];
+ if (segmentLength < remaining)
+ {
+ remaining -= segmentLength;
+ }
+ else
+ {
+ float ratio = remaining / segmentLength;
+ result = Vector3.Lerp(_points[i - 1], _points[i], ratio);
+ break;
+ }
+ }
+ return result;
+ }
+ }
+}
@@ -0,0 +1,2 @@
+fileFormatVersion: 1
+guid: d0f3cc70acc524d6ea3d5bccab3165a1

0 comments on commit f38ace4

Please sign in to comment.