sebavan před 6 roky
rodič
revize
cbf093e91a

+ 1 - 0
dist/preview release/what's new.md

@@ -87,6 +87,7 @@
 - Invert vScale of compressed ktx textures as they are inverted in the file and UNPACK_FLIP_Y_WEBGL is not supported by ktx ([TrevorDev](https://github.com/TrevorDev))
 - Enable dragging in boundingBoxGizmo without needing a parent ([TrevorDev](https://github.com/TrevorDev))
 - Added per mesh culling strategy ([jerome](https://github.com/jbousquie))
+- Added InputsManager and keyboard bindings for FollowCamera. ([mrdunk](https://github.com))
 - Added per solid particle culling possibility : `solidParticle.isInFrustum()`  ([jerome](https://github.com/jbousquie))
 - Added transparency support to `GlowLayer` ([Sebavan](https://github.com/Sebavan))
 

+ 209 - 0
src/Cameras/Inputs/babylon.followCameraKeyboardMoveInput.ts

@@ -0,0 +1,209 @@
+module BABYLON {
+    /**
+     * Manage the keyboard inputs to control the movement of an arc rotate camera.
+     * @see http://doc.babylonjs.com/how_to/customizing_camera_inputs
+     */
+    export class FollowCameraKeyboardMoveInput implements ICameraInput<FollowCamera> {
+        /**
+         * Defines the camera the input is attached to.
+         */
+        public camera: FollowCamera;
+
+        /**
+         * Defines the list of key codes associated with the up action (increase heightOffset)
+         */
+        @serialize()
+        public keysUp = [38];
+
+        /**
+         * Defines the list of key codes associated with the down action (decrease heightOffset)
+         */
+        @serialize()
+        public keysDown = [40];
+
+        /**
+         * Defines the list of key codes associated with the left action (increase rotation)
+         */
+        @serialize()
+        public keysLeft = [37];
+
+        /**
+         * Defines the list of key codes associated with the right action (decrease rotation)
+         */
+        @serialize()
+        public keysRight = [39];
+
+        /**
+         * Defines the rate of change of heightOffset.
+         */
+        @serialize()
+        public heightSensibility: number = 1;
+
+        /**
+         * Defines the rate of change of rotationOffset.
+         */
+        @serialize()
+        public rotationSensibility: number = 1;
+
+        /**
+         * Defines the rate of change of radius.
+         */
+        @serialize()
+        public radiusSensibility: number = 1;
+
+        /**
+         * Defines the minimum heightOffset value.
+         */
+        @serialize()
+        public minHeightOffset: number = 0;
+
+        /**
+         * Defines the minimum radius value.
+         */
+        @serialize()
+        public minRadius: number = 0;
+
+        private _keys = new Array<number>();
+        // private _ctrlPressed: boolean;
+        private _altPressed: boolean;
+        private _onCanvasBlurObserver: Nullable<Observer<Engine>>;
+        private _onKeyboardObserver: Nullable<Observer<KeyboardInfo>>;
+        private _engine: Engine;
+        private _scene: Scene;
+
+        /**
+         * Attach the input controls to a specific dom element to get the input from.
+         * @param element Defines the element the controls should be listened from
+         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
+         */
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
+
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(() => {
+                this._keys = [];
+            });
+
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add((info) => {
+                let evt = info.event;
+                if (!evt.metaKey) {
+                    if (info.type === KeyboardEventTypes.KEYDOWN) {
+                        // this._ctrlPressed = evt.ctrlKey;
+                        this._altPressed = evt.altKey;
+
+                        if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                            this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                            this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                            this.keysRight.indexOf(evt.keyCode) !== -1) {
+                            var index = this._keys.indexOf(evt.keyCode);
+
+                            if (index === -1) {
+                                this._keys.push(evt.keyCode);
+                            }
+
+                            if (evt.preventDefault) {
+                                if (!noPreventDefault) {
+                                    evt.preventDefault();
+                                }
+                            }
+                        }
+                    }
+                    else {
+                        if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                            this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                            this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                            this.keysRight.indexOf(evt.keyCode) !== -1) {
+                            var index = this._keys.indexOf(evt.keyCode);
+
+                            if (index >= 0) {
+                                this._keys.splice(index, 1);
+                            }
+
+                            if (evt.preventDefault) {
+                                if (!noPreventDefault) {
+                                    evt.preventDefault();
+                                }
+                            }
+                        }
+                    }
+                }
+            });
+        }
+
+        /**
+         * Detach the current controls from the specified dom element.
+         * @param element Defines the element to stop listening the inputs from
+         */
+        public detachControl(element: Nullable<HTMLElement>) {
+            if (this._scene) {
+                if (this._onKeyboardObserver) {
+                    this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                }
+                if (this._onCanvasBlurObserver) {
+                    this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                }
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
+            }
+
+            this._keys = [];
+        }
+
+        /**
+         * Update the current camera state depending on the inputs that have been used this frame.
+         * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
+         */
+        public checkInputs(): void {
+            if (this._onKeyboardObserver) {
+                for (var index = 0; index < this._keys.length; index++) {
+                    var keyCode = this._keys[index];
+                    if (this.keysLeft.indexOf(keyCode) !== -1) {
+                      this.camera.rotationOffset += this.rotationSensibility;
+                      this.camera.rotationOffset %= 180;
+                    } else if (this.keysUp.indexOf(keyCode) !== -1) {
+                      if (this._altPressed) {
+                        this.camera.radius += this.radiusSensibility;
+                      } else {
+                        this.camera.heightOffset += this.heightSensibility;
+                      }
+                    } else if (this.keysRight.indexOf(keyCode) !== -1) {
+                      this.camera.rotationOffset -= this.rotationSensibility;
+                      this.camera.rotationOffset %= 180;
+                    } else if (this.keysDown.indexOf(keyCode) !== -1) {
+                      if (this._altPressed) {
+                        this.camera.radius -= this.radiusSensibility;
+                        this.camera.radius =
+                          Math.max(this.minRadius, this.camera.radius);
+                      } else {
+                        this.camera.heightOffset -= this.heightSensibility;
+                        this.camera.heightOffset =
+                          Math.max(this.minHeightOffset, this.camera.heightOffset);
+                      }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Gets the class name of the current intput.
+         * @returns the class name
+         */
+        public getClassName(): string {
+            return "FollowCameraKeyboardMoveInput";
+        }
+
+        /**
+         * Get the friendly name associated with the input class.
+         * @returns the input friendly name
+         */
+        public getSimpleName(): string {
+            return "keyboard";
+        }
+    }
+
+    (<any>CameraInputTypes)["FollowCameraKeyboardMoveInput"] = FollowCameraKeyboardMoveInput;
+}

+ 1 - 1
src/Cameras/arcRotateCamera.ts

@@ -415,7 +415,7 @@ import { ArcRotateCameraInputsManager } from "../Cameras/arcRotateCameraInputsMa
         public _panningMouseButton: number;
 
         /**
-         * Defines the inpute associated to the camera.
+         * Defines the input associated to the camera.
          */
         public inputs: ArcRotateCameraInputsManager;
 

+ 52 - 0
src/Cameras/babylon.followCameraInputsManager.ts

@@ -0,0 +1,52 @@
+module BABYLON {
+    /**
+     * Default Inputs manager for the FollowCamera.
+     * It groups all the default supported inputs for ease of use.
+     * @see http://doc.babylonjs.com/how_to/customizing_camera_inputs
+     */
+    export class FollowCameraInputsManager extends CameraInputsManager<FollowCamera> {
+        /**
+         * Instantiates a new FollowCameraInputsManager.
+         * @param camera Defines the camera the inputs belong to
+         */
+        constructor(camera: FollowCamera) {
+            super(camera);
+        }
+
+        /**
+         * Add keyboard input support to the input manager.
+         * @returns the current input manager
+         */
+        public addKeyboard(): FollowCameraInputsManager {
+            this.add(new FollowCameraKeyboardMoveInput());
+            return this;
+        }
+
+        /**
+         * Add mouse wheel input support to the input manager.
+         * @returns the current input manager
+         */
+        public addMouseWheel(): FollowCameraInputsManager {
+            console.warn("MouseWheel support not yet implemented for FollowCamera.");
+            return this;
+        }
+
+        /**
+         * Add pointers input support to the input manager.
+         * @returns the current input manager
+         */
+        public addPointers(): FollowCameraInputsManager {
+            console.warn("Pointer support not yet implemented for FollowCamera.");
+            return this;
+        }
+
+        /**
+         * Add orientation input support to the input manager.
+         * @returns the current input manager
+         */
+        public addVRDeviceOrientation(): FollowCameraInputsManager {
+            console.warn("DeviceOrientation support not yet implemented for FollowCamera.");
+            return this;
+        }
+    }
+}

+ 35 - 0
src/Cameras/followCamera.ts

@@ -57,6 +57,11 @@ import { AbstractMesh } from "../Meshes/abstractMesh";
         @serializeAsMeshReference("lockedTargetId")
         public lockedTarget: Nullable<AbstractMesh>;
 
+        /**
+         * Defines the input associated with the camera.
+         */
+        public inputs: FollowCameraInputsManager;
+
         /**
          * Instantiates the follow camera.
          * @see http://doc.babylonjs.com/features/cameras#follow-camera
@@ -69,6 +74,10 @@ import { AbstractMesh } from "../Meshes/abstractMesh";
             super(name, position, scene);
 
             this.lockedTarget = lockedTarget;
+            this.inputs = new FollowCameraInputsManager(this);
+            this.inputs.addKeyboard();
+            // Uncomment the following line when the relevant handlers have been implemented.
+            // this.inputs.addKeyboard().addMouseWheel().addPointers().addVRDeviceOrientation();
         }
 
         private _follow(cameraTarget: AbstractMesh) {
@@ -112,8 +121,34 @@ import { AbstractMesh } from "../Meshes/abstractMesh";
             this.setTarget(targetPosition);
         }
 
+        /**
+         * Attached controls to the current camera.
+         * @param element Defines the element the controls should be listened from
+         * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
+         */
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+          this.inputs.attachElement(element, noPreventDefault);
+
+          this._reset = () => {
+          };
+        }
+
+        /**
+         * Detach the current controls from the camera.
+         * The camera will stop reacting to inputs.
+         * @param element Defines the element to stop listening the inputs from
+         */
+        public detachControl(element: HTMLElement): void {
+          this.inputs.detachElement(element);
+
+          if (this._reset) {
+            this._reset();
+          }
+        }
+
         /** @hidden */
         public _checkInputs(): void {
+            this.inputs.checkInputs();
             super._checkInputs();
             if (this.lockedTarget) {
                 this._follow(this.lockedTarget);