// ==== 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 Websockets functionality added to a 3D World// Run with two or more users// You have to tell the users the password you will be using// Click button to change a random box's texture on all clients running this World// Pick a side and compete against an opponent!
AB.clockTick =100;// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps =100000;// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep =100;// Take screenshot on this step. (All resources should have finished loading.) Default 50.const FILE_ARRAY =["/uploads/starter/earth.1.jpg",// array 0 to 4 are the earths "/uploads/starter/earth.2.jpg","/uploads/starter/earth.3.jpg","/uploads/starter/earth.4.jpg","/uploads/starter/earth.5.jpg","/uploads/starter/baby.1.png",// array 5"/uploads/starter/ghost.3.png"// array 6 ];const SKYCOLOR =0xFFE4E1;// very light pink // a number, not a string// 0xFFB6C1; // light pink // 0xccffcc; // light green const ARMYSIZE =50;// an "army" of objects const objectsize =500;const WALKSTEP =200;// bounds of the random move per timestep // try 50 (vibrating sheet) versus 1000 (cloud)const MAXPOS =4000;// start things within these bounds const startRadiusConst = MAXPOS *1.5;// distance from centre to start the camera atconst maxRadiusConst = MAXPOS *5;// maximum distance from camera we will render things ABHandler.MAXCAMERAPOS = MAXPOS *10;// allow camera go far away ABWorld.drawCameraControls =false;
AB.drawRunControls =false;var THEARMY =newArray( ARMYSIZE );var textureArray =newArray( FILE_ARRAY.length );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()) initArmy();});}function asynchFinished()// all file loads returned {for(var i =0; i < FILE_ARRAY.length; i++)if(! textureArray[i])returnfalse;returntrue;}function initArmy()// called when all textures ready {var t =0;for(var c=1; c <= ARMYSIZE ; c++){// var shape = new THREE.SphereGeometry ( objectsize, 30, 30 ); var shape =new THREE.BoxGeometry( objectsize, objectsize, objectsize );var theobject =new THREE.Mesh( shape );
theobject.position.x = AB.randomIntAtoB (-MAXPOS, MAXPOS );
theobject.position.z = AB.randomIntAtoB (-MAXPOS, MAXPOS );
theobject.position.y =0;// var r = AB.randomIntAtoB ( 0, textureArray.length - 1 ); // random texture var r = AB.randomIntAtoB (0,4);// random one of the earths
theobject.material =new THREE.MeshBasicMaterial({ map: textureArray[r]});ABWorld.scene.add(theobject);
THEARMY[t]= theobject;// save it for later
t++;}// can start the run loopABWorld.render();
AB.runReady =true;
AB.msg (`<hr><p>Multi-user game.Pick a side.Click buttons to change boxes on all users' machines.Drag the camera.<p><button onclick='baby();'class=ab-largenormbutton >Baby</button><button onclick='skull();'class=ab-largenormbutton >Skull</button><p>`);}function moveArmy()// move all the objects {for(var i =0; i < THEARMY.length; i++){if( THEARMY[i])// in case initArmy() not called yet {
THEARMY[i].position.x = THEARMY[i].position.x + AB.randomIntAtoB(-WALKSTEP,WALKSTEP);
THEARMY[i].position.z = THEARMY[i].position.z + AB.randomIntAtoB(-WALKSTEP,WALKSTEP);
THEARMY[i].position.y = THEARMY[i].position.y + AB.randomIntAtoB(-WALKSTEP,WALKSTEP);ABWorld.scene.add( THEARMY[i]);}}}
AB.world.newRun =function(){
AB.newSplash();
AB.splashHtml (`<h1>Password only Websocket boxes </h1>
A version of Websocket boxes that only certain users can join.<br>You enter a password.You only join with users who enter the same password (not with all users of the World).<br>The first user to run the World can enter any password!But other users must know what password they will use.<p>Enter password:<input style='width:25vw;' maxlength='2000' NAME="p" id="p" VALUE=''><button onclick='start();'class=ab-normbutton >Start</button><p><div id=errordiv name=errordiv></div>`);
AB.runReady =false;ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );
loadResources();// aynch file loads // calls initArmy() when it returns };
AB.world.nextStep =function(){
moveArmy();};//--- start Socket -----------------------------------------------------function start()// user has entered a password {var password = jQuery("input#p").val();
password = password.trim();if(! alphanumeric ( password )){
$("#errordiv").html("<font color=red> <B> Error: Password must be alphanumeric. </b></font> ");return;}// else we have a password, start the socket run with this password
AB.socketStart ( password );
AB.removeSplash();}function alphanumeric ( str )// return if string is just alphanumeric {var rc = str.match(/^[0-9a-zA-Z]+$/);// start of line "[0-9a-zA-Z]+" end of line if( rc )returntrue;elsereturnfalse;}//--- Socket functionality -----------------------------------------------------// functions called by buttons// baby and skull are textures 5 and 6 in the array:function baby(){ changeBox(5); AB.socketOut (5);}function skull(){ changeBox(6); AB.socketOut (6);}function changeBox(n)// change a random box to texture n (5 or 6) {var i = AB.randomIntAtoB (0, THEARMY.length -1);// pick a random box to change
THEARMY[i].material =new THREE.MeshBasicMaterial({ map: textureArray[n]});}
AB.socketIn =function(n)// incoming data on socket, i.e. clicks of other player {if(! AB.runReady )return;
changeBox(n);};