Code viewer for World: Castle World (clone by Ale...

// Cloned by Alexandru on 1 Dec 2022 from World "Castle World" by Starter user 
// Please leave this clone trail here.
 



// ==== 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.
// ====================================================================================================================




// Demo of 3D model
// OBJ plus MTL

// A "Simple World" like chase inside an invisible arena inside the castle 
// Chase uses x,y,z rather than grid of squares 


  
  
  

// ===================================================================================================================
// === 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.  
	
AB.maxSteps        = 500;    

	// Length of run: Maximum length of run in steps.  

AB.screenshotStep  = 50;   
  
	// Take screenshot on this step. (All resources should have finished loading.)  

	

//---- global constants: -------------------------------------------------------

	const OBJPATH = "/uploads/starter/";	// path of OBJ and MTL 
	const OBJNAME = "castle.obj";
	const MTLNAME = "castle.new.mtl";

// castle credit
// https://www.script-tutorials.com/webgl-with-three-js-lesson-6/
// http://www.script-tutorials.com/demos/409/index2.html


// =================================================================================
// Bug: Original MTL file fails with new Three.js  
// The original "castle.mtl" works with old Three.js but fails with new version.
// Solution: Edit the MTL file. See note here:
// https://ancientbrain.com/docs.three.php
// =================================================================================




	const TEXTURE_AGENT 	= '/uploads/starter/pacman.jpg' ;
	const TEXTURE_ENEMY 	= '/uploads/starter/ghost.3.png' ;

// credits:
// https://commons.wikimedia.org/wiki/Category:Pac-Man_icons
// https://commons.wikimedia.org/wiki/Category:Skull_and_crossbone_icons
	
	const MUSIC_BACK  = '/uploads/starter/Defense.Line.mp3' ;
	
	
const SKYCOLOR 		= 0xffffcc ;				// a number, not a string 
const LIGHTCOLOR 	= 0xffffff ;

const squaresize 	= 50;							// size of cube length 


// basic castle model size 
// see debug line to compute model size below 
// Xsize: 6158.792236328125 Ysize: 703.5784759521484 Zsize: 3791.05908203125

const MODELLENGTH 			= 6159;							
const MODELWIDTH			= 3791; 

const SCALE_CASTLE			= 0.5;							// scale it by this		 
const SCALEDMODELLENGTH 	= MODELLENGTH * SCALE_CASTLE;	 			 
const SCALEDMODELWIDTH	 	= MODELWIDTH  * SCALE_CASTLE;	 			 

const startRadiusConst 		= SCALEDMODELLENGTH * 0.5 ; 
const maxRadiusConst 		= SCALEDMODELLENGTH * 10 ; 


	// camera points at 0,0 
	// where to put castle? 
	// fit bottom LHS corner to here:
	
	const CX 	= - ( SCALEDMODELLENGTH * 0.3 );		 
	const CZ 	=   ( SCALEDMODELWIDTH  * 0.3 );		 

	
// how far can the agent and enemy wander inside the castle
// experiment to see where the inner box fits inside the model 

const MIN_X 	= CX + ( SCALEDMODELLENGTH * 0.1 ) ;
const MAX_X		= CX + ( SCALEDMODELLENGTH * 0.55 ) ;

const MIN_Z 	= CZ - ( SCALEDMODELWIDTH * 0.45 ) ;
const MAX_Z		= CZ - ( SCALEDMODELWIDTH * 0.1 ) ;



//--- change ABWorld defaults: -------------------------------

ABHandler.GROUNDZERO		= true;						// "ground" exists at altitude zero

ABWorld.drawCameraControls = false; 

var thecastle

	

function loadResources()		// asynchronous file loads - call initScene when finished 
{

	// load castle model OBJ and materials MTL (which reference JPEGs)
	
	var m = new THREE.MTLLoader();
	m.setResourcePath ( OBJPATH );
	m.setPath         ( OBJPATH );
	
	m.load ( MTLNAME, function ( materials ) 
	{
		materials.preload(); 
		var o = new THREE.OBJLoader();
		o.setMaterials ( materials );
		o.setPath ( OBJPATH );
		
		o.load ( OBJNAME, function ( object ) 
		{
			thecastle = object;
			if ( asynchFinished() )	initScene();		 
		});
	});
	
	
	// load cube textures 
	var loader1 = new THREE.TextureLoader();
	var loader2 = new THREE.TextureLoader();
		
	loader1.load ( TEXTURE_AGENT, function ( thetexture )  	 
	{
		thetexture.minFilter  = THREE.LinearFilter;
		agent_texture = thetexture;
		if ( asynchFinished() )	initScene();		 
	});	
	
	loader2.load ( TEXTURE_ENEMY, function ( thetexture )  
	{
		thetexture.minFilter  = THREE.LinearFilter;
		enemy_texture = thetexture;
		if ( asynchFinished() )	initScene();		 
	});
}


function asynchFinished()		 
{
	if ( thecastle )  return true;  
	else return false;
}	
	
	
	



function initScene()		// file loads have returned 
{
	
 // add castle object to scene  

	thecastle.scale.multiplyScalar ( SCALE_CASTLE );    	  

    thecastle.position.y = - (squaresize * 0.5);				// adjust so cubes (centred on 0) appear exactly above castle floor 
    thecastle.position.x = CX;
    thecastle.position.z = CZ;  
 
   	ABWorld.scene.add ( thecastle );
			
	// calculate OBJ object size:
	//	console.log ( "Xsize: " + ABWorld.objectXsize(thecastle) + " Ysize: " + ABWorld.objectYsize(thecastle) + " Zsize: " + ABWorld.objectZsize(thecastle) );

	 
 // ready to start run loop? 
	
	ABWorld.render();

	console.log ( "Resources loaded." );
	resourcesLoaded = true;
	
	if ( resourcesLoaded && splashClicked ) 
		AB.runReady = true;  		// start run loop 
	
}





AB.world.newRun = function() 
{

	ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 

	// newRun can run behind splash screen 
	// do not start run loop until resources ready AND splash screen is dismissed 
	
	AB.runReady = false; 
	
	loadResources();		// aynch file loads		
							// calls initScene() when it returns 
 
    var thelight = new THREE.DirectionalLight ( LIGHTCOLOR, 5 );
    thelight.position.set ( startRadiusConst, startRadiusConst, startRadiusConst );
    ABWorld.scene.add(thelight);
		
};


// --- Splash screen --------------------------------------------------------------
// Splash screen is to get audio started on mobile/Chrome by user interaction.
// This should works on all platforms - plays background music.

	
	// display standard splash screen (World title, World image, Start button) 
	
	AB.newSplash();

	
	// when user clicks/touches button on splash screen, audio starts and run starts:
		
	AB.splashClick ( function ()        
	{
		// audio linked to user interaction:  
		AB.backgroundMusic ( MUSIC_BACK );	
		
		AB.removeSplash();			// remove splash screen 
		
		// ready to start run loop? 
		
		splashClicked = true;
		
		if ( resourcesLoaded && splashClicked ) 
			AB.runReady = true;  		// start run loop 
		
	});