// Cloned by Okikiola Sanni on 13 Nov 2022 from World "Websockets boxes" 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 Websockets functionality added to a 3D World
// Run with two or more users
// Click button to change a random box's texture on all clients running this World
// Pick a side and compete against an opponent!
// You can annoy the other player by reloading the page!
const clock = new THREE.Clock();
AB.clockTick = 150;
// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps = 1000;
// 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 MUSIC_BACK = "/uploads/kikisanni/arcade.mp3"
const FILE_ARRAY = [
"/uploads/kikisanni/white.png", // array 0 to 4 are the earths
"/uploads/kikisanni/white.png",
"/uploads/kikisanni/white.png",
"/uploads/kikisanni/white.png",
"/uploads/kikisanni/white.png",
"/uploads/kikisanni/red.jpg", // array 5
"/uploads/kikisanni/yellow.jpeg", // array 6
"/uploads/kikisanni/blue.png",
"/uploads/kikisanni/green.png"
];
const SKYBOX_ARRAY = [
"/uploads/kikisanni/flame_bk.jpg",
"/uploads/kikisanni/flame_ft.jpg",
"/uploads/kikisanni/flame_up.jpg",
"/uploads/kikisanni/flame_dn.jpg",
"/uploads/kikisanni/flame_lf.jpg",
"/uploads/kikisanni/flame_rt.jpg"
];
const SKYCOLOR = 0xd3d3d3 ;
const ARMYSIZE = 100; // an "army" of objects
const objectsize = 500 ;
const WALKSTEP = 100; // 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 at
const 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 = new Array( ARMYSIZE );
var textureArray = new Array ( FILE_ARRAY.length );
function initLights()
{
const ambientLight = new THREE.AmbientLight( 0xffffff, 1 );
ABWorld.scene.add( ambientLight );
const frontLight = new THREE.DirectionalLight( 0xffffff, 1 );
frontLight.position.set( 10, 10, 10 );
const backLight = new THREE.DirectionalLight( 0xffffff, 1 );
backLight.position.set( -10, 10, -10 );
ABWorld.scene.add( frontLight, backLight );
}
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() ) initScene();
});
}
function asynchFinished() // all file loads returned
{
for ( var i = 0; i < FILE_ARRAY.length; i++ )
if ( ! textureArray[i] )
return false;
return true;
}
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++;
}
ABWorld.render();
AB.removeLoading();
AB.runReady = true;
let listElement = document.createElement("li");
listElement.innerHTML
AB.msg ( `<hr> <p> Multiplayer game. Click buttons to change boxes on all users' machines. Drag the camera. <p>
<button onclick='red();' class=ab-largenormbutton > Red </button>
<button onclick='yellow();' class=ab-largenormbutton > Yellow </button>
<button onclick='blue();' class=ab-largenormbutton > Blue </button>
<button onclick='green();' class=ab-largenormbutton > Green </button> <p>
`
);
// <h1> Chat Opponent </h1>
// If you are logged in, chat is tagged with your name.
// <p>
// <div style="width:60vw; background-color:#add8e6; border: 1px solid black; margin:5; padding: 10px;">
// <h3> Me </h3>
// <INPUT style="width:30vw;" id=me >
// <button onclick="sendchat();" class=ab-normbutton > Send </button>
// </div>
// <div style="width:60vw; background-color:darkgrey; border: 1px solid black; margin:5; padding: 10px;">
// <h3> Them </h3>
// <div id=them > </div>
// </div>
// <div style="width:60vw; background-color:blue; border: 1px solid black; margin:5; padding: 10px;">
// <h3> Players online </h3>
// <div id=themlist > </div>
// </div>
}
function initScene()
{
initArmy();
ABWorld.scene.background = new THREE.CubeTextureLoader().load ( SKYBOX_ARRAY, function()
{
ABWorld.render();
AB.removeLoading();
AB.runReady = true;
});
}
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.loadingScreen();
// AB.runReady = false;
// ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );
// loadResources(); // aynch file loads
// // calls initArmy() when it returns
// initLights();
// // var ambient = new THREE.AmbientLight(); // light
// // ABWorld.scene.add( ambient );
// // var thelight = new THREE.DirectionalLight ( LIGHTCOLOR, -1 );
// // thelight.position.set ( startRadiusConst, startRadiusConst, startRadiusConst );
// // ABWorld.scene.add(thelight);
// };
AB.world.newRun = function()
{
AB.loadingScreen();
AB.runReady = false;
ABWorld.init3d ( startRadiusConst, maxRadiusConst);
ABWorld.scene.background=(new THREE.CubeTextureLoader).load(SKYBOX_ARRAY)
loadResources(); // aynch file loads
// calls initArmy() when it returns
initLights();
};
AB.world.nextStep = function()
{
moveArmy();
};
//--- Socket functionality -----------------------------------------------------
// start socket
AB.socketStart();
// functions called by buttons
// baby and skull are textures 5 and 6 in the array:
function red() { changeBox(5); AB.socketOut (5); }
function yellow() { changeBox(6); AB.socketOut (6); }
function blue() { changeBox(7); AB.socketOut (7); }
function green() { changeBox(8); AB.socketOut (8); }
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
{
changeBox(n);
};
// --- music and sound effects ----------------------------------------
var backmusic = AB.backgroundMusic ( MUSIC_BACK );
function musicPlay() { backmusic.play(); }
function musicPause() { backmusic.pause(); }