SpaceDebris


 

The main focus in this project was to use Blender as a model and level designer. Export the scene from Blender to HTML with the threeJS exporter. Prepare the scene to access each object by name and animate them properly with javascript. With this kind of visual editing you can create plenty of levels in almost no time.

To keep things as simple as possible we don’t care too much about GUI, sound and beauty. It’s still a complex scene and it needs some time to understand fully whats happening. Im gonna to explain the main concept of the scripting and modeling tasks. Download the fully commented source code and the Blender file to get more details and see exactly whats going on.

Everything is canvas based so it can easily be ported to any language.

 

overview

Once you have downloaded the source code. The project files are under js/scene/, the blender files are under js/blenderScene/.

 

JS_file

load_screen.js

Create the loadscreen and update it accordingly to the loaded percentage.Also add the introduction if load has finished.

JS_file

load_blenderScene.js

Init the threeJS render. Load the Blender scene.

JS_file

init_blenderScene.js

Once the loading process has finished we group and prepare the loaded objects.

JS_file

init_player.js

Init the player and add some properties like speed, position, lives, fuel etc..

JS_file

init_particleSystem.js

A basic particle system for the thruster and explosion effect.

JS_file

init_gameMechanics.js

Check for collisions, add explosions, update Player, check for collectables, etc..

JS_file

init_GUi.js

Prepare and update the GUI.

 

 

Blender

Blender was used for modeling, texturing and level design. If you don’t know Blender make sure you check it out. It’s a beautiful piece of software, free and open-source. ThreeJS also provides exporters for other 3d software.

Im not going to explain the model and texturing process. There are so many good tutorials that explains how to model and texture with Blender.

 

Just a few things to keep in mind while modeling assets for a 3d game environment with threeJS.

– Name everything properly to access the objects and materials later

– UV unwrap all the object in the scene

– Group things together

– Use the same geometry as often as possible

– Add collision bounds for faster collision detection

– Keep the polycount low

– Texture size

 

There are not many options in Blender which effects the threeJS exporter. Start with a simple scene and test all the options to see what you get.SD_blender_options

 

threeJS

Wikipedia: “Three.js is a lightweight cross-browser JavaScript library/API used to create and display animated 3D computer graphics on a Web browser.”

We use threeJS to import and display the Blender scene in the web-browser. Before we can access any of the models we have to load the main scene file we have exported from blender.

function load_blenderFile()
{
     //Create Scene loader and add while_load(callbackProgress) and end_load(callbackFinished) events
    var loader = new THREE.SceneLoader();
    loader.callbackProgress = callbackProgress;

    //Scene to load
    loader.load( "js/blenderScene/level_1.js", callbackFinished );
}

function callbackProgress( progress, result ) 
{

    total = progress.totalModels + progress.totalTextures; //Get the total amount of models an materials to load
    loaded = progress.loadedModels + progress.loadedTextures; //Get the amount of already loaded models an materials

    if ( total )
    { 
        //Get percentages of loaded elements back
        bar = Math.floor( loaded / total * 100 );
    }

    initLoadscreen(bar); //Update the loading bar each time it changes

    count = 0;
    //load each material by passing them to the handle_update function
    for ( var m in result.materials ) count++;
    handle_update( result, Math.floor( count/total ) );

}

//Load progress has finished
function callbackFinished( result ) 
{

    loadedObjects = result;

    //Display the render canvas from threeJS
    document.getElementById("canvas_threeJS").style.opacity = 1;
    introduction();

    //Get all the groups we have created in Blender and pass each of them to the array of groups
    groups = result.groups;

//    console.log(groups) //DEBUG   Log the name of each group you import
//    console.log(result.geometries) //DEBUG    Keep controll of what geometries you load. Best practice to use the same geometrie multiple times
//    console.log(scene) //DEBUG    Log the whole scene to know exactly whats rendered  

    //Get Name of each object and add them to the scene
    for( var name in result.objects ) 
    {            
//        console.log(result.objects[name].name) //DEBUG    Log the name of each object you import
        mesh = result.objects[name];

        scene.add(mesh); //Add each object to the scene
    }

//     scene.add(result.scene); //Instead of add each object seperate to the scene just replace the existin scene with the loaded one

    //to Access any object by name
//    result.objects["Ship_Head.001"].position.set(0,1,0)

    //if everything loaded correctly go on with game mechanics
    init_blenderScene();//Preparing the loaded objects to be animated
    init_player();//Preparing the Player_Ship

}

