import { MovingEntity } from '../core/MovingEntity.js';
import { SteeringManager } from './SteeringManager.js';
import { Vector3 } from '../math/Vector3.js';
import { Smoother } from './Smoother.js';
const steeringForce = new Vector3();
const displacement = new Vector3();
const acceleration = new Vector3();
const target = new Vector3();
const velocitySmooth = new Vector3();
/**
* This type of game entity implements a special type of locomotion, the so called
* *Vehicle Model*. The class uses basic physical metrics in order to implement a
* realistic movement.
*
* @author {@link https://github.com/Mugen87|Mugen87}
* @author {@link https://github.com/robp94|robp94}
* @augments MovingEntity
*/
class Vehicle extends MovingEntity {
/**
* Constructs a new vehicle.
*/
constructor() {
super();
/**
* The mass of the vehicle in kilogram.
* @type {Number}
* @default 1
*/
this.mass = 1;
/**
* The maximum force this entity can produce to power itself.
* @type {Number}
* @default 100
*/
this.maxForce = 100;
/**
* The steering manager of this vehicle.
* @type {SteeringManager}
*/
this.steering = new SteeringManager( this );
/**
* An optional smoother to avoid shakiness due to conflicting steering behaviors.
* @type {?Smoother}
* @default null
*/
this.smoother = null;
}
/**
* This method is responsible for updating the position based on the force produced
* by the internal steering manager.
*
* @param {Number} delta - The time delta.
* @return {Vehicle} A reference to this vehicle.
*/
update( delta ) {
// calculate steering force
this.steering.calculate( delta, steeringForce );
// acceleration = force / mass
acceleration.copy( steeringForce ).divideScalar( this.mass );
// update velocity
this.velocity.add( acceleration.multiplyScalar( delta ) );
// make sure vehicle does not exceed maximum speed
if ( this.getSpeedSquared() > ( this.maxSpeed * this.maxSpeed ) ) {
this.velocity.normalize();
this.velocity.multiplyScalar( this.maxSpeed );
}
// calculate displacement
displacement.copy( this.velocity ).multiplyScalar( delta );
// calculate target position
target.copy( this.position ).add( displacement );
// update the orientation if the vehicle has a non zero velocity
if ( this.updateOrientation === true && this.smoother === null && this.getSpeedSquared() > 0.00000001 ) {
this.lookAt( target );
}
// update position
this.position.copy( target );
// if smoothing is enabled, the orientation (not the position!) of the vehicle is
// changed based on a post-processed velocity vector
if ( this.updateOrientation === true && this.smoother !== null ) {
this.smoother.calculate( this.velocity, velocitySmooth );
displacement.copy( velocitySmooth ).multiplyScalar( delta );
target.copy( this.position ).add( displacement );
this.lookAt( target );
}
return this;
}
/**
* Transforms this instance into a JSON object.
*
* @return {Object} The JSON object.
*/
toJSON() {
const json = super.toJSON();
json.mass = this.mass;
json.maxForce = this.maxForce;
json.steering = this.steering.toJSON();
json.smoother = this.smoother ? this.smoother.toJSON() : null;
return json;
}
/**
* Restores this instance from the given JSON object.
*
* @param {Object} json - The JSON object.
* @return {Vehicle} A reference to this vehicle.
*/
fromJSON( json ) {
super.fromJSON( json );
this.mass = json.mass;
this.maxForce = json.maxForce;
this.steering = new SteeringManager( this ).fromJSON( json.steering );
this.smoother = json.smoother ? new Smoother().fromJSON( json.smoother ) : null;
return this;
}
/**
* Restores UUIDs with references to GameEntity objects.
*
* @param {Map<String,GameEntity>} entities - Maps game entities to UUIDs.
* @return {Vehicle} A reference to this vehicle.
*/
resolveReferences( entities ) {
super.resolveReferences( entities );
this.steering.resolveReferences( entities );
}
}
export { Vehicle };