Browse Source

FlyControls: Derive from `Controls`. (#29095)

Michael Herzog 1 year ago
parent
commit
184f21483e

+ 1 - 2
docs/examples/en/controls/Controls.html

@@ -102,12 +102,11 @@
 			Call this method if you no longer want use to the controls. It frees all internal resources and removes all event listeners.
 			Call this method if you no longer want use to the controls. It frees all internal resources and removes all event listeners.
 		</p>
 		</p>
 
 
-		<h3>[method:undefined update] ()</h3>
+		<h3>[method:undefined update] ( [param:Number delta] )</h3>
 		<p>
 		<p>
 			Controls should implement this method if they have to update their internal state per simulation step.
 			Controls should implement this method if they have to update their internal state per simulation step.
 		</p>
 		</p>
 
 
-
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 
 		<p>
 		<p>

+ 5 - 31
docs/examples/en/controls/FlyControls.html

@@ -7,6 +7,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	</head>
 	<body>
 	<body>
+		[page:Controls] &rarr;
 
 
 		<h1>[name]</h1>
 		<h1>[name]</h1>
 
 
@@ -54,35 +55,21 @@
 
 
 		<h2>Properties</h2>
 		<h2>Properties</h2>
 
 
+		<p>See the base [page:Controls] class for common properties.</p>
+
 		<h3>[property:Boolean autoForward]</h3>
 		<h3>[property:Boolean autoForward]</h3>
 		<p>
 		<p>
 			If set to `true`, the camera automatically moves forward (and does not stop) when initially translated. Default is `false`.
 			If set to `true`, the camera automatically moves forward (and does not stop) when initially translated. Default is `false`.
 		</p>
 		</p>
 
 
-		<h3>[property:HTMLDOMElement domElement]</h3>
-		<p>
-			The HTMLDOMElement used to listen for mouse / touch events. This must be passed in the constructor; changing it here will
-			not set up new event listeners.
-		</p>
-
 		<h3>[property:Boolean dragToLook]</h3>
 		<h3>[property:Boolean dragToLook]</h3>
 		<p>
 		<p>
 			If set to `true`, you can only look around by performing a drag interaction. Default is `false`.
 			If set to `true`, you can only look around by performing a drag interaction. Default is `false`.
 		</p>
 		</p>
 
 
-		<h3>[property:Boolean enabled]</h3>
-		<p>
-			When set to `false`, the controls will not respond to user input. Default is `true`.
-		</p>
-
 		<h3>[property:Number movementSpeed]</h3>
 		<h3>[property:Number movementSpeed]</h3>
 		<p>
 		<p>
-			The movement speed. Default is *1*.
-		</p>
-
-		<h3>[property:Camera object]</h3>
-		<p>
-			The camera to be controlled.
+			The movement speed. Default is `1`.
 		</p>
 		</p>
 
 
 		<h3>[property:Number rollSpeed]</h3>
 		<h3>[property:Number rollSpeed]</h3>
@@ -92,20 +79,7 @@
 
 
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
-		<h3>[method:undefined dispose] ()</h3>
-		<p>
-			Should be called if the controls is no longer required.
-		</p>
-
-		<h3>[method:undefined update] ( [param:Number delta] )</h3>
-		<p>
-			<p>
-				[page:Number delta]: Time delta value.
-			</p>
-			<p>
-				Updates the controls. Usually called in the animation loop.
-			</p>
-		</p>
+		<p>See the base [page:Controls] class for common methods.</p>
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 

+ 194 - 188
examples/jsm/controls/FlyControls.js

@@ -1,24 +1,19 @@
 import {
 import {
-	EventDispatcher,
 	Quaternion,
 	Quaternion,
 	Vector3
 	Vector3
 } from 'three';
 } from 'three';
+import { Controls } from './Controls.js';
 
 
 const _changeEvent = { type: 'change' };
 const _changeEvent = { type: 'change' };
 
 
-class FlyControls extends EventDispatcher {
+const _EPS = 0.000001;
+const _tmpQuaternion = new Quaternion();
 
 
-	constructor( object, domElement ) {
+class FlyControls extends Controls {
 
 
-		super();
+	constructor( object, domElement = null ) {
 
 
-		this.object = object;
-		this.domElement = domElement;
-
-		// API
-
-		// Set to false to disable this control
-		this.enabled = true;
+		super( object, domElement );
 
 
 		this.movementSpeed = 1.0;
 		this.movementSpeed = 1.0;
 		this.rollSpeed = 0.005;
 		this.rollSpeed = 0.005;
@@ -26,301 +21,312 @@ class FlyControls extends EventDispatcher {
 		this.dragToLook = false;
 		this.dragToLook = false;
 		this.autoForward = false;
 		this.autoForward = false;
 
 
-		// disable default target object behavior
-
 		// internals
 		// internals
 
 
-		const scope = this;
+		this._moveState = { up: 0, down: 0, left: 0, right: 0, forward: 0, back: 0, pitchUp: 0, pitchDown: 0, yawLeft: 0, yawRight: 0, rollLeft: 0, rollRight: 0 };
+		this._moveVector = new Vector3( 0, 0, 0 );
+		this._rotationVector = new Vector3( 0, 0, 0 );
+		this._lastQuaternion = new Quaternion();
+		this._lastPosition = new Vector3();
+		this._status = 0;
 
 
-		const EPS = 0.000001;
+		// event listeners
 
 
-		const lastQuaternion = new Quaternion();
-		const lastPosition = new Vector3();
+		this._onKeyDown = onKeyDown.bind( this );
+		this._onKeyUp = onKeyUp.bind( this );
+		this._onPointerMove = onPointerMove.bind( this );
+		this._onPointerDown = onPointerDown.bind( this );
+		this._onPointerUp = onPointerUp.bind( this );
+		this._onPointerCancel = onPointerCancel.bind( this );
+		this._onContextMenu = onContextMenu.bind( this );
 
 
-		this.tmpQuaternion = new Quaternion();
+		//
 
 
-		this.status = 0;
+		if ( domElement !== null ) {
 
 
-		this.moveState = { up: 0, down: 0, left: 0, right: 0, forward: 0, back: 0, pitchUp: 0, pitchDown: 0, yawLeft: 0, yawRight: 0, rollLeft: 0, rollRight: 0 };
-		this.moveVector = new Vector3( 0, 0, 0 );
-		this.rotationVector = new Vector3( 0, 0, 0 );
+			this.connect();
 
 
-		this.keydown = function ( event ) {
+		}
 
 
-			if ( event.altKey || this.enabled === false ) {
+	}
 
 
-				return;
+	connect() {
 
 
-			}
+		window.addEventListener( 'keydown', this._onKeyDown );
+		window.addEventListener( 'keyup', this._onKeyUp );
 
 
-			switch ( event.code ) {
+		this.domElement.addEventListener( 'pointermove', this._onPointerMove );
+		this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
+		this.domElement.addEventListener( 'pointerup', this._onPointerUp );
+		this.domElement.addEventListener( 'pointercancel', this._onPointerCancel );
+		this.domElement.addEventListener( 'contextmenu', this._onContextMenu );
 
 
-				case 'ShiftLeft':
-				case 'ShiftRight': this.movementSpeedMultiplier = .1; break;
+	}
 
 
-				case 'KeyW': this.moveState.forward = 1; break;
-				case 'KeyS': this.moveState.back = 1; break;
+	disconnect() {
 
 
-				case 'KeyA': this.moveState.left = 1; break;
-				case 'KeyD': this.moveState.right = 1; break;
+		window.removeEventListener( 'keydown', this._onKeyDown );
+		window.removeEventListener( 'keyup', this._onKeyUp );
 
 
-				case 'KeyR': this.moveState.up = 1; break;
-				case 'KeyF': this.moveState.down = 1; break;
+		this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
+		this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
+		this.domElement.removeEventListener( 'pointerup', this._onPointerUp );
+		this.domElement.removeEventListener( 'pointercancel', this._onPointerCancel );
+		this.domElement.removeEventListener( 'contextmenu', this._onContextMenu );
 
 
-				case 'ArrowUp': this.moveState.pitchUp = 1; break;
-				case 'ArrowDown': this.moveState.pitchDown = 1; break;
+	}
 
 
-				case 'ArrowLeft': this.moveState.yawLeft = 1; break;
-				case 'ArrowRight': this.moveState.yawRight = 1; break;
+	dispose() {
 
 
-				case 'KeyQ': this.moveState.rollLeft = 1; break;
-				case 'KeyE': this.moveState.rollRight = 1; break;
+		this.disconnect();
 
 
-			}
+	}
 
 
-			this.updateMovementVector();
-			this.updateRotationVector();
+	update( delta ) {
 
 
-		};
+		if ( this.enabled === false ) return;
 
 
-		this.keyup = function ( event ) {
+		const object = this.object;
 
 
-			if ( this.enabled === false ) return;
+		const moveMult = delta * this.movementSpeed;
+		const rotMult = delta * this.rollSpeed;
 
 
-			switch ( event.code ) {
+		object.translateX( this._moveVector.x * moveMult );
+		object.translateY( this._moveVector.y * moveMult );
+		object.translateZ( this._moveVector.z * moveMult );
 
 
-				case 'ShiftLeft':
-				case 'ShiftRight': this.movementSpeedMultiplier = 1; break;
+		_tmpQuaternion.set( this._rotationVector.x * rotMult, this._rotationVector.y * rotMult, this._rotationVector.z * rotMult, 1 ).normalize();
+		object.quaternion.multiply( _tmpQuaternion );
 
 
-				case 'KeyW': this.moveState.forward = 0; break;
-				case 'KeyS': this.moveState.back = 0; break;
+		if (
+			this._lastPosition.distanceToSquared( object.position ) > _EPS ||
+			8 * ( 1 - this._lastQuaternion.dot( object.quaternion ) ) > _EPS
+		) {
 
 
-				case 'KeyA': this.moveState.left = 0; break;
-				case 'KeyD': this.moveState.right = 0; break;
+			this.dispatchEvent( _changeEvent );
+			this._lastQuaternion.copy( object.quaternion );
+			this._lastPosition.copy( object.position );
 
 
-				case 'KeyR': this.moveState.up = 0; break;
-				case 'KeyF': this.moveState.down = 0; break;
+		}
 
 
-				case 'ArrowUp': this.moveState.pitchUp = 0; break;
-				case 'ArrowDown': this.moveState.pitchDown = 0; break;
+	}
 
 
-				case 'ArrowLeft': this.moveState.yawLeft = 0; break;
-				case 'ArrowRight': this.moveState.yawRight = 0; break;
+	// private
 
 
-				case 'KeyQ': this.moveState.rollLeft = 0; break;
-				case 'KeyE': this.moveState.rollRight = 0; break;
+	_updateMovementVector() {
 
 
-			}
+		const forward = ( this._moveState.forward || ( this.autoForward && ! this._moveState.back ) ) ? 1 : 0;
 
 
-			this.updateMovementVector();
-			this.updateRotationVector();
+		this._moveVector.x = ( - this._moveState.left + this._moveState.right );
+		this._moveVector.y = ( - this._moveState.down + this._moveState.up );
+		this._moveVector.z = ( - forward + this._moveState.back );
 
 
-		};
+		//console.log( 'move:', [ this._moveVector.x, this._moveVector.y, this._moveVector.z ] );
 
 
-		this.pointerdown = function ( event ) {
+	}
 
 
-			if ( this.enabled === false ) return;
+	_updateRotationVector() {
 
 
-			if ( this.dragToLook ) {
+		this._rotationVector.x = ( - this._moveState.pitchDown + this._moveState.pitchUp );
+		this._rotationVector.y = ( - this._moveState.yawRight + this._moveState.yawLeft );
+		this._rotationVector.z = ( - this._moveState.rollRight + this._moveState.rollLeft );
 
 
-				this.status ++;
+		//console.log( 'rotate:', [ this._rotationVector.x, this._rotationVector.y, this._rotationVector.z ] );
 
 
-			} else {
+	}
 
 
-				switch ( event.button ) {
+	_getContainerDimensions() {
 
 
-					case 0: this.moveState.forward = 1; break;
-					case 2: this.moveState.back = 1; break;
+		if ( this.domElement != document ) {
 
 
-				}
+			return {
+				size: [ this.domElement.offsetWidth, this.domElement.offsetHeight ],
+				offset: [ this.domElement.offsetLeft, this.domElement.offsetTop ]
+			};
 
 
-				this.updateMovementVector();
+		} else {
 
 
-			}
+			return {
+				size: [ window.innerWidth, window.innerHeight ],
+				offset: [ 0, 0 ]
+			};
 
 
-		};
+		}
 
 
-		this.pointermove = function ( event ) {
+	}
 
 
-			if ( this.enabled === false ) return;
+}
 
 
-			if ( ! this.dragToLook || this.status > 0 ) {
+function onKeyDown( event ) {
 
 
-				const container = this.getContainerDimensions();
-				const halfWidth = container.size[ 0 ] / 2;
-				const halfHeight = container.size[ 1 ] / 2;
+	if ( event.altKey || this.enabled === false ) {
 
 
-				this.moveState.yawLeft = - ( ( event.pageX - container.offset[ 0 ] ) - halfWidth ) / halfWidth;
-				this.moveState.pitchDown = ( ( event.pageY - container.offset[ 1 ] ) - halfHeight ) / halfHeight;
+		return;
 
 
-				this.updateRotationVector();
+	}
+
+	switch ( event.code ) {
 
 
-			}
+		case 'ShiftLeft':
+		case 'ShiftRight': this.movementSpeedMultiplier = .1; break;
 
 
-		};
+		case 'KeyW': this._moveState.forward = 1; break;
+		case 'KeyS': this._moveState.back = 1; break;
 
 
-		this.pointerup = function ( event ) {
+		case 'KeyA': this._moveState.left = 1; break;
+		case 'KeyD': this._moveState.right = 1; break;
 
 
-			if ( this.enabled === false ) return;
+		case 'KeyR': this._moveState.up = 1; break;
+		case 'KeyF': this._moveState.down = 1; break;
 
 
-			if ( this.dragToLook ) {
+		case 'ArrowUp': this._moveState.pitchUp = 1; break;
+		case 'ArrowDown': this._moveState.pitchDown = 1; break;
 
 
-				this.status --;
+		case 'ArrowLeft': this._moveState.yawLeft = 1; break;
+		case 'ArrowRight': this._moveState.yawRight = 1; break;
 
 
-				this.moveState.yawLeft = this.moveState.pitchDown = 0;
+		case 'KeyQ': this._moveState.rollLeft = 1; break;
+		case 'KeyE': this._moveState.rollRight = 1; break;
 
 
-			} else {
+	}
 
 
-				switch ( event.button ) {
+	this._updateMovementVector();
+	this._updateRotationVector();
 
 
-					case 0: this.moveState.forward = 0; break;
-					case 2: this.moveState.back = 0; break;
+}
 
 
-				}
+function onKeyUp( event ) {
 
 
-				this.updateMovementVector();
+	if ( this.enabled === false ) return;
 
 
-			}
+	switch ( event.code ) {
 
 
-			this.updateRotationVector();
+		case 'ShiftLeft':
+		case 'ShiftRight': this.movementSpeedMultiplier = 1; break;
 
 
-		};
+		case 'KeyW': this._moveState.forward = 0; break;
+		case 'KeyS': this._moveState.back = 0; break;
 
 
-		this.pointercancel = function () {
+		case 'KeyA': this._moveState.left = 0; break;
+		case 'KeyD': this._moveState.right = 0; break;
 
 
-			if ( this.enabled === false ) return;
+		case 'KeyR': this._moveState.up = 0; break;
+		case 'KeyF': this._moveState.down = 0; break;
 
 
-			if ( this.dragToLook ) {
+		case 'ArrowUp': this._moveState.pitchUp = 0; break;
+		case 'ArrowDown': this._moveState.pitchDown = 0; break;
 
 
-				this.status = 0;
+		case 'ArrowLeft': this._moveState.yawLeft = 0; break;
+		case 'ArrowRight': this._moveState.yawRight = 0; break;
 
 
-				this.moveState.yawLeft = this.moveState.pitchDown = 0;
+		case 'KeyQ': this._moveState.rollLeft = 0; break;
+		case 'KeyE': this._moveState.rollRight = 0; break;
 
 
-			} else {
+	}
 
 
-				this.moveState.forward = 0;
-				this.moveState.back = 0;
+	this._updateMovementVector();
+	this._updateRotationVector();
 
 
-				this.updateMovementVector();
+}
 
 
-			}
+function onPointerDown( event ) {
 
 
-			this.updateRotationVector();
+	if ( this.enabled === false ) return;
 
 
-		};
+	if ( this.dragToLook ) {
 
 
-		this.contextMenu = function ( event ) {
+		this._status ++;
 
 
-			if ( this.enabled === false ) return;
+	} else {
 
 
-			event.preventDefault();
+		switch ( event.button ) {
 
 
-		};
+			case 0: this._moveState.forward = 1; break;
+			case 2: this._moveState.back = 1; break;
 
 
-		this.update = function ( delta ) {
+		}
 
 
-			if ( this.enabled === false ) return;
+		this._updateMovementVector();
 
 
-			const moveMult = delta * scope.movementSpeed;
-			const rotMult = delta * scope.rollSpeed;
+	}
 
 
-			scope.object.translateX( scope.moveVector.x * moveMult );
-			scope.object.translateY( scope.moveVector.y * moveMult );
-			scope.object.translateZ( scope.moveVector.z * moveMult );
+}
 
 
-			scope.tmpQuaternion.set( scope.rotationVector.x * rotMult, scope.rotationVector.y * rotMult, scope.rotationVector.z * rotMult, 1 ).normalize();
-			scope.object.quaternion.multiply( scope.tmpQuaternion );
+function onPointerMove( event ) {
 
 
-			if (
-				lastPosition.distanceToSquared( scope.object.position ) > EPS ||
-				8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS
-			) {
+	if ( this.enabled === false ) return;
 
 
-				scope.dispatchEvent( _changeEvent );
-				lastQuaternion.copy( scope.object.quaternion );
-				lastPosition.copy( scope.object.position );
+	if ( ! this.dragToLook || this._status > 0 ) {
 
 
-			}
+		const container = this._getContainerDimensions();
+		const halfWidth = container.size[ 0 ] / 2;
+		const halfHeight = container.size[ 1 ] / 2;
 
 
-		};
+		this._moveState.yawLeft = - ( ( event.pageX - container.offset[ 0 ] ) - halfWidth ) / halfWidth;
+		this._moveState.pitchDown = ( ( event.pageY - container.offset[ 1 ] ) - halfHeight ) / halfHeight;
 
 
-		this.updateMovementVector = function () {
+		this._updateRotationVector();
 
 
-			const forward = ( this.moveState.forward || ( this.autoForward && ! this.moveState.back ) ) ? 1 : 0;
+	}
 
 
-			this.moveVector.x = ( - this.moveState.left + this.moveState.right );
-			this.moveVector.y = ( - this.moveState.down + this.moveState.up );
-			this.moveVector.z = ( - forward + this.moveState.back );
+}
 
 
-			//console.log( 'move:', [ this.moveVector.x, this.moveVector.y, this.moveVector.z ] );
+function onPointerUp( event ) {
 
 
-		};
+	if ( this.enabled === false ) return;
 
 
-		this.updateRotationVector = function () {
+	if ( this.dragToLook ) {
 
 
-			this.rotationVector.x = ( - this.moveState.pitchDown + this.moveState.pitchUp );
-			this.rotationVector.y = ( - this.moveState.yawRight + this.moveState.yawLeft );
-			this.rotationVector.z = ( - this.moveState.rollRight + this.moveState.rollLeft );
+		this._status --;
 
 
-			//console.log( 'rotate:', [ this.rotationVector.x, this.rotationVector.y, this.rotationVector.z ] );
+		this._moveState.yawLeft = this._moveState.pitchDown = 0;
 
 
-		};
+	} else {
 
 
-		this.getContainerDimensions = function () {
+		switch ( event.button ) {
 
 
-			if ( this.domElement != document ) {
+			case 0: this._moveState.forward = 0; break;
+			case 2: this._moveState.back = 0; break;
 
 
-				return {
-					size: [ this.domElement.offsetWidth, this.domElement.offsetHeight ],
-					offset: [ this.domElement.offsetLeft, this.domElement.offsetTop ]
-				};
+		}
 
 
-			} else {
+		this._updateMovementVector();
 
 
-				return {
-					size: [ window.innerWidth, window.innerHeight ],
-					offset: [ 0, 0 ]
-				};
+	}
 
 
-			}
+	this._updateRotationVector();
 
 
-		};
+}
 
 
-		this.dispose = function () {
+function onPointerCancel() {
 
 
-			this.domElement.removeEventListener( 'contextmenu', _contextmenu );
-			this.domElement.removeEventListener( 'pointerdown', _pointerdown );
-			this.domElement.removeEventListener( 'pointermove', _pointermove );
-			this.domElement.removeEventListener( 'pointerup', _pointerup );
-			this.domElement.removeEventListener( 'pointercancel', _pointercancel );
+	if ( this.enabled === false ) return;
 
 
-			window.removeEventListener( 'keydown', _keydown );
-			window.removeEventListener( 'keyup', _keyup );
+	if ( this.dragToLook ) {
 
 
-		};
+		this._status = 0;
 
 
-		const _contextmenu = this.contextMenu.bind( this );
-		const _pointermove = this.pointermove.bind( this );
-		const _pointerdown = this.pointerdown.bind( this );
-		const _pointerup = this.pointerup.bind( this );
-		const _pointercancel = this.pointercancel.bind( this );
-		const _keydown = this.keydown.bind( this );
-		const _keyup = this.keyup.bind( this );
+		this._moveState.yawLeft = this._moveState.pitchDown = 0;
 
 
-		this.domElement.addEventListener( 'contextmenu', _contextmenu );
-		this.domElement.addEventListener( 'pointerdown', _pointerdown );
-		this.domElement.addEventListener( 'pointermove', _pointermove );
-		this.domElement.addEventListener( 'pointerup', _pointerup );
-		this.domElement.addEventListener( 'pointercancel', _pointercancel );
+	} else {
 
 
-		window.addEventListener( 'keydown', _keydown );
-		window.addEventListener( 'keyup', _keyup );
+		this._moveState.forward = 0;
+		this._moveState.back = 0;
 
 
-		this.updateMovementVector();
-		this.updateRotationVector();
+		this._updateMovementVector();
 
 
 	}
 	}
 
 
+	this._updateRotationVector();
+
+}
+
+function onContextMenu( event ) {
+
+	if ( this.enabled === false ) return;
+
+	event.preventDefault();
+
 }
 }
 
 
 export { FlyControls };
 export { FlyControls };

粤ICP备19079148号