@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
204 lines • 7.5 kB
JavaScript
import { Logger } from "../Misc/logger.js";
import { SerializationHelper } from "../Misc/decorators.serialization.js";
import { Camera } from "./camera.js";
/**
* @ignore
* This is a list of all the different input types that are available in the application.
* Fo instance: ArcRotateCameraGamepadInput...
*/
// eslint-disable-next-line no-var, @typescript-eslint/naming-convention
export var CameraInputTypes = {};
/**
* This represents the input manager used within a camera.
* It helps dealing with all the different kind of input attached to a camera.
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
*/
export class CameraInputsManager {
/**
* Instantiate a new Camera Input Manager.
* @param camera Defines the camera the input manager belongs to
*/
constructor(camera) {
/**
* Defines the dom element the camera is collecting inputs from.
* This is null if the controls have not been attached.
*/
this.attachedToElement = false;
this.attached = {};
this.camera = camera;
this.checkInputs = () => { };
}
/**
* Add an input method to a camera
* @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs
* @param input Camera input method
*/
add(input) {
const type = input.getSimpleName();
if (this.attached[type]) {
Logger.Warn("camera input of type " + type + " already exists on camera");
return;
}
this.attached[type] = input;
input.camera = this.camera;
// for checkInputs, we are dynamically creating a function
// the goal is to avoid the performance penalty of looping for inputs in the render loop
if (input.checkInputs) {
this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
}
if (this.attachedToElement) {
input.attachControl(this.noPreventDefault);
}
}
/**
* Remove a specific input method from a camera
* example: camera.inputs.remove(camera.inputs.attached.mouse);
* @param inputToRemove camera input method
*/
remove(inputToRemove) {
for (const cam in this.attached) {
const input = this.attached[cam];
if (input === inputToRemove) {
input.detachControl();
input.camera = null;
delete this.attached[cam];
this.rebuildInputCheck();
return;
}
}
}
/**
* Remove a specific input type from a camera
* example: camera.inputs.remove("ArcRotateCameraGamepadInput");
* @param inputType the type of the input to remove
*/
removeByType(inputType) {
for (const cam in this.attached) {
const input = this.attached[cam];
if (input.getClassName() === inputType) {
input.detachControl();
input.camera = null;
delete this.attached[cam];
this.rebuildInputCheck();
}
}
}
_addCheckInputs(fn) {
const current = this.checkInputs;
return () => {
current();
fn();
};
}
/**
* Attach the input controls to the currently attached dom element to listen the events from.
* @param input Defines the input to attach
*/
attachInput(input) {
if (this.attachedToElement) {
input.attachControl(this.noPreventDefault);
}
}
/**
* Attach the current manager inputs controls to a specific dom element to listen the events from.
* @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
*/
attachElement(noPreventDefault = false) {
if (this.attachedToElement) {
return;
}
noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
this.attachedToElement = true;
this.noPreventDefault = noPreventDefault;
for (const cam in this.attached) {
this.attached[cam].attachControl(noPreventDefault);
}
}
/**
* Detach the current manager inputs controls from a specific dom element.
* @param disconnect Defines whether the input should be removed from the current list of attached inputs
*/
detachElement(disconnect = false) {
for (const cam in this.attached) {
this.attached[cam].detachControl();
if (disconnect) {
this.attached[cam].camera = null;
}
}
this.attachedToElement = false;
}
/**
* Rebuild the dynamic inputCheck function from the current list of
* defined inputs in the manager.
*/
rebuildInputCheck() {
this.checkInputs = () => { };
for (const cam in this.attached) {
const input = this.attached[cam];
if (input.checkInputs) {
this.checkInputs = this._addCheckInputs(input.checkInputs.bind(input));
}
}
}
/**
* Remove all attached input methods from a camera
*/
clear() {
if (this.attachedToElement) {
this.detachElement(true);
}
this.attached = {};
this.attachedToElement = false;
this.checkInputs = () => { };
}
/**
* Serialize the current input manager attached to a camera.
* This ensures than once parsed,
* the input associated to the camera will be identical to the current ones
* @param serializedCamera Defines the camera serialization JSON the input serialization should write to
*/
serialize(serializedCamera) {
const inputs = {};
for (const cam in this.attached) {
const input = this.attached[cam];
const res = SerializationHelper.Serialize(input);
inputs[input.getClassName()] = res;
}
serializedCamera.inputsmgr = inputs;
}
/**
* Parses an input manager serialized JSON to restore the previous list of inputs
* and states associated to a camera.
* @param parsedCamera Defines the JSON to parse
*/
parse(parsedCamera) {
const parsedInputs = parsedCamera.inputsmgr;
if (parsedInputs) {
this.clear();
for (const n in parsedInputs) {
const construct = CameraInputTypes[n];
if (construct) {
const parsedinput = parsedInputs[n];
const input = SerializationHelper.Parse(() => {
return new construct();
}, parsedinput, null);
this.add(input);
}
}
}
else {
//2016-03-08 this part is for managing backward compatibility
for (const n in this.attached) {
const construct = CameraInputTypes[this.attached[n].getClassName()];
if (construct) {
const input = SerializationHelper.Parse(() => {
return new construct();
}, parsedCamera, null);
this.remove(this.attached[n]);
this.add(input);
}
}
}
}
}
//# sourceMappingURL=cameraInputsManager.js.map