/// <summary> /// Instructs a Vehicle Entity to follow a defined path (pathway), within the defined predicted timeframe /// </summary> /// <param name="vehicle"></param> /// <param name="direction"></param> /// <param name="predictionTime"></param> /// <param name="path"></param> /// <returns>The Vector to move to</returns> public static Vector3 FollowPath(VehicleActor vehicle, int direction, float predictionTime, Pathway path) { // our goal will be offset from our path distance by this amount float pathDistanceOffset = direction * predictionTime * vehicle.Velocity; // predict our future position Vector3 futurePosition = vehicle.PredictFuturePosition(predictionTime); // measure distance along path of our current and predicted positions float nowPathDistance = path.MapPointToPathDistance(vehicle.Position); float futurePathDistance = path.MapPointToPathDistance(futurePosition); // are we facing in the correction direction? bool rightway = ((pathDistanceOffset > 0) ? (nowPathDistance < futurePathDistance) : (nowPathDistance > futurePathDistance)); // find the point on the path nearest the predicted future position // 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) Vector3 tangent; float outside; Vector3 onPath = path.MapPointToPath(futurePosition, out tangent, out outside); // no steering is required if (a) our future position is inside // the path tube and (b) we are facing in the correct direction if ((outside < 0) && rightway) { // all is well, return zero steering return(Vector3.Zero); } 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); //log PathFollowing(futurePosition, onPath, target, outside); // return steering to seek target on path return(Seek(vehicle, target)); } }
/// <summary> /// Should the force be calculated? /// </summary> /// <returns> /// A <see cref="Vector3"/> /// </returns> protected override Vector3 CalculateForce() { if (_path == null || _path.SegmentCount < 2) { return(Vector3.zero); } // our goal will be offset from our path distance by this amount float pathDistanceOffset = (int)_direction * _predictionTime * Vehicle.Speed; // predict our future position Vector3 futurePosition = Vehicle.PredictFuturePosition(_predictionTime); // measure distance along path of our current and predicted positions float nowPathDistance = _path.MapPointToPathDistance(Vehicle.Position); float futurePathDistance = _path.MapPointToPathDistance(futurePosition); // are we facing in the correction direction? bool rightway = ((pathDistanceOffset > 0) ? (nowPathDistance < futurePathDistance) : (nowPathDistance > futurePathDistance)); // find the point on the path nearest the predicted future position var tStruct = new PathRelativePosition(); _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) { // TODO Evaluate. This assumes the vehicle has inertia, and would stop if inside the path tube return(Vector3.zero); } else { /* * Otherwise we need to steer towards a target point obtained * by adding pathDistanceOffset to our current path position. * * Notice that this method does not steer for the point in the * path that is closest to our future position, which is why * the return value of MapPointToPath is ignored above. Instead, * it estimates how far the vehicle will move in units, and then * aim for the point in the path that is that many units away * from our current path position _in path length_. This means * that it adds up the segment lengths and aims for the point * that is N units along the length of the path, which can imply * bends and turns and is not a straight vector projected away * from our position. * * This also means that having too high a prediction time will * have the effect of the agent seemingly approaching the path * in an elliptical manner. */ float targetPathDistance = nowPathDistance + pathDistanceOffset; var target = _path.MapPathDistanceToPoint(targetPathDistance); // return steering to seek target on path var seek = Vehicle.GetSeekVector(target); return(seek); } }