// Cloned by Joe Rathborne on 11 Nov 2018 from World "MineCraft" by Starter user
// Please leave this clone trail here.
// ==== Starter World ===============================================================================================
// (c) Ancient Brain Ltd. All rights reserved.
// This code is only for use on the Ancient Brain site.
// This code may be freely copied and edited by anyone on the Ancient Brain site.
// This code may not be copied, re-published or used on any other website.
// To include a run of this code on another website, see the "Embed code" links provided on the Ancient Brain site.
// ==================================================================================================================
// "MineCraft" World
// User adds blocks using arrows and Page Up/Down
// Demo of World "save data to server" and restore:
// If you run this logged in you can save your work and restore it
// user_span1 - Instructions
// user_span2 - Save button
// user_span3 - Restore button
// --- nextStep not used: ------------------------
// not using nextStep to drive it
// all actions are taken whenever user hits keys and not any other time
// --- mobile and audio notes: ------------------------
// does not work on mobile (no keyboard)
// if change it to mobile, check that touch event can trigger audio
// ===================================================================================================================
// === Start of tweaker's box ========================================================================================
// ===================================================================================================================
// The easiest things to modify are in this box.
// You should be able to change things in this box without being a JavaScript programmer.
// Go ahead and change some of these. What's the worst that could happen?
AB.clockTick = 100;
// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps = 1000000;
// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep = 50;
// Take screenshot on this step. (All resources should have finished loading.) Default 50.
AB.drawRunControls = false;
// Scrap the Run/Step/Pause controls
const FILE_ARRAY = [
"/uploads/starter/minecraft.1.jpg",
"/uploads/starter/minecraft.2.jpg"
];
const SOUND_BLOCK = '/uploads/starter/chamber.mp3' ;
// sound effect credit:
// http://soundbible.com/1399-Chambering-A-Round.html
const SKYCOLOR = 0xffffff; // a number, not a string
const objectsize = 300 ;
const MAXPOS = 4000 ;
const startRadiusConst = MAXPOS * 0.5 ; // distance from centre to start the camera at
const maxRadiusConst = MAXPOS * 5 ; // maximum distance from camera we will render things
//--- change ABWorld defaults: -------------------------------
ABHandler.MAXCAMERAPOS = MAXPOS * 50 ; // allow camera go far away
ABWorld.drawCameraControls = false;
// ===================================================================================================================
// === End of tweaker's box ==========================================================================================
// ===================================================================================================================
// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.
// --- start of World class --------------------------------------------------------------
function World()
{
var cx, cy, cz; // current location
var textureArray = new Array ( FILE_ARRAY.length );
// keep array of blocks, can save this to server:
var BLOCKARRAY = []; // start with empty array
function loadResources() // asynchronous file loads - call initScene() when all finished
{
for ( var i = 0; i < FILE_ARRAY.length; i++ )
startFileLoad ( i ); // launch n asynchronous file loads
}
function startFileLoad ( n ) // asynchronous file load of texture n
{
var loader = new THREE.TextureLoader();
loader.load ( FILE_ARRAY[n], function ( thetexture )
{
thetexture.minFilter = THREE.LinearFilter;
textureArray[n] = thetexture;
if ( asynchFinished() ) init();
});
}
function asynchFinished() // all file loads returned
{
for ( var i = 0; i < FILE_ARRAY.length; i++ )
if ( ! textureArray[i] )
return false;
return true;
}
function init() // called when all textures ready
{
// create one box to start
var shape = new THREE.BoxGeometry( objectsize, objectsize, objectsize );
var theobject = new THREE.Mesh( shape );
theobject.position.x = 0;
theobject.position.z = 0;
theobject.position.y = 0;
cx = theobject.position.x; // current position
cy = theobject.position.y;
cz = theobject.position.z;
ABWorld.scene.add(theobject);
BLOCKARRAY.push ( theobject.position ); // add to array of blocks
paintThis ( theobject );
// can start the run loop
ABRun.runReady = true;
}
function drawFromArray (a) // clear scene and draw blocks restored from array
{
// clear scene (remove all scene.children)
while ( ABWorld.scene.children.length )
{
ABWorld.scene.remove ( ABWorld.scene.children[0] );
}
for ( var i=0; i < a.length; i++ )
{
var shape = new THREE.BoxGeometry( objectsize, objectsize, objectsize );
var theobject = new THREE.Mesh( shape );
theobject.position.x = a[i].x;
theobject.position.y = a[i].y;
theobject.position.z = a[i].z;
ABWorld.scene.add(theobject);
paintThis ( theobject );
}
i = a.length - 1; // current position will be position of last block
cx = a[i].x;
cy = a[i].y;
cz = a[i].z;
BLOCKARRAY = a;
playBlockSound();
}
function paintThis( object ) // paint objects with random textures
{
var t = AB.randomIntAtoB ( 0, textureArray.length - 1 ); // random texture
object.material = new THREE.MeshBasicMaterial ( { map: textureArray[t] } );
}
// key handling function
// we will handle these keys:
var OURKEYS = [ 33, 34, 37, 38, 39, 40 ];
function ourKeys ( event ) { return ( OURKEYS.includes ( event.keyCode ) ); }
function handleKeyDown ( event )
{
if ( ! ABRun.runReady ) return true; // not ready yet
// if not one of our special keys, send it to default key handling:
if ( ! ourKeys ( event ) ) return true;
// else handle key and prevent default handling:
// make new block:
var shape = new THREE.BoxGeometry( objectsize, objectsize, objectsize );
var theobject = new THREE.Mesh( shape );
theobject.position.x = cx; // default position is current position - going to then move it
theobject.position.y = cy;
theobject.position.z = cz;
if ( event.keyCode == 37 ) theobject.position.x = cx - objectsize ; // left
if ( event.keyCode == 39 ) theobject.position.x = cx + objectsize ; // right
if ( event.keyCode == 38 ) theobject.position.z = cz - objectsize ; // forward
if ( event.keyCode == 40 ) theobject.position.z = cz + objectsize ; // back
if ( event.keyCode == 34 ) theobject.position.y = cy - objectsize ;
if ( event.keyCode == 33 ) theobject.position.y = cy + objectsize ;
cx = theobject.position.x; // current position is now this
cy = theobject.position.y;
cz = theobject.position.z;
ABWorld.scene.add(theobject);
BLOCKARRAY.push ( theobject.position ); // add to array of blocks
paintThis ( theobject );
playBlockSound();
event.stopPropagation(); event.preventDefault(); return false;
}
this.newRun = function()
{
ABRun.runReady = false;
ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );
if ( AB.onDesktop() )
{
$("#user_span1").html( "<p> Instructions: Draw blocks using Arrow keys and PgUp, PgDn. <br> Drag and scroll camera to move and zoom. </p>" );
if ( AB.runloggedin )
{
// Definitely can save, not sure if can restore:
$("#user_span2").html ( " <button onclick='AB.saveData();' >Save your work</button> " );
// Check if any data exists, if so make restore button:
AB.queryDataExists(); // will call World.queryDataExists when done
}
else
$("#user_span2").html( " <p> To be able to save and restore your work, log in and run this from the World page. </p> " );
}
else
$("#user_span1").html( "<p> This World currently only works on desktop. </p>" );
loadResources(); // aynch file loads
// calls init() when it returns
// set up the main key handler:
document.addEventListener( 'keydown', handleKeyDown );
};
this.nextStep = function() // not used
{
};
// --- save and restore data -----------------------------------------
this.saveData = function() // defines what object to save to server
{
// if no restore button, can make one now
$("#user_span3").html ( " <button onclick='AB.restoreData();' >Restore your work</button> " );
// console.log ( "Saving " + BLOCKARRAY.length + " blocks to server" );
return ( BLOCKARRAY );
};
this.restoreData = function ( a ) // process object returned from server
{
// console.log ( "Restoring " + a.length + " blocks from server" );
drawFromArray (a);
};
this.queryDataExists = function ( exists )
{
if ( exists )
$("#user_span3").html ( " <button onclick='AB.restoreData();' >Restore your work</button> " );
};
}
// --- end of World class --------------------------------------------------------------
// --- audio --------------------------------------------------------------
function playBlockSound()
{
var audio = new Audio( SOUND_BLOCK );
audio.play();
}