function handle_update( result, pieces ) {

                //Load material for each object
				var m,g, material, count = 0;
                //For each material we have found
				for ( m in result.materials ) {

					material = result.materials[ m ];
					if ( ! ( material instanceof THREE.MeshFaceMaterial ) ) {

						if( !material.program ) { 
                            renderer.initMaterial( material, result.scene.__lights);

                        //Map the texture correctly if it is repeated
                        if(material.map){ material.map.wrapS = material.map.wrapT = THREE.RepeatWrapping;}

                        count += 1;

                        if( count > pieces ) {break;}

						}
					}
                }
}

Once everything is loaded correctly there is some more work to do with the scene. The Blender exporter doesn’t export lights and parent child relationship right now. So we need to add the lights and relationships manual.

Add lights is very easy. Add them to the scene or to a certain object.

//Add the ambient light, since this is not exportet from blender
    var ambientLight = new THREE.AmbientLight(0x003940);
        scene.add(ambientLight)

    //Add a pointlight
    var light = new THREE.PointLight(0xFCFAD9,0.8);
	light.position.set(0,10,10);
        scene.add(light)

The Blender exporter also includes groups and empties. We use this to create a parent child relationship.As we named the group and the empty the same in Blender. We assign now the empty as the parent for each object of the group in Javascript.

 //Loop trough all the diffrent groups
    for( var group in groups ) 
    {
//        console.log(group) //DEBUG    Show all the available groups

        //Check if there is an Empty with the same name as the group
        if(loadedObjects.objects[group])
        {   
            //If so, parent all the elements to the empty
            for (var i=0;i<groups[group].length;i++)
            { 
                loadedObjects.objects[group].add(loadedObjects.objects[groups[group][i]]); //Add the groupped objects to the parent
                //Set the new position relative to its parent
                newPos = loadedObjects.objects[groups[group][i]].position.subVectors(loadedObjects.objects[groups[group][i]].position,loadedObjects.objects[group].position); 

                loadedObjects.objects[group].quaternion.set(0,0,0,0); //Reset any rotation
            }

        }

 

game mechanics

In this game we don’t use any additional libraries for physics or any game engine. We only care about player movement and collision detection which is actually a really simple task. We just use a standard player movement script.

var power = 0.02;
var yspeed = 0;
var xspeed = 0;
var friction = 0.99;
var gravity = 0.0015;

function checkKey(e) {

    e = e || window.event;

    if (e.keyCode == '38') {
        // up arrow
        yspeed -= power;
    }
    else if (e.keyCode == '40') {
        // down arrow
        yspeed += power;
    }
    else if (e.keyCode == '37') {
        // left arrow
        xspeed -= power;
    }
    else if (e.keyCode == '39') {
        // right arrow
        xspeed += power;
    }
}

function update_Player() //Rendertick
{   
    //Update Player position
    if(xspeed != 0 || yspeed != 0 )
    {
        yspeed -= gravity;
        xspeed *= friction;
        yspeed *= friction;
        player.position.y += yspeed;
        player.position.x += xspeed;
    }
}

For collision detection we use the threeJS raycaster. The raycaster shoot rays in every direction and check if they collide with anything and how great the distance is.

var collidableMeshList = []; //Array of objects which cause collision with the player

function collisionDetection()
{   
    var originPoint = player.position.clone(); //The object to check if it collides
    for (var vertexIndex = 0; vertexIndex < loadedObjects.objects["col_Ship_Head.001"].geometry.vertices.length; vertexIndex++)
	{		
		var localVertex = loadedObjects.objects["col_Ship_Head.001"].geometry.vertices[vertexIndex].clone();
		var globalVertex = localVertex.applyMatrix4( loadedObjects.objects["col_Ship_Head.001"].matrix );
		var directionVector = globalVertex.sub( loadedObjects.objects["col_Ship_Head.001"].position );
		var ray = new THREE.Raycaster( originPoint, directionVector.clone() );

		var collisionResults = ray.intersectObjects( collidableMeshList );
		if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) 
                // COLLISION DETECTED
               { 
               }
        }
}

 

conclusion

ThreeJS combined with Blender is a very powerful tool. You could even export animated models. Add a game engine and a physics simulator to it and it gets awsome. With this practice you could create A+ games without any cost, all you need is time to create.

 

tools

icn_blender

icn_gimp-150x150

icn_Audacity