import { SteeringBehavior } from '../SteeringBehavior.js';
import { Path } from '../Path.js';
import { SeekBehavior } from './SeekBehavior.js';
import { ArriveBehavior } from './ArriveBehavior.js';
/**
* This steering behavior produces a force that moves a vehicle along a series of waypoints forming a path.
*
* @author {@link https://github.com/Mugen87|Mugen87}
* @augments SteeringBehavior
*/
class FollowPathBehavior extends SteeringBehavior {
/**
* Constructs a new follow path behavior.
*
* @param {Path} path - The path to follow.
* @param {Number} nextWaypointDistance - The distance the agent seeks for the next waypoint.
*/
constructor( path = new Path(), nextWaypointDistance = 1 ) {
super();
/**
* The path to follow.
* @type {Path}
*/
this.path = path;
/**
* The distance the agent seeks for the next waypoint.
* @type {Number}
* @default 1
*/
this.nextWaypointDistance = nextWaypointDistance;
// internal behaviors
this._arrive = new ArriveBehavior();
this._seek = new SeekBehavior();
}
/**
* Calculates the steering force for a single simulation step.
*
* @param {Vehicle} vehicle - The game entity the force is produced for.
* @param {Vector3} force - The force/result vector.
* @param {Number} delta - The time delta.
* @return {Vector3} The force/result vector.
*/
calculate( vehicle, force /*, delta */ ) {
const path = this.path;
// calculate distance in square space from current waypoint to vehicle
const distanceSq = path.current().squaredDistanceTo( vehicle.position );
// move to next waypoint if close enough to current target
if ( distanceSq < ( this.nextWaypointDistance * this.nextWaypointDistance ) ) {
path.advance();
}
const target = path.current();
if ( path.finished() === true ) {
this._arrive.target = target;
this._arrive.calculate( vehicle, force );
} else {
this._seek.target = target;
this._seek.calculate( vehicle, force );
}
return force;
}
/**
* Transforms this instance into a JSON object.
*
* @return {Object} The JSON object.
*/
toJSON() {
const json = super.toJSON();
json.path = this.path.toJSON();
json.nextWaypointDistance = this.nextWaypointDistance;
return json;
}
/**
* Restores this instance from the given JSON object.
*
* @param {Object} json - The JSON object.
* @return {FollowPathBehavior} A reference to this behavior.
*/
fromJSON( json ) {
super.fromJSON( json );
this.path.fromJSON( json.path );
this.nextWaypointDistance = json.nextWaypointDistance;
return this;
}
}
export { FollowPathBehavior };