I think I may have a cheat that will solve my JavaScript object woes. My woes are not of the how-to-do-it variety. This is JavaScript after all, I have at least three ways that I can solve my current problem. My woes are more along the lines of how much of this mess do I inflict on kids in 3D Game Programming for Kids?
The problem remains that I have a JavaScript prototype that describes a Three.js / Physijs ramp in a game:
Each ramp needs to support mouse drag events to allow the player to reposition the ramp. I have a fairly decent solution that relies on the prototype defining an
onDrag()
method: var ramp = {
startAt: function(location) {
this.mesh = new Physijs.ConvexMesh( /* ... */ );
this.setRotation(location.rotation);
this.setPosition(location.position[0], location.position[1]);
addMouseHandlers(this);
},
onDrag: function(event) {
this.mesh.__dirtyPosition = true;
this.mesh.position.x = this.mesh.position.x + event.x_diff;
this.mesh.position.y = this.mesh.position.y + event.y_diff;
},
// ...
};
As much as that works, I would prefer to add the mouse event listener in a manner that is more consistent with the rest of the book. Something like: Mouse.addEventListener('drag', this.mesh, this.drag, this)
But without the this
craziness. This had me stymied last night, because this is JavaScript. Context is king in JavaScript so I could see no way to avoid binding this
(and thus needing to explain it to kids). What I realize today is that I can cheat, with a little help from JavaScript's lexical scoping (another thing that I hope to avoid telling kids about). Specifically, the
onDrag
method that I currently have in place acts on and uses only the ramp's mesh object. So I can create a lexically scoped reference to that mesh, which can then be used in the event listener: var ramp = {
startAt: function(location) {
this.mesh = new Physijs.ConvexMesh( /* ... */ );
this.setRotation(location.rotation);
this.setPosition(location.position[0], location.position[1]);
var mesh = this.mesh;
Mouse.addEventListener('drag', mesh, function(event) {
mesh.__dirtyPosition = true;
mesh.position.x = mesh.position.x + event.x_diff;
mesh.position.y = mesh.position.y + event.y_diff;
});
},
// ...
};
Obviously I would have to introduce this
. I would have to make some mention that it does not always mean what you think it means, but I could leave the complete explanation as beyond the scope of the book (or possibly inflict it in an appendix).I get that working with a small wrapper around the previous
addMouseHandlers()
code which requires the supplied object follow the conventions of defining a mesh
property and any event properties requiring a callback: var Mouse = {
callbacks: {'drag': {}},
addEventListener: function(name, mesh, callback) {
if (!this.callbacks.hasOwnProperty(name)) return;
var handler = {};
handler.mesh = mesh;
handler[name] = callback;
addMouseHandlers(handler);
}
};
With that, I have mouse events working on Three.js object in way that looks very much like the document.addEventListener()
that I inflict on kids in a previous chapter.I could almost see it modifying the Physijs and Three.js mesh prototype so that something like the following would work:
mesh.addEventListener('drag', function(event) {
this.__dirtyPosition = true;
this.position.x = this.position.x + event.x_diff;
this.position.y = this.position.y + event.y_diff;
});
I worry that this syntax would open the this
can of proverbial worms.I will probably factor this code out into a library tomorrow. I may give the Three.js mesh prototype support for
addEventListener()
a try at the same time. Even if I avoid it in the book, it might be nice to have around.(the current state of the code)
Day #652
No comments:
Post a Comment