Lesson 32 - Picking and Testing

 

Introduction

This lesson is very similar to lesson 30. We once again use the RayCaster, but this time we use it to test what objects may intersect a given spot on the screen in 2D space. The basic set-up and intialization is exactly the same as lesson 30, creating a partially transparent cube with a wooden floor, populated with a number of bouncing objects. All the setup and collision handling is the same as before, so we needn't cover it.

The goal of the user is to click on the screen and "hit" one of the objects. When the user successfully touches one of the objects, it turns white and slowly fades away. Once wholly transparent it is removed from the scene. When all the objects are gone, a congratulatory phrase appears and the "game" is over.

Two 'Casters

In this lesson, we set up two RayCasters, one for calculating collisions, the other, pointCaster, we use to look for clicks on the objects.

var rayCaster   = new THREE.Raycaster();
var pointCaster = new THREE.Raycaster();

Then we set up a mouse-click handler, which looks like this:

function onClick ( e ) {

    var vector = new THREE.Vector2();

    vector.set( 2 * (e.clientX / gfxScene.canvasWidth) - 1, 1 - 2 * (e.clientY / gfxScene.canvasHeight ));

    // pass two parameters to RayCaster, where the user clicked and the direction of the camera
    pointCaster.setFromCamera(vector, gfxScene.camera);

    // get all the objects that the ray instersects
    var intersects = pointCaster.intersectObjects(objects.children);

    // The first object in the array is the closest to the camera
    if (intersects.length > 0 ) {
        // Make the object white, and decrease its opacity
        intersects[0].object.material.color.setHex(0xffffff);
        intersects[0].object.material.opacity -= 0.025;
        intersects[0].object.material.transparent = true;
    }
}

The routine receives the event, which has the coordinates the user clicked on. These are converted to the range -1..1 (as expected by three.js). The pointCaster is then initialized by passing the converted coordinate-vector and the camera (which is used to determine the direction of the view). The pointCaster method intersectsObjects() is called and returns a collection of the objects which are intersected.

If there are objects, then, as before, the first object in the collection is the closest. So that object's material is set to which and it's transparency is decremented by 0.025.

Subsequently, at each call to animate(), a call is made to fadeObjects:

function fadeObjects() {
    for ( var i = objects.children.length - 1; i >= 0; i-- ) {
        var ball = objects.children[i];

        if (ball.material.opacity <= 0.999) {
            if (ball.material.opacity <= 0) {
                objects.remove(ball);
            }
            else {
                ball.material.opacity -= 0.025;
                ball.material.needsUpdate = true;
            }
        }
    }

    if (objects.children.length === 0  && gameOver === false) {
        createText();
        gameOver = true;
    }
}

Here, each object who has previously been touched (and hence has an opacity less than one) has its opacity further decremented by 0.025. The result is than each object touched disappears in about 2/3 of a second (at 60 fps). When the object's opacity reaches zero it is removed from the sceene. When all the objects have been removed a call is made to createText(), which creates a big text object (see lesson 15) saying "You Won!" and the game is over...

And that's it! Click on this link to see the actual rendered demo in all it's gaming glory!

As always, the original sources are on github here.



About Us | Contact Us | ©2017 Geo-F/X