相机默认会在我们我们将其绑定(attachControl)到画布上面时,给我们自动处理操作输入事件。你还可以使用detachControl
函数来解除事件的绑定。大多数Babylon.js的专家都使用两步:
//第一步,设置相机的activeCamera为你创建的相机
scene.activeCamera = myCamera;
//第二步,将相机绑定到画布
//配置项:画布对象canvas,不阻止默认事件noPreventDefault
scene.activeCamera.attachControl(canvas, true);
还有更简单的版本:
myCamera.attachControl(canvas);
默认情况下,noPreventDefault
值为false。这意味着绑定到画布的所有的相机操作都将自动阻止默认事件。
在Babylon.js v2.4版本引入了一种不同的方式来管理相机的操作,提供了一种面向输入可组合性的方法。你可以使用输入管理器,并且每个输入都可以被视为此摄像机系列的插件,以及给定的输入类型(鼠标,键盘,游戏手柄,陀螺仪等)。
使用输入管理器( input manager),你可以添加,删除,启用或者禁用相机可用的任何输入。你可以非常轻松的实现自己的输入机制或覆盖现有的输入机制。
例如,输入管理器( input manager)可以用过相机的inputs
属性来获取:
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
var inputManager = camera.inputs;
配置你的输入
大多数输入提供设置自定义敏感度使相机适应你的场景。
每个输入在管理器上提供了一个简短的名称。目的是为了方便设置。
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
camera.inputs.attached.gamepad.gamepadAngularSensibility = 250;
添加现有的输入
ArcRotateCamera和FreeCamera的输入管理器都公开了用于添加内置输入的简写函数。
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.addGamepad();
等同于
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
如果需要,你还可以自定义自己的输入方式(本节末尾处将实现自定义输入)。
启用或禁用输入
当你调用相机的attachControl
时,会自动激活input manager
的所有的输入。同样的,调用相机的detachControl
时,将关闭所有的输入。
如果想要暂时禁用输入,可以直接在输入上调用detachControl
来禁止某个操作输入:
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.attached.mouse.detachControl();
camera.inputs.addGamepad();
如果你想再打开它,可以调用attachInput
:
camera.inputs.attachInput(camera.inputs.attached.mouse);
删除输入
有时,你需要一个非常具体的输入机制。在这种情况下,最好的办法可能是清除当前所有的默认输入并添加需要的输入。
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.clear();
camera.inputs.addMouse();
你还可以从input Manager
里面删除掉某个输入。你可以按实例或者类型名称删除:
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
// 按照实例删除输入
camera.inputs.remove(camera.inputs.attached.mouse);
// 按照类型名称删除输入
camera.inputs.removeByType("FreeCameraKeyboardMoveInput");
实现自己的输入
我们实现的自己的输入必须是一个类(构造函数)。而且还必须为类添加多个所需的方法,这些方法将会由输入函数对象调用:
//这个方法返回相机的类型名称,它可用于序列化场景
getTypeName();
//这个函数返回添加到输入管理器中的输入的简称
//比如camera.inputs.attached.mouse将返回 "mouse"
getSimpleName();
//这个函数用于绑定设备事件,即使你的输入不需要DOM元素。
// element 和noPreventDefault 为必填项
//返回空
attachControl(element, noPreventDefault);
//解绑控制方法必须能够停止输入事件并解绑所有的指针,闭包和事件监听。
//element 为必填项
// 返回空
detachControl(element);
//如果你需要输入与渲染同步,这个函数将在每一个渲染帧中调用。
//无须使用requestAnimationFrame方法. 如果需要这是一个需要计算的好地方。
// 返回空
checkInputs();
使用JavaScript实现
我们将改变FreeCamera
的键盘操作,将移动操作改为旋转操作。
首先删除掉默认的键盘输入:
camera.inputs.removeByType("FreeCameraKeyboardMoveInput");
创建新的构造函数FreeCameraKeyboardRotateInput
:
var FreeCameraKeyboardRotateInput = function () {
this._keys = [];
this.keysLeft = [37];
this.keysRight = [39];
this.sensibility = 0.01;
}
添加获取名称方法
FreeCameraKeyboardRotateInput.prototype.getTypeName = function () {
return "FreeCameraKeyboardRotateInput";
};
FreeCameraKeyboardRotateInput.prototype.getSimpleName = function () {
return "keyboardRotate";
};
然后再添加绑定事件和解绑事件的方法:
FreeCameraKeyboardRotateInput.prototype.attachControl = function (element, noPreventDefault) {
var _this = this;
if (!this._onKeyDown) {
element.tabIndex = 1;
this._onKeyDown = function (evt) {
if (_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 (!noPreventDefault) {
evt.preventDefault();
}
}
};
this._onKeyUp = function (evt) {
if (_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 (!noPreventDefault) {
evt.preventDefault();
}
}
};
element.addEventListener("keydown", this._onKeyDown, false);
element.addEventListener("keyup", this._onKeyUp, false);
BABYLON.Tools.RegisterTopRootEvents([
{ name: "blur", handler: this._onLostFocus }
]);
}
};
FreeCameraKeyboardRotateInput.prototype.detachControl = function (element) {
if (this._onKeyDown) {
element.removeEventListener("keydown", this._onKeyDown);
element.removeEventListener("keyup", this._onKeyUp);
BABYLON.Tools.UnregisterTopRootEvents([
{ name: "blur", handler: this._onLostFocus }
]);
this._keys = [];
this._onKeyDown = null;
this._onKeyUp = null;
}
};
添加每一帧的处理检测:
FreeCameraKeyboardRotateInput.prototype.checkInputs = function () {
if (this._onKeyDown) {
var camera = this.camera;
// Keyboard
for (var index = 0; index < this._keys.length; index++) {
var keyCode = this._keys[index];
if (this.keysLeft.indexOf(keyCode) !== -1) {
camera.cameraRotation.y += this.sensibility;
}
else if (this.keysRight.indexOf(keyCode) !== -1) {
camera.cameraRotation.y -= this.sensibility;
}
}
}
};
最后将新的输入方法添加到相机的input Manager
:
camera.inputs.add(new FreeCameraKeyboardRotateInput());
- 在此处查看官方示例
使用TypeScript
使用TypeScript,您可以实现接口ICameraInput。
interface ICameraInput<TCamera extends BABYLON.Camera> {
// 填充输入管理的父相机
camera: TCamera;
//这个方法返回相机的类型名称,它可用于序列化场景
getTypeName(): string;
//这个函数返回添加到输入管理器中的输入的简称
//比如camera.inputs.attached.mouse将返回 "mouse"
getSimpleName(): string;
//这个函数用于绑定设备事件,即使你的输入不需要DOM元素。
attachControl: (element: HTMLElement, noPreventDefault?: boolean) => void;
//解绑控制方法必须能够停止输入事件并解绑所有的指针,闭包和事件监听。
detachControl: (element: HTMLElement) => void;
//如果你需要输入与渲染同步,这个函数将在每一个渲染帧中调用。
//无须使用requestAnimationFrame方法. 如果需要这是一个需要计算的好地方。
checkInputs?: () => void;
}