How to create a simple totem destroyer prototype in 3d space with 2d physics. Actually it’s the same process as doing a totem destroyer in 2d, instead of 2d sprites we use 3d objects. First off, take a look at a totem destroyer game, this one is the most basic version TotemDestroyer. As you can see, a very basic game concept and still very enjoyable.
The P2.js physics engine will handle all the physics and collision detection events, all we have to do is to create a level to play with. In this case we will use a free vector drawing software called Inkscape to create many levels easy and fast.
Prepare Inkscape
We use Inkscape as level editor, Inkscape will export an xml file with all the layers and objects we have created. We can also add custom information to any object such as, is it destructible, is it a target or the ground plane. All this features make Inkscape perfect as level editor for a totem destroyer game.
There are a few things to keep in mind while using Inkscape as level editor.
Once Inscape is prepared, it’s fairly easy to create a level. Each layer of the document defines a new level in the final game. Make sure you are on the right layer, enable snapping for precise positioning, start draw some rectangles and create a fun level. Define a target zone, in this case with an id called “ground”. Also create an object which should finally land and stop on that position with an id called “target”. We use this objects later on to define if the player finished the level or not.
Load levels
Load a SVG file with a simple loader, once loaded we can create levels based on that data. The SVG file has the center point on the bottom left, the 3d world has the center point top center. To align the objects properly we have to offset all the position values.
//ADD XML LOADER
var xhttp = new XMLHttpRequest();
xhttp.open("GET","assets/levels.svg",false);
xhttp.onload = parseSVG;
xhttp.send();
//GET ALL LAYERS/LEVELS FROM SVG
function parseSVG()
{
//GET ALL LAYERS/LEVELS
var layers = xhttp.responseXML.getElementsByTagName("g");
//SELECT FIRST LEVEL
var selected = layers[0]
//GET AN ARRAY OF RECTS IN SELECTED LEVEL
var level = selected.getElementsByTagName("rect");
//NEXT -> CREATE 2D/3D OBJECTS
};
//SVG OFFSET VALUES
var mirrorY = xhttp.responseXML.getElementsByTagName("svg")[0].getAttribute("height"); //MIRROR Y VALUE
var centerX = xhttp.responseXML.getElementsByTagName("svg")[0].getAttribute("width")/2; //MOVE TO CENTER X
User input
Handles user input for touch and mouse events.
//ADD CLICK EVENT
renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
renderer.domElement.addEventListener( 'touchstart', onDocumentMouseDown, false );
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onDocumentMouseDown( event ) {
event.preventDefault();
//IS TOUCH OR CLICK EVENT
if(event.type == 'mousedown')
{
mouse = new THREE.Vector2(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1
);
}
else
{
mouse = new THREE.Vector2(
( event.touches[0].clientX / window.innerWidth ) * 2 - 1,
- ( event.touches[0].clientY / window.innerHeight ) * 2 + 1
)
};
//SEND RAY IN 3D SPACE
raycaster.setFromCamera( mouse, camera );
//GET OBJECTS IN TOUCH/CLICK POSITION
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
//CHECK IF OBJECT CAN BE DESTROYED
if(intersects[0].object.name == "cube" && !intersects[0].object.data.target)
{
//PREPARE TO REMOVE 2D OBJECT
removeBodys.push(intersects[0].object.data);
//REMOVE 3D OBJECT
scene.remove( intersects[0].object );
//AWAKE EACH BODY IN P2 WORLD
for (var i = 0; i < world.bodies.length; i++)
{
world.bodies[i].wakeUp()
}
};
};
};
Conclusion
While this is still a raw prototype, it already has a lot of code to study and understand. Once the code is separated into render, game logic and object scripts, the actual game script will be just a few line of code.
It’s still a really simple script and if everything is set up correctly, creating multiple levels is fast and easy.