@awayjs/scene
Version:
AwayJS scene classes
242 lines (191 loc) • 6.15 kB
text/typescript
import { MathConsts } from '@awayjs/core';
import { ControllerBase } from '../controllers/ControllerBase';
import { DisplayObject } from '../display/DisplayObject';
/**
* Extended camera used to hover round a specified target object.
*
* @see away3d.containers.View3D
*/
export class FirstPersonController extends ControllerBase {
public _iCurrentPanAngle: number = 0;
public _iCurrentTiltAngle: number = 90;
private _panAngle: number = 0;
private _tiltAngle: number = 90;
private _minTiltAngle: number = -90;
private _maxTiltAngle: number = 90;
private _steps: number = 8;
private _walkIncrement: number = 0;
private _strafeIncrement: number = 0;
private _wrapPanAngle: boolean = false;
public fly: boolean = false;
/**
* Fractional step taken each time the <code>hover()</code> method is called. Defaults to 8.
*
* Affects the speed at which the <code>tiltAngle</code> and <code>panAngle</code> resolve to their targets.
*
* @see #tiltAngle
* @see #panAngle
*/
public get steps(): number {
return this._steps;
}
public set steps(val: number) {
val = (val < 1) ? 1 : val;
if (this._steps == val)
return;
this._steps = val;
this.pNotifyUpdate();
}
/**
* Rotation of the camera in degrees around the y axis. Defaults to 0.
*/
public get panAngle(): number {
return this._panAngle;
}
public set panAngle(val: number) {
if (this._panAngle == val)
return;
this._panAngle = val;
this.pNotifyUpdate();
}
/**
* Elevation angle of the camera in degrees. Defaults to 90.
*/
public get tiltAngle(): number {
return this._tiltAngle;
}
public set tiltAngle(val: number) {
val = Math.max(this._minTiltAngle, Math.min(this._maxTiltAngle, val));
if (this._tiltAngle == val)
return;
this._tiltAngle = val;
this.pNotifyUpdate();
}
/**
* Minimum bounds for the <code>tiltAngle</code>. Defaults to -90.
*
* @see #tiltAngle
*/
public get minTiltAngle(): number {
return this._minTiltAngle;
}
public set minTiltAngle(val: number) {
if (this._minTiltAngle == val)
return;
this._minTiltAngle = val;
this.tiltAngle = Math.max(this._minTiltAngle, Math.min(this._maxTiltAngle, this._tiltAngle));
}
/**
* Maximum bounds for the <code>tiltAngle</code>. Defaults to 90.
*
* @see #tiltAngle
*/
public get maxTiltAngle(): number {
return this._maxTiltAngle;
}
public set maxTiltAngle(val: number) {
if (this._maxTiltAngle == val)
return;
this._maxTiltAngle = val;
this.tiltAngle = Math.max(this._minTiltAngle, Math.min(this._maxTiltAngle, this._tiltAngle));
}
/**
* Defines whether the value of the pan angle wraps when over 360 degrees or under 0 degrees. Defaults to false.
*/
public get wrapPanAngle(): boolean {
return this._wrapPanAngle;
}
public set wrapPanAngle(val: boolean) {
if (this._wrapPanAngle == val)
return;
this._wrapPanAngle = val;
this.pNotifyUpdate();
}
/**
* Creates a new <code>HoverController</code> object.
*/
constructor(targetObject: DisplayObject = null, panAngle: number = 0,
tiltAngle: number = 90, minTiltAngle: number = -90, maxTiltAngle: number = 90,
steps: number = 8, wrapPanAngle: boolean = false) {
super(targetObject);
this.panAngle = panAngle;
this.tiltAngle = tiltAngle;
this.minTiltAngle = minTiltAngle;
this.maxTiltAngle = maxTiltAngle;
this.steps = steps;
this.wrapPanAngle = wrapPanAngle;
//values passed in contrustor are applied immediately
this._iCurrentPanAngle = this._panAngle;
this._iCurrentTiltAngle = this._tiltAngle;
}
/**
* Updates the current tilt angle and pan angle values.
*
* Values are calculated using the defined <code>tiltAngle</code>,
* <code>panAngle</code> and <code>steps</code> variables.
*
* @param interpolate If the update to a target pan- or tiltAngle is interpolated. Default is true.
*
* @see #tiltAngle
* @see #panAngle
* @see #steps
*/
public update(interpolate: boolean = true): void {
if (this._tiltAngle != this._iCurrentTiltAngle || this._panAngle != this._iCurrentPanAngle) {
this._pControllerDirty = true;
if (this._wrapPanAngle) {
if (this._panAngle < 0) {
this._iCurrentPanAngle += this._panAngle % 360 + 360 - this._panAngle;
this._panAngle = this._panAngle % 360 + 360;
} else {
this._iCurrentPanAngle += this._panAngle % 360 - this._panAngle;
this._panAngle = this._panAngle % 360;
}
while (this._panAngle - this._iCurrentPanAngle < -180)
this._iCurrentPanAngle -= 360;
while (this._panAngle - this._iCurrentPanAngle > 180)
this._iCurrentPanAngle += 360;
}
if (interpolate) {
this._iCurrentTiltAngle += (this._tiltAngle - this._iCurrentTiltAngle) / (this.steps + 1);
this._iCurrentPanAngle += (this._panAngle - this._iCurrentPanAngle) / (this.steps + 1);
} else {
this._iCurrentTiltAngle = this._tiltAngle;
this._iCurrentPanAngle = this._panAngle;
}
//snap coords if angle differences are close
if ((Math.abs(this.tiltAngle - this._iCurrentTiltAngle) < 0.01) &&
(Math.abs(this._panAngle - this._iCurrentPanAngle) < 0.01)) {
this._iCurrentTiltAngle = this._tiltAngle;
this._iCurrentPanAngle = this._panAngle;
}
}
this.targetObject.rotationX = this._iCurrentTiltAngle;
this.targetObject.rotationY = this._iCurrentPanAngle;
if (this._walkIncrement) {
if (this.fly) {
this.targetObject.transform.moveForward(this._walkIncrement);
} else {
this.targetObject.x += this._walkIncrement * Math.sin(this._panAngle * MathConsts.DEGREES_TO_RADIANS);
this.targetObject.z += this._walkIncrement * Math.cos(this._panAngle * MathConsts.DEGREES_TO_RADIANS);
}
this._walkIncrement = 0;
}
if (this._strafeIncrement) {
this.targetObject.transform.moveRight(this._strafeIncrement);
this._strafeIncrement = 0;
}
}
public incrementWalk(val: number): void {
if (val == 0)
return;
this._walkIncrement += val;
this.pNotifyUpdate();
}
public incrementStrafe(val: number): void {
if (val == 0)
return;
this._strafeIncrement += val;
this.pNotifyUpdate();
}
}