Переглянути джерело

Merge pull request #5702 from mrdunk/FollowCamera_InputManager

Added InputsManager and keyboard bindings for FollowCamera.
David Catuhe 6 роки тому
батько
коміт
13e694d5ad

+ 12 - 1
Tools/Gulp/config.json

@@ -46,6 +46,7 @@
             "freeCamera",
             "flyCamera",
             "arcRotateCamera",
+            "followCamera",
             "hemisphericLight",
             "pointLight",
             "directionalLight",
@@ -567,6 +568,16 @@
                 "targetCamera"
             ]
         },
+        "followCamera": {
+            "files": [
+                "../../src/Cameras/Inputs/babylon.followCameraKeyboardMoveInput.js",
+                "../../src/Cameras/babylon.followCameraInputsManager.js",
+                "../../src/Cameras/babylon.followCamera.js"
+            ],
+            "dependUpon": [
+                "targetCamera"
+            ]
+        },
         "hemisphericLight": {
             "files": [
                 "../../src/Lights/babylon.hemisphericLight.js"
@@ -2129,4 +2140,4 @@
             ]
         }
     }
-}
+}

+ 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))
 
 ### OBJ Loader

+ 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/babylon.arcRotateCamera.ts

@@ -397,7 +397,7 @@ module BABYLON {
         public _panningMouseButton: number;
 
         /**
-         * Defines the inpute associated to the camera.
+         * Defines the input associated to the camera.
          */
         public inputs: ArcRotateCameraInputsManager;
 

+ 35 - 0
src/Cameras/babylon.followCamera.ts

@@ -50,6 +50,11 @@ module BABYLON {
         @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
@@ -62,6 +67,10 @@ module BABYLON {
             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) {
@@ -105,8 +114,34 @@ module BABYLON {
             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);

+ 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;
+        }
+    }
+}