一:根据需求需要重写ArcRotateCamera的AutoRotationBehavior
import {
ArcRotateCamera,
AutoRotationBehavior,
PointerEventTypes,
Scene,
Animation,
AbstractMesh,
Mesh,
ActionManager,
ExecuteCodeAction,
CubicEase,
EasingFunction
} from '@babylonjs/core';
interface TEventListeners {
idleTimeout: any[];
resetComplete: any[];
}
const easingFunction = new CubicEase();
easingFunction.setEasingMode(EasingFunction.EASINGMODE_EASEINOUT);
/**
* 重写AutoRotationBehavior
*/
class CameraController {
public camera: ArcRotateCamera;
public scene: Scene;
public autoRotationBehavior: AutoRotationBehavior;
private lastInteractionTime: number = Date.now();
private resetInterval: NodeJS.Timer | number | undefined = undefined;
private eventListeners: TEventListeners = {
idleTimeout: [],
resetComplete: []
};
private setupTimer: NodeJS.Timer | number | undefined = undefined;
private once: boolean = false;
public OVER_TIME = 30 * 1000;
private triggerEvents = new Set();
/**
*
* @param camera 相机
* @param scene 场景
* @param mesh 要添加事件的mesh
* @param delay 延迟添加时间
* @param once 是否只执行一次
*/
constructor(camera: ArcRotateCamera, scene: Scene, mesh: AbstractMesh | Mesh, delay?: number, once = false) {
this.camera = camera;
this.scene = scene;
this.once = once;
this.autoRotationBehavior = new AutoRotationBehavior();
const isDelay = Boolean(delay);
/**
* 是否延迟加载
* 某型情况下,不希望希望在场景初始化之后就立即自转,
* 该参数就可以设置为延迟加载的时间
*/
if (isDelay) {
this.setupTimer = setTimeout(() => {
//camera.useAutoRotationBehavior =true 已经失效 attach方法就是添加行为到相机上
this.autoRotationBehavior.attach(this.camera);
}, delay);
} else {
this.autoRotationBehavior.attach(this.camera);
}
this.autoRotationBehavior.idleRotationSpeed = -0.5;
this.autoRotationBehavior.idleRotationWaitTime = 5 * 1000; // 5秒后开始自动旋转
this.autoRotationBehavior.idleRotationSpinupTime = 5000; // 1秒内加速到全速
// this.SetupListeners();
this.SetMeshAction(mesh);
this.StartResetCheck();
}
SetupListeners() {
// 这里如果在场景上添加监听器会有问题
this.scene.onPointerObservable.add((pointerInfo) => {
switch (pointerInfo.type) {
case PointerEventTypes.POINTERDOWN:
this.autoRotationBehavior.idleRotationSpeed = 0;
this.lastInteractionTime = Date.now();
console.log(1111);
break;
case PointerEventTypes.POINTERUP:
this.autoRotationBehavior.idleRotationSpeed = -0.1;
this.lastInteractionTime = Date.now();
console.log(2222);
break;
case PointerEventTypes.POINTERMOVE:
if (pointerInfo.event.button !== 0) {
// 判断按钮是否有被按下
this.lastInteractionTime = Date.now(); // 如果有,则重置时间
}
break;
}
});
}
SetMeshAction(mesh: AbstractMesh | Mesh) {
mesh.actionManager = new ActionManager(this.scene);
mesh.actionManager.registerAction(
new ExecuteCodeAction(
{
trigger: ActionManager.OnPickTrigger
},
() => {
this.autoRotationBehavior.idleRotationSpeed = 0;
this.lastInteractionTime = Date.now();
}
)
);
mesh.actionManager.registerAction(
new ExecuteCodeAction(
{
trigger: ActionManager.OnPickUpTrigger
},
() => {
this.autoRotationBehavior.idleRotationSpeed = -0.5;
this.lastInteractionTime = Date.now();
console.log(this.lastInteractionTime, '最后一次交互时间');
}
)
);
this.scene.onPointerObservable.add((pointerInfo) => {
if (pointerInfo.type === PointerEventTypes.POINTERMOVE) {
if (pointerInfo.pickInfo?.hit && pointerInfo.pickInfo.pickedMesh === mesh) {
// 如果鼠标悬停在mesh上
}
}
});
}
StartResetCheck() {
this.resetInterval = setInterval(() => {
const currentTime = Date.now();
const timeDifference = currentTime - this.lastInteractionTime;
console.log(currentTime - this.lastInteractionTime, '时间差');
// 如果超过20秒,则重置相机角度
if (timeDifference > this.OVER_TIME) {
if (!this.once || !this.triggerEvents.has('idleTimeout')) {
this.TriggerEvent('idleTimeout');
this.ResetCameraRotaion();
this.lastInteractionTime = currentTime; // 重置交互时间
}
}
}, 1000);
}
StopResetCheck() {
if (this.resetInterval) {
clearInterval(this.resetInterval as number);
}
}
ResetCameraRotaion = (initAplha = 1.57, duration = 1000) => {
let currentAlpha = this.camera.alpha;
// 将当前角度限制在 0 ~ 2π 之间
currentAlpha %= Math.PI * 2;
// 如果当前角度小于 0,则加上 2π
if (currentAlpha < 0) {
currentAlpha += Math.PI * 2;
}
// 计算当前角度与目标角度之间的差值
let deltaAlpha = initAplha - currentAlpha;
// 如果差值大于 π,则将差值减去 2π 说明反方向旋转更短
if (Math.abs(deltaAlpha) > Math.PI) {
deltaAlpha = deltaAlpha > 0 ? deltaAlpha - Math.PI * 2 : deltaAlpha + Math.PI * 2;
}
const ani = Animation.CreateAndStartAnimation(
'resetCameraRotaion',
this.camera,
'alpha',
60,
duration / (1000 / 60),
this.camera.alpha,
this.camera.alpha + deltaAlpha,
Animation.ANIMATIONLOOPMODE_CONSTANT
);
ani!.onAnimationEnd = () => {
if (!this.once || !this.triggerEvents.has('resetComplete')) {
this.autoRotationBehavior.idleRotationSpeed = 0;
this.TriggerEvent('resetComplete');
}
};
};
addEventListener(eventName: keyof TEventListeners, callback: () => void) {
if (!this.eventListeners[eventName]) {
this.eventListeners[eventName] = [];
}
this.eventListeners[eventName].push(callback);
}
removeEventListener(eventName: keyof TEventListeners, callback: () => void) {
if (this.eventListeners[eventName]) {
this.eventListeners[eventName] = this.eventListeners[eventName].filter((cb) => cb !== callback);
}
}
TriggerEvent(eventName: keyof TEventListeners) {
if (this.eventListeners[eventName]) {
this.eventListeners[eventName].forEach((callback) => callback());
this.triggerEvents.add(eventName);
}
}
Dispose() {
this.StopResetCheck();
this.autoRotationBehavior.detach();
this.eventListeners = null;
this.setupTimer = undefined;
this.resetInterval = undefined;
this.triggerEvents.clear();
}
}
export { CameraController };
二:用法
// 延迟4秒开始自动旋转
this.cameraController = new CameraController(this.camera, this.scene, interactionModel, 4000, true);