Code viewer for World: Ch.3. 2D grid.
 
// Over a few chapters, we are working up to a "Battleship" style Websocket game.

// Ch.3
// A 2D grid of boxes. (Our own 2D space inside the bigger Three.js 3D "pixel" space.)

// Introduces a "for" loop.

// this introduces a "for" loop, inside of which is another "for" loop - slightly advanced
// so we suggest you take a break first and go to w3schools and experiment with a basic "for" loop
// https://www.w3schools.com/js/js_loop_for.asp

 


// === start of code ===========================================================================================================


// --- const (constants) --------------------------------------

// we are going to define sizes of things all in one place, so they can be easily changed
// rather than having them scattered through code

const gridsize 		= 15;							// number of squares along side of world	   
const squaresize 	= 100;							// size of square in pixels

const MAXPOS 		= gridsize * squaresize;		// length of one side in pixels 

const startRadiusConst	 	= MAXPOS * 1 ;		    // distance from centre to start the camera at
const maxRadiusConst 		= MAXPOS * 5 ;			// maximum distance from camera we will render things  
	
const SKYCOLOR 		= 'lightyellow';			    // define sky colour in this section 


 const TEXTURE_WALL 	= '/uploads/chapters/stone.png' ;
 const TEXTURE_SHIP 	= '/uploads/chapters/ship.png' ;
 
// credit:
// https://commons.wikimedia.org/wiki/File:Square_stone_brick_Texture.jpg
// https://commons.wikimedia.org/wiki/File:Regina_Maris.JPG

	 

// --- var (variables) --------------------------------------

var wall_texture, ship_texture; 


 
	ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 

	loadTextures();		 	 
							
    AB.msg ( "Drag and scroll the mouse to move and zoom the camera.");				
    
    
	
function loadTextures()		  
{
	var loader1 = new THREE.TextureLoader();
	var loader2 = new THREE.TextureLoader();
		
	loader1.load ( TEXTURE_SHIP, function ( texture )  	 
	{
		ship_texture = texture;                  
		if ( wall_texture )	makeEverything();		// if both textures have loaded we can make everything 
	});	

	loader2.load ( TEXTURE_WALL, function ( texture )  		
	{
		wall_texture = texture;                  
		if ( ship_texture )	makeEverything();		  
	});	
}




//--- my 2D grid system -------------------------------------------------------------------------------
// Three.js uses (x,y,z) coordinates
// first I want a 2D grid so height parameter will always be zero
// in fact this is the y parameter

// second, if, say, I have 15 blocks on each side, I will do numbering 0 to 14
// so I will give my blocks locations (0,0), (0,1) ... (0,14), (1,0), (1,1) ... (14,14)
// we need to map my addressing system to the Three.js addressing system

function translate ( i, j )			// convert point (i,j) in my 2D system to a point in Three.js space 
{
	var v = new THREE.Vector3();
	
	v.y = 0;	
	v.x = i * squaresize ;   		 
	v.z = j * squaresize ;   	
	
	return v;
}


	
function makeEverything()		 
{
    makeWalls();
    makeShips();
}


function makeWalls()
{
	var i,j, shape, thecube, position;
	shape    = new THREE.BoxGeometry ( squaresize, squaresize, squaresize );			 
	 
	// to make the walls we could say:
	// make wall at (0,0)
	// make wall at (0,1)
	// ...
	// make wall at (0,14)
	// ... etc.
	// but this is a lot of repetitive code 
	
    // a "for" loop can help to make the code much shorter 
    // a "for" loop typically: goes through all items, executing some code for each one 
    // https://www.w3schools.com/js/js_loop_for.asp

    // also seen here is an "if" statement using the "or" operator ||
    // https://www.w3schools.com/js/js_comparisons.asp
    
	 for ( i = 0; i < gridsize ; i++ )          // for i taking values (0,1, .. gridsize-1), for example (0,1, .. 14)
	  for ( j = 0; j < gridsize ; j++ ) 
	  {                                         // --- start of block of code to run for every i,j combination 
		if ( ( i==0 ) || ( i==gridsize-1 ) || ( j==0 ) || ( j==gridsize-1 ) )       // if i or j indicate we are at one of the edges  
		{
			thecube = new THREE.Mesh( shape );
			thecube.material = new THREE.MeshBasicMaterial( { map: wall_texture } );
			position = translate(i,j);              // translate this position to Three.js space 
			thecube.position.copy ( position ); 		
			ABWorld.scene.add(thecube);
		}
	  }                                         // --- end of block of code to run for every i,j combination 
}

 
function makeShips()    // make one or more ships 
{
	 var  shape, thecube, position;
	 shape = new THREE.BoxGeometry ( squaresize, squaresize, squaresize );	
	 
	 thecube = new THREE.Mesh( shape );
 	 thecube.material =  new THREE.MeshBasicMaterial( { map: ship_texture } );
 	 position = translate ( 4, 8 );     // put ship somewhere in the grid - can change this 
 	 thecube.position.copy ( position ); 
	 ABWorld.scene.add(thecube);
}
 
 
// === end of code ===========================================================================================================




 
// Exercises:
// Change the size of the grid.
// Change the "for" and "if" statements to make other configurations of wall blocks.
// Make ship bigger than one box. Put ship image on 3 to 5 boxes in a row 
// Advanced exercise: Change the ship to a position that changes as the grid size changes. Like 1/3 of the way down, 2/3 of the way across. 
// Advanced exercise: Make the wall layout actually 3D. Make a cube of walls using a "for" loop. 


// Outcomes: Student can:
// Learn how to use a "for" loop.
// Learn how to use "if" with an "or" operator.
// Learn how to use equality and less than / greater than checks. 
// Learn how to make one's own addressing on a 2D grid.
// Learn how to map a 2D grid to a 3D space like Three.js.