## Friday, February 1, 2013

### OO Click and Drag Three.js Ramps

‹prev | My Chain | next›

As the the beta for 3D Game Programming for Kids draws near, I have been reviewing the content. One thing that I realized was that that the game that I have been building is tentatively scheduled to go after the JavaScript objects introduction. I do not plan on going heavy with the object oriented coding for this book, but it still seems like something that I have to at least touch on.

With that in mind, I should try to find some opportunity for object oriented coding in the platformer game that I have been trying to build:

My initial thought is to convert the ramps from their current functional approach:
``````  function makeRamp(x, y, rotation) {
var ramp = new Physijs.ConvexMesh(
new THREE.CubeGeometry(50, 500, 10),
Physijs.createMaterial(
new THREE.MeshBasicMaterial({color:0x0000cc}), 0.2, 1.0
),
0
);
ramp.rotation.set(0, 0, rotation);
ramp.position.set(x, y, 0);
return ramp;
}
var ramp1 = makeRamp(0.4*width/2, -height/2 + 25, -Math.PI/4);
var ramp2 = makeRamp(-0.3*width/2, 0, Math.PI/3);
This can be rewritten as:
``````  var Ramp = function(x, y, rotation) {
this.mesh = new Physijs.ConvexMesh(
new THREE.CubeGeometry(50, 500, 10),
Physijs.createMaterial(
new THREE.MeshBasicMaterial({color:0x0000cc}), 0.2, 1.0
),
0
);
this.setPosition(x,y);
this.setRotation(rotation);
};

Ramp.prototype.setRotation = function(rotation) {
this.mesh.rotation.set(0,0,rotation);
};

Ramp.prototype.setPosition = function(x, y) {
this.mesh.position.set(x, y, 0);
};``````
This class can then be invoked in much the same way as the factory function:
``````  var ramp1 = new Ramp(0.4*width/2, -height/2 + 25, -Math.PI/4);
var ramp2 = new Ramp(-0.3*width/2, 0, Math.PI/3);
Admittedly, that is not a significant reduction in the amount of code. It is a bit cleaner. What can really improve in this approach is the event handling. Previously, I had to rely on document event handlers:
``````  var active_ramp, mouse_x, mouse_y;
//console.log(event.clientX);
//console.log(event.clientY);

mouse_x = event.clientX;
mouse_y = event.clientY;
var position = new THREE.Vector3(
event.clientX - width/2,
height/2 - event.clientY,
500
);
var vector = new THREE.Vector3(0, 0, -1);
var ray = new THREE.Ray(position, vector);
var intersects = ray.intersectObject(ramp1);
if (intersects.length > 0) active_ramp = ramp1;
intersects = ray.intersectObject(ramp2);
if (intersects.length > 0) active_ramp = ramp2;
});``````
The disadvantage of this approach is the need to manually check all ramps. With an OO approach, each ramp is responsible for checking if it has been clicked:
``````  Ramp.prototype.onClick =  function(event) {
this.mouse_x = event.clientX;
this.mouse_y = event.clientY;
var position = new THREE.Vector3(
event.clientX - width/2,
height/2 - event.clientY,
500
);
var vector = new THREE.Vector3(0, 0, -1);
var ray = new THREE.Ray(position, vector);
var intersects = ray.intersectObject(this.mesh);
this.isActive = (intersects.length > 0);
};``````
That's not a heck of a lot cleaner, but it does accomplish the goal of forcing each instance to check if it is being clicked. Really, I need to move just about all of that out into a more general click handler (or get the DOM event library working again). The only thing in there that is specific to the ramps being moved around is the `isActive` setting. I will worry about generalizing another night.

For now, I get it working with some simple event document event listeners in the Ramp constructor:
``````  var Ramp = function(x, y, rotation) {
// ...
var that = this;
};
``````
Ew. I am definitely going to need to rethink this. It does work—I can again click and drag ramps around the screen. But I had hoped to avoid a scoping discussion in a kid's introduction book, but here I am forced to fall back to a `that = this` scope hack.

I am unsure if this means that I should be writing my own DOM events library or if I ought to go back to retry some of the existing solutions. For now, I call it a night. At least it's a night with a working implementation.

(the code so far)

Day #648