An observant box

Let’s use the observer pattern to reimplement our earlier revolving rotating box.

A rotating revolving 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.