在 Babylon.js 中,行为(Behavior,这个和Unity的继承自MonoBehavior的组件实在是有点儿像)的编写非常中要,这里举一个例子:
// RotateBehavior.js
class RotateBehavior {
constructor() {
this.rotateEnabled = true;
this.rotationSpeed = 60; // 默认每秒旋转 60 度
}
init() {
console.log("旋转行为初始化");
}
// Babylon.js 会自动调用这个方法来附加行为
attach(target) {
this.target = target;
this.target.onBeforeRenderObservable.add(() => {
if (this.rotateEnabled) {
this.target.rotation.y += BABYLON.Tools.ToRadians(this.rotationSpeed) * this.target.getScene().getEngine().getDeltaTime() / 1000;
}
});
}
// Babylon.js 会自动调用这个方法来分离行为
detach() {
if (this.target) {
this.target.onBeforeRenderObservable.remove(this.target.onBeforeRenderObservable.getObservers().find((observer) => observer.callback === this.update));
this.target = null;
}
console.log("旋转行为分离");
}
setRotateEnable(enable) {
this.rotateEnabled = enable;
}
setRotationSpeed(speed) {
this.rotationSpeed = speed;
}
}
export default RotateBehavior;
上面这个行为让mesh可以按y轴每秒旋转特定的角度。其中
this.rotateEnabled = true;
this.rotationSpeed = 60; // 默认每秒旋转 60 度
这两行代码写到 init 方法中也可以。
需要说明的是,以下三个方法是必须实现的,他们分别是:
- init() ,这个方法会在行为被附加到目标之前调用。
- attach(target) ,这个方法会在行为被附加时调用。
- detach(),这个方法会在行为被分离时调用。
以下是一个使用该行为的参考代码:
import * as BABYLON from 'babylonjs';
import RotateBehavior from './RotateBehavior';
// 创建场景和引擎
var createScene = function () {
var canvas = document.getElementById("renderCanvas");
var engine = new BABYLON.Engine(canvas, true);
var scene = new BABYLON.Scene(engine);
// 创建摄像机
var camera = new BABYLON.ArcRotateCamera("camera", Math.PI / 2, Math.PI / 4, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
// 创建一个简单的立方体
var box = BABYLON.MeshBuilder.CreateBox("box", { size: 2 }, scene);
box.position.y = 1; // 将立方体稍微抬高,避免与地面重叠
// 创建旋转行为实例并附加到立方体上
var rotateBehavior = new RotateBehavior();
box.addBehavior(rotateBehavior);
// 提供一个按钮来控制旋转的启停和速度
var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
var toggleRotateButton = BABYLON.GUI.Button.CreateSimpleButton("toggleRotate", "Toggle Rotate");
toggleRotateButton.width = "120px";
toggleRotateButton.height = "40px";
toggleRotateButton.color = "white";
toggleRotateButton.background = "green";
toggleRotateButton.onPointerClickObservable.add(() => {
rotateBehavior.setRotateEnable(!rotateBehavior.rotateEnabled);
toggleRotateButton.text = rotateBehavior.rotateEnabled ? "Stop Rotate" : "Start Rotate";
});
advancedTexture.addControl(toggleRotateButton);
var setSpeedButton = BABYLON.GUI.Button.CreateSimpleButton("setSpeed", "Set Speed to 120");
setSpeedButton.width = "120px";
setSpeedButton.height = "40px";
setSpeedButton.color = "white";
setSpeedButton.background = "blue";
setSpeedButton.onPointerClickObservable.add(() => {
rotateBehavior.setRotationSpeed(120);
});
advancedTexture.addControl(setSpeedButton);
// 渲染场景
engine.runRenderLoop(function () {
scene.render();
});
// 处理窗口大小变化
window.addEventListener("resize", function () {
engine.resize();
});
return scene;
};
// 创建场景
var scene = createScene();
这里将行为附加到mesh上的方法有两种,以上例子中写的是:
box.addBehavior(rotateBehavior);
其实写成以下形式也是可以的:
rotateBehavior.attach(box, scene, engine);
但是Babylon推荐的是第一种,因为它提供了一些内置的管理和生命周期处理功能,而Behavior.attch这个方法是需要手动管理的,虽然灵活性比较高,但对开发者要求也较高,不建议初学者使用。