Code viewer for World: Joe's Minecraft

// 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();
}