Let’s use the observer pattern to reimplement our earlier revolving rotating box.
For simplicity, we’ll define a shared subject as a global variable visible to all functions:
let subject = new Subject();
Our new version of the makeRotatingRevolvingBox
function is tasked with constructing the scene graph as well as turning its two nodes into observers:
function makeRotatingRevolvingBox() { let geom = new THREE.CubeGeometry(4, 1, 1); let mat = new THREE.MeshLambertMaterial({color: 'blue'}); let box = new THREE.Mesh(geom, mat); box.position.x = 4; box.rps = 0.5; // rotation every 2 seconds box.update = spinZ; // make box an observer subject.register(box); let boxRoot = new THREE.Object3D(); boxRoot.rps = 0.1; // revolution every 10 seconds boxRoot.update = spinZ; // make boxRoot an observer subject.register(boxRoot); boxRoot.add(box); return boxRoot; }
Both nodes, box and boxRoot, share the same update function spinZ
since each rotates around the z-axis. Each node stores its own rotation rate in its own rps property which, as a method of each node, spinZ
can access. Any node to which spinZ
is attached as a method defines its own rate of rotation.
function spinZ(delta) { this.rotation.z += rpsToRadians(this.rps, delta); this.rotation.z %= 2 * Math.PI; }
The update
function which gets called for every frame refresh is simplicity itself:
function update() { let delta = clock.getDelta(); subject.notify(delta); }
Update
doesn’t need to know anything about behaviors. It only needs to notify subject of time elapsed since the last refresh. You might wish to compare the function definitions given here with their counterparts defined previously.