// ==== Starter World =================================================================================================// This code is designed for use on the Ancient Brain site.// This code may be freely copied and edited by anyone on the Ancient Brain site.// To include a working run of this program on another site, see the "Embed code" links provided on Ancient Brain.// ====================================================================================================================// "MineCraft" World // User adds blocks using arrows and Page Up/Down // --- nextStep not used: ------------------------ // we do not define any AB.world.nextStep // all actions are taken whenever user hits keys and not any other time// --- mobile: ------------------------ // does not work on mobile (no keyboard)// --- Demo of everything to do with "logged in" runs: ---------------------------------------------------------------// If you run this logged in you can save your work and restore it. // Whether logged in or not, splash screen shows "scoreboard" of all users' creations, and allows load of any. // ===================================================================================================================// === 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 controlsconst 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.htmlconst 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 atconst 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.// can write CSS to page // document.write (of CSS at least) is good at the moment we include the JS, not later
document.write (`<style>.mybutton
{
border-radius:0px;
background-color: darkslategrey;}.mybutton:hover { background-color: darkcyan;}</style>`);// global array of all user data var allData;var splashClicked =false;var cx, cy, cz;// current location var textureArray =newArray( 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])returnfalse;returntrue;}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 );if( splashClicked )
AB.runReady =true;// start run loop }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(! AB.runReady )returntrue;// not ready yet // if not one of our special keys, send it to default key handling:if(! ourKeys ( event ))returntrue;// 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 ;// leftif( event.keyCode ==39) theobject.position.x = cx + objectsize ;// rightif( event.keyCode ==38) theobject.position.z = cz - objectsize ;// forwardif( 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();returnfalse;}//--- Scoreboard on splash screen --------------------------------------------------------function shortstring ( str )// If doing a scoreboard, the data changes as users change.// You need to consider unusual data, such as very long user name.{return( str.substring (0,30));// first n characters of string }// sort the results of getAllData// this will be World-specific function mysort (a,b)// how to compare two objects in the getAllData array // array of items ( userid, username, object )// sort by object length (no. of blocks){var alen = a[2].length;var blen = b[2].length;if( alen == blen )return0;if( alen > blen )return-1;if( alen < blen )return1;}function makeSplash ( a )// replace splash screen with this HTML// show a "scoreboard" of all users who have saved data // the arg is the array returned by getAllData, an array of items ( userid, username, object ){var html ="<div style='max-width:600px; text-align:left;'>"+"<h1> MineCraft <img width=50 src='/uploads/starter/minecraft.1.jpg'> </h1> ";if( AB.onDesktop()){
html = html +" <p> <b>Instructions:</b> Draw blocks using Arrow keys and PgUp, PgDn. </p> ";if( AB.runloggedin )
html = html +"<p> <b> Logged in: </b> "+// " <a href='https://ancientbrain.com/user.php?userid="+ AB.myuserid + "'>" + shortstring( AB.myusername ) + "</a>. " +" You are running "+" <a href='https://ancientbrain.com/docs.runs.php#runloggedin'>\"logged in\"</a>. "+" You can save your work to the server. </p>";else
html = html +"<p style='background-color:#ffffcc;'> <b> Not logged in: </b> "+" You are not running "+" <a href='https://ancientbrain.com/docs.runs.php#runloggedin'>\"logged in\"</a>. "+" You cannot save your work to the server. To run logged in, log in and run this from the World page. </p> ";}else
html = html +" <p> <b> Warning:</b> This World only works fully on desktop. </p> ";// scoreboard if( a.length ===0){
html = html +"<p> <b> Start: </b> Start MineCraft: <button style='vertical-align:text-bottom' id=splashbutton class=ab-normbutton >Start</button> </p>"+" <p> No user has saved any creations yet. </p>";}else{
html = html +"<p> <b> Start: </b> Start from scratch: <button style='vertical-align:text-bottom' id=splashbutton class=ab-normbutton >Start</button> "+" Or load creation of previous user: </p>"+"<div class=ab-horizontalscroll >"+"<table class=ab-mytable style='background: rgba(238, 255, 255, 1.0);' >"+"<TR> <TD class=ab-headertd> User </td> <TD class=ab-headertd> Number of blocks </td><td class=ab-headertd> Load creation </td></TR>";for(var i =0; i < a.length; i++){
html = html +"<tr><td> <a href='https://ancientbrain.com/user.php?userid="+ a[i][0]+"'>"+ shortstring( a[i][1])+"</a></td>"+"<td>"+ a[i][2].length +"</td>"+"<td> <button onclick='loadCreation("+ i +");' class=ab-normbutton >Load</button> </td></tr>";// "Load" button i will call function to load object i (we have saved a list of all objects in memory)}
html = html +"</table></div>";}return( html +"</div>");}
AB.world.newRun =function(){
AB.runReady =false;// get all data saved for this World for all users// when this returns it makes a splash screen with this info
AB.getAllData ( processAllData );// processAllData is the callback function // can set up scene while waiting for splash screen to be clicked ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );// if logged in, on desktop, put buttons in run div if( AB.onDesktop())if( AB.runloggedin ){// Definitely can save, not sure if can restore:
AB.msg (" <button onclick='saveData();' class='ab-normbutton mybutton' >Save work</button> ");// Check if any data exists, if so make restore button
AB.queryDataExists (function( exists )// asynchronous - need callback function {if( exists ) makeRestoreButton();});}
loadResources();// aynch file loads // calls init() when it returns // set up the main key handler:
document.addEventListener('keydown', handleKeyDown );};function makeRestoreButton(){
AB.msg (" <button onclick='restoreData();' class='ab-normbutton mybutton' >Restore work</button> ",2);}function saveData()// save BLOCKARRAY to server {// if no restore button exists, can make one now // if exists, this just overwrites it
makeRestoreButton();// console.log ( "Saving " + BLOCKARRAY.length + " blocks to server" );
AB.saveData ( BLOCKARRAY );}function restoreData(){
AB.restoreData (function( a ){// object returned from server is an array of blocks // console.log ( "Restoring " + a.length + " blocks from server" );
drawFromArray (a);});}function processAllData ( a )// arg is the array returned by getAllData // makes a splash screen with "scoreboard"{
AB.newSplash();// sort the array to get a sorted "human scoreboard"// the sort will be World specific
a.sort ( mysort );// build splash contents from the array var html = makeSplash ( a );// replace splash contents
AB.splashHtml ( html );
AB.splashClick ( removeSplash );// 'start from scratch' button
allData = a;// global var - save it for later}// load creation i from saved "allData" function loadCreation ( i ){
removeSplash();// now audio is ready
drawFromArray ( allData[i][2]);}function removeSplash(){// touch/click on splash screen marks audio as good for JS to call without further human interaction
audio.play(); audio.pause();
AB.removeSplash();// remove splash screen
splashClicked =true;
AB.runReady =true;// start run loop }// --- audio --------------------------------------------------------------var audio =newAudio( SOUND_BLOCK );function playBlockSound(){
audio.play();}