import { SteeringBehavior } from '../SteeringBehavior.js';
import { ArriveBehavior } from './ArriveBehavior.js';
import { Vector3 } from '../../math/Vector3.js';
const midPoint = new Vector3();
const translation = new Vector3();
const predictedPosition1 = new Vector3();
const predictedPosition2 = new Vector3();
/**
* This steering behavior produces a force that moves a vehicle to the midpoint
* of the imaginary line connecting two other agents.
*
* @author {@link https://github.com/Mugen87|Mugen87}
* @augments SteeringBehavior
*/
class InterposeBehavior extends SteeringBehavior {
/**
* Constructs a new interpose behavior.
*
* @param {MovingEntity} entity1 - The first agent.
* @param {MovingEntity} entity2 - The second agent.
* @param {Number} deceleration - The amount of deceleration.
*/
constructor( entity1 = null, entity2 = null, deceleration = 3 ) {
super();
/**
* The first agent.
* @type {?MovingEntity}
* @default null
*/
this.entity1 = entity1;
/**
* The second agent.
* @type {?MovingEntity}
* @default null
*/
this.entity2 = entity2;
/**
* The amount of deceleration.
* @type {Number}
* @default 3
*/
this.deceleration = deceleration;
// internal behaviors
this._arrive = new ArriveBehavior();
}
/**
* 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 entity1 = this.entity1;
const entity2 = this.entity2;
// first we need to figure out where the two entities are going to be
// in the future. This is approximated by determining the time
// taken to reach the mid way point at the current time at max speed
midPoint.addVectors( entity1.position, entity2.position ).multiplyScalar( 0.5 );
const time = vehicle.position.distanceTo( midPoint ) / vehicle.maxSpeed;
// now we have the time, we assume that entity 1 and entity 2 will
// continue on a straight trajectory and extrapolate to get their future positions
translation.copy( entity1.velocity ).multiplyScalar( time );
predictedPosition1.addVectors( entity1.position, translation );
translation.copy( entity2.velocity ).multiplyScalar( time );
predictedPosition2.addVectors( entity2.position, translation );
// calculate the mid point of these predicted positions
midPoint.addVectors( predictedPosition1, predictedPosition2 ).multiplyScalar( 0.5 );
// then steer to arrive at it
this._arrive.deceleration = this.deceleration;
this._arrive.target = midPoint;
this._arrive.calculate( vehicle, force );
return force;
}
/**
* Transforms this instance into a JSON object.
*
* @return {Object} The JSON object.
*/
toJSON() {
const json = super.toJSON();
json.entity1 = this.entity1 ? this.entity1.uuid : null;
json.entity2 = this.entity2 ? this.entity2.uuid : null;
json.deceleration = this.deceleration;
return json;
}
/**
* Restores this instance from the given JSON object.
*
* @param {Object} json - The JSON object.
* @return {InterposeBehavior} A reference to this behavior.
*/
fromJSON( json ) {
super.fromJSON( json );
this.entity1 = json.entity1;
this.entity2 = json.entity2;
this.deceleration = json.deceleration;
return this;
}
/**
* Restores UUIDs with references to GameEntity objects.
*
* @param {Map<String,GameEntity>} entities - Maps game entities to UUIDs.
* @return {InterposeBehavior} A reference to this behavior.
*/
resolveReferences( entities ) {
this.entity1 = entities.get( this.entity1 ) || null;
this.entity2 = entities.get( this.entity2 ) || null;
}
}
export { InterposeBehavior };