Sunday, July 15, 2018

Helix Jump development tutorial using THREE.JS (Part 3)


Hello, guys, let's continue with the development of Helix Jump using THREE.JS

In the previous tutorial ( Part 2 ) we learned how to add platforms and multilevel platforms.
In this section, we will learn to add two type of platforms
1- Green Platforms ( safe platforms )
2- Red Platforms ( game over if the ball hits it )

I will also cover how to add colliders to platforms, which will be needed to detect collision between ball and surface.

Adding Colliders

Collision detection is typically difficult if we are not using a physics engine. But not using physics engine has its own advantages. Adding physics engine for this game will be like, picking a cup using a crane. So its just don't make any sense.

So I will add 2 rectangular colliders to each platform rotated at some angle so that it does not leave edges.

Basically, colliders will look like this.

AABB box collision

As you can see I have added a rectangular box and rotated them at an angle to cover the edges of the platform. You may think what if ball collides somewhat near to cylinder or far from the cylinder so it may not touch the surface.
For that, I want to assure you, the ball will not go anywhere because we will move the ball up and down only and also at fixed x and z value.

Have a look here ball will fall here only


I am using 3D AABB collision detection technique. But I have customized the technique for this game.
For more information on collision detection, you can visit here

I have used a simple box geometry as Collider and I have adjusted its position and rotation according to the platform position.

var collider = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 0.2), 
    this.materials.solid);
collider.position.set(-1.83, -0.22, 1.11);
collider.rotation.x += Math.PI / 2;
collider.rotation.z -= 0.78;
collider.receiveShadow = true;
collider.visible = this.MESH_VISIBILTY;

This collider will have to be rotated in x-axis at Math.PI /2 degree to appear horizontal otherwise it will appear vertical.

Update Constants

Before we proceed to add random platforms ( green and red ) we need to add some constants.
I am taking some more constants which will be used later

Game.player = { 
    height: 2, 
    speed: 0.1, 
    turnSpeed: Math.PI * 0.02, 
    rotateSpeed: Math.PI * 0.01 
};
Game.materials = {
    solid: new THREE.MeshNormalMaterial({})
};
Game.MESH_VISIBILTY = true;
Game.USE_WIREFRAME = false;
Game.GAME_LOADED = false;
Game.GAME_STARTED = false;
Game.RED_PIECE = 10;
Game.GREEN_PIECE = 11;

Game.cameraY = -0.5;
Game.gameOver = false;
Game.score = 0;


Now we have to add random platforms and detect collision with the ball. so we need to save them in arrays. I have taken two array colliderArr and platformArr

Game.addPlatform = function() {

    this.colliderArr = [];
    this.platformArr = [];

    var yDiff = 2;
    var platformPieceType = [
            { type: this.GREEN_PIECE },
            { type: this.RED_PIECE }
        ];
    var rotationValue = 0.786;
    var plIndex = -1;

    var levelCount = 5;
    var collider = [];
    var platGroupArr = [];
    var colliderGroupArr = [];
    var platformPiece;
    
    var randomPlatform = [
        {
            count: 1,
            rotation: [1.3],
            type: [0]

        },
        {
            count: 5,
            rotation: [2.8, 4.8, 5.8, 7.8, 0.8],
            type: [1, 0, 0, 1, 0]
        },
        {
            count: 3,
            rotation: [7.2, 6.2, 3.6],
            type: [0, 0, 1]
        },
        {
            count: 2,
            rotation: [0.2, 2.2],
            type: [0, 1]
        },
        {
            count: 5,
            rotation: [0.9, 2.9, 3.9, 4.9, 6.9, ],
            type: [1, 0, 1, 0, 0]
        },
        {
            count: 5,
            rotation: [0, 1, 2.3, 4.1, 6],
            type: [1, 0, 1, 0, 1]
        }

    ];

    for (var a = 0; a < levelCount; a++) {

        ++plIndex;
        if (plIndex >= randomPlatform.length) {
            plIndex = 0;
        }

        platGroupArr = [];
        colliderGroupArr = [];

        var type = randomPlatform[plIndex].type;

        for (var i = 0; i < randomPlatform[plIndex].count; i++) {
            
            if (platformPieceType[type[i]].type === this.RED_PIECE)
                platformPiece = this.redPlatform.clone();
            else
                platformPiece = this.greenPlatform.clone();

            platformPiece.position.set(0, 0, 0);

            collider = [];

            collider.push(new THREE.Mesh(new THREE.BoxGeometry(1, 1, 0.2),
             this.materials.solid));
            collider[0].position.set(-1.83, -0.22, 1.11);
            collider[0].rotation.x += Math.PI / 2;
            collider[0].rotation.z -= 0.78;
            collider[0].receiveShadow = true;
            collider[0].visible = this.MESH_VISIBILTY;
            collider[0].platformType = platformPieceType[type[i]].type;
        
            collider.push(new THREE.Mesh(new THREE.BoxGeometry(1, 1, 0.2), 
                this.materials.solid));
            collider[1].position.set(-2.15, -0.22, 0.51);
            collider[1].rotation.x += Math.PI / 2;
            collider[1].receiveShadow = true;
            collider[1].visible = this.MESH_VISIBILTY;
            collider[1].platformType = platformPieceType[type[i]].type;

            var platGroup = new THREE.Group();
            platGroup.add(platformPiece);
            platGroup.add(collider[0]);
            platGroup.add(collider[1]);
            platGroup.rotation.y -= randomPlatform[plIndex].rotation[i] * rotationValue;
            platGroup.position.y -= (a * yDiff);
            this.cylinderGroup.add(platGroup);

            platGroupArr.push(platGroup);

            colliderGroupArr.push(collider[0]);
            colliderGroupArr.push(collider[1]);
        }
        this.platformArr[a * 2] = platGroupArr;
        this.colliderArr[a * 2] = colliderGroupArr;
    }
}

So far random platforms and colliders are added. Next, we have to rotate the cylinder to span all the platforms.

Cylinder Rotation

We will rotate our cylinder using arrow keys ( left arrow and right arrow ) of the keyboard.
Add key listener and update it.

function update() {
    requestAnimationFrame(update);
    Game.renderer.render(Game.scene, Game.camera);
    Game.updateKeyboard();
}

var keyboard = {};
Game.updateKeyboard = function() {
    if (!this.gameOver) {
        if (keyboard[37]) { // left arrow key
            this.cylinderGroup.rotation.y -= this.player.rotateSpeed;
        }

        if (keyboard[39]) { // right arrow key
            this.cylinderGroup.rotation.y += this.player.rotateSpeed;
        }
    }
}

window.addEventListener('keydown', function(event) {
    keyboard[event.keyCode] = true;
});

window.addEventListener('keyup', function(event) {
    keyboard[event.keyCode] = false;
});

This is the end for this part. In the next part, we will add Physics to our game and make the ball jump infinitely.

Where to go from here? ( Part4 of the tutorial )

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.