/*******************************************************************************************************
CA318 Ancient Brain Project
********************************************************************************************************
This project was done by:
- Aaron Crawford (20336753)
- Thomas Hazekamp (20423602)
References:
- Audio:
- All audio was taken from https://myfreemp3.to/
- Other user AB worlds:
- https://ancientbrain.com/viewjs.php?world=6044718909
********************************************************************************************************/// Notes: Game doesnt start until one player has selected team 2, as this sends data to the other player saying it is their go (it is not necessary for a player to select team 1)// Background musicconst MUSICFILE ='/uploads/aaroncrawford/Sea_Shanty.mp3';
MUSICFILE.volume =0.2;// Changing volume of music
AB.backgroundMusic( MUSICFILE );// Adding background music to world// Hit and miss sound effects used when using the attack boardconstMissSounds="/uploads/aaroncrawford/MissSound.mp3";varMissSound=newAudio(MissSounds);constHitSounds="/uploads/aaroncrawford/HitSound.mp3";varHitSound=newAudio(HitSounds);// Default camera controlsABWorld.drawCameraControls =false;// Controls for camera
AB.drawRunControls =false;// Controls for the steps and run// Time in game (how many runs in the game)
AB.maxSteps =10000;
AB.clockTick =100;// Textures and tilesconst skycolor ='lightyellow';const boxcolor ='/uploads/hazekat2/water.jpg';// Water texture for gridsconst targetbox ='/uploads/aaroncrawford/target_tile.png';// Target tileconst hitbox ='/uploads/aaroncrawford/tile2.png';// Tile used to show affermative hit /MAYBE CHANGE VARIABLE NAME?const missbox ='/uploads/aaroncrawford/tile3.png';// Tile used to show missed hitconst LIGHTCOLOR =0xffffff;const SKYCOLOR =0x009933;const red = SKYCOLOR;const gridsize =8;// Number of squares per grid side const squaresize =400;// Size of square in pixelsvar positioning1 =[];// Players boardvar positioning2 =[];// Attack boardconst MAXPOS = gridsize * squaresize;// Length of one side in pixels const skyboxConst = MAXPOS *3;ABHandler.GROUNDZERO =true;const maxRadiusConst = MAXPOS *10;const startRadiusConst = MAXPOS *0.8;const startRadius =5500;// Distance from centre we start the camera atconst maxRadius = startRadius *500;// Maximum distance from camera we render things var GRID1 =newArray(gridsize);// Horizontal grid (Used for boats)var GRID2 =newArray(gridsize);// Vertical grid (Used as the attack board)var tile_texture;// Default tile texturevar b1z, b1x;var keep =[0,7];// Used to keep the attack grid co-ordinates// Keeping score of both playersvar p1score =0;var p2score =0;var alreadyHit =[];// Co-ordiantes of already hit enemy boats var alreadyMissed =[];// Co-ordinates of already missed attack board positionsvar myturn;// Know if p1 or p2 turn// the object is a cube (each dimension equal):
AB.newSplash ( splashScreenStartMenu());// Shows the menu page, first thing that loads into the worldfunction initSkybox(){// This function was taken from https://ancientbrain.com/viewjs.php?world=6044718909// Creates the cube around the uservar materialArray =[(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seanhutchinson/skyrender0001.bmp"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seanhutchinson/skyrender0004.bmp"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seanhutchinson/skyrender0003.bmp"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seanhutchinson/skyrender0006.bmp"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seanhutchinson/skyrender0005.bmp"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seanhutchinson/skyrender0002.bmp"), side: THREE.BackSide})),];// Used for the background cubevar skyGeometry =new THREE.BoxGeometry( skyboxConst, skyboxConst, skyboxConst );var skyMaterial =new THREE.MeshFaceMaterial( materialArray );var theskybox =new THREE.Mesh( skyGeometry, skyMaterial );
threeworld.scene.add( theskybox );// Adding the cube (so we are in the cube)}// New run of the world
AB.world.newRun =function(){
AB.socketStart();// Starts web sockets
BOXHEIGHT = squaresize;
threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );var thelight =new THREE.DirectionalLight( LIGHTCOLOR,3);
threeworld.scene.add(thelight);
initSkybox();// Calls function to add cube around us
initScene();// Calls function to add scene
AB.runReady =false;};function initScene(){var color =new THREE.Color();ABWorld.init3d ( startRadius, maxRadius, skycolor );var manager =new THREE.LoadingManager();var loader =new THREE.OBJLoader( manager );// Build boats// We got the boat models from https://clara.io/view/565a3914-446c-4c26-accc-b0a3dc099a0f
loader.load("/uploads/aaroncrawford/fishing-boat.obj", buildboat1 );
loader.load("/uploads/aaroncrawford/fishing-boat.obj", buildboat2 );
loader.load("/uploads/aaroncrawford/fishing-boat.obj", buildboat3 );
loader.load("/uploads/aaroncrawford/fishing-boat.obj", buildboat4 );// Load default boxesvar loader1 =new THREE.TextureLoader();
loader1.load ( boxcolor,function( boxcolor ){
boxcolor.minFilter = THREE.LinearFilter;
tile_texture = boxcolor;if( asynchFinished())GridMaker();});// Load target boxesvar loader2 =new THREE.TextureLoader();
loader2.load ( targetbox,function( targetbox ){
targetbox.minFilter = THREE.LinearFilter;
target_texture = targetbox;if( asynchFinished())TargetMaker(0,7);});var ambient =new THREE.AmbientLight();ABWorld.scene.add(ambient);}// This functions runs as a loop
AB.world.nextStep =function(){// Text displaying whos turn it isif(myturn){
whosTurn ='<span style="color:green"> It is your turn!</span>';}else{
whosTurn ='<span style="color:red">It is the other players turn!</span>';}// Text showing in controls window
AB.msg ('<h3> Please wait until the other player has selected start before choosing your team!</h3>'+'<p>You may have to double/spam click when selcting your team</p>'+'<button onclick=Team1(); class=ab-largenormbutton > Team1 </button> '+'<button onclick=Team2(); class=ab-largenormbutton > Team2 </button> <h2>'+'<h2>You have '+'<span style="color:green">'+ p1score +' hit(s) </span>'+' on their boat(s)'+'<br>'+'They have '+'<span style="color:red">'+ p2score +' hit(s) </span>'+' on your boat(s)'+'</h2>'+'<h3><u>'+ whosTurn +'</u></h3>'+`<h1>Controls:</h1><ol><li>Use arrow keys to move around the attack board (when it is your go)</li><li>Press enter to hit the current position</li><li>Use mouse 1(left click) to move the camera angle</li></ol>`);// Data to share with other playervar data =[positioning1, p1score, myturn];// Game ends if one of the players has hit all loctions of the boatsif(p1score ==12|| p2score ==12){// If you win the game will end
AB.abortRun =true;}// Used to check what key the user has pressed & used
document.onkeydown = checkKey;function checkKey(e){
e = e || window.event;// If its is the current players turnif(myturn){// Each key will check that it is still on the board & will update the box colour to show the user exactly where they are situated with their positioning// Will replace the current box with a normal box, & change the next box to the target box. Depending on up, down, right, leftif(e.keyCode =='38'){// up arrowif(keep[1]<7){ReplaceTarget(keep[0], keep[1]);
keep =TargetMaker(keep[0], keep[1]+1);}}elseif(e.keyCode =='40'){// down arrowif(keep[1]>0){ReplaceTarget(keep[0], keep[1]);
keep =TargetMaker(keep[0], keep[1]-1);}}elseif(e.keyCode =='37'){// left arrowif(keep[0]>0){ReplaceTarget(keep[0], keep[1]);
keep =TargetMaker(keep[0]-1, keep[1]);}}elseif(e.keyCode =='39'){// right arrowif(keep[0]<7){ReplaceTarget(keep[0], keep[1]);
keep =TargetMaker(keep[0]+1, keep[1]);}}elseif(e.keyCode =='13'){// Enter key
temp = myturn;CheckHit(keep, positioning2);// Checks if the current entered position is a hit or notif(!myturn){// Updating data to send to other playervar data =[positioning1, p1score, temp];if(AB.socket)// If the socket has loaded & connected{if(AB.socket.connected){
AB.socketOut(data);// Sends players boats positioning, current players score & turn}}}}}}};functionTeam1(){// Sending data to other playervar data =[positioning1, p1score,false];// The false is being sent to palayer 2 to indicate it is not their turnif(AB.socket){if(AB.socket.connected){
AB.socketOut(data);// Sends players boats positioning & current players score & turn}}}functionTeam2(){// Sending data to other playervar data =[positioning1, p1score,true];// The true is being sent to player 1 to indicate it is their turnif(AB.socket){if(AB.socket.connected){
AB.socketOut(data);// Sends players boats positioning & current players score}}}functionCheckHit(keep, pos){// Checks if the current box is a hit on the opponents board
testIfAlreadyHit =false;
testIfBoatHit =false;for(let i =0; i < alreadyHit.length; i++){// For loop to check if box on board has already been fired at and was a hitif(keep[0]== alreadyHit[i][0]&& keep[1]== alreadyHit[i][1]){
testIfAlreadyHit =true;}}if(!testIfAlreadyHit){// If statements to check if we have hit a boat position (hitting part of a boat)if(keep[0]== pos[0][0]){// boat 1 (vertical boat)if(keep[1]==(pos[0][1]-1)|| keep[1]==(pos[0][1]+1)|| keep[1]==(pos[0][1])){
alreadyHit.push(keep);HitConfirm(keep[0], keep[1]);
testIfBoatHit =true;
console.log("HIT boat 1");
p1score +=1;HitSound.play();
myturn =false;// Next players turn}}if(keep[0]== pos[1][0]){// boat 2 (vertical boat)if(keep[1]==(pos[1][1]-1)|| keep[1]==(pos[1][1]+1)|| keep[1]==(pos[1][1])){
alreadyHit.push(keep);HitConfirm(keep[0], keep[1]);
testIfBoatHit =true;
console.log("HIT boat 2");
p1score +=1;HitSound.play();
myturn =false;}}if(keep[1]== pos[2][1]){// boat 3 (horizontal boat)if(keep[0]==(pos[2][0]-1)|| keep[0]==(pos[2][0]+1)|| keep[0]==(pos[2][0])){
alreadyHit.push(keep);HitConfirm(keep[0], keep[1]);
testIfBoatHit =true;
console.log("HIT boat 3");
p1score +=1;HitSound.play();
myturn =false;}}if(keep[1]== pos[3][1]){// boat 3 (horizontal boat)if(keep[0]==(pos[3][0]-1)|| keep[0]==(pos[3][0]+1)|| keep[0]==(pos[3][0])){
alreadyHit.push(keep);HitConfirm(keep[0], keep[1]);
testIfBoatHit =true;
console.log("HIT boat 4");
p1score +=1;HitSound.play();
myturn =false;}}if(!testIfBoatHit){// Enters this statement if user fires and misses
alreadyMissed.push(keep);MissedTarget(keep[0], keep[1]);MissSound.play();
myturn =false;}}}functionMissedTarget(x, y){// Adding a texture to show we have missed the targetvar loader4 =new THREE.TextureLoader();
loader4.load ( missbox,function( missbox ){
missbox.minFilter = THREE.LinearFilter;
miss_texture = missbox;if( asynchFinished()){
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: miss_texture });
thecube.position.copy ( translate2(x, y));ABWorld.scene.add(thecube);}});}functionReplaceTarget(x, y){// Function to replace target when user moves with arrow keys, except if they have already fired
testIfAlreadyMissed =false;for(let i =0; i < alreadyMissed.length; i++){if(x == alreadyMissed[i][0]&& y == alreadyMissed[i][1]){
testIfAlreadyMissed =true;}}
testIfAlreadyHit =false;for(let i =0; i < alreadyHit.length; i++){if(x == alreadyHit[i][0]&& y == alreadyHit[i][1]){
testIfAlreadyHit =true;}}if(!testIfAlreadyHit &&!testIfAlreadyMissed)// Recovering the original cube{
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: tile_texture });
thecube.position.copy ( translate2(x, y));// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates ABWorld.scene.add(thecube);}elseif(testIfAlreadyHit &&!testIfAlreadyMissed)// Adding hit target cube{
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: hit_texture });
thecube.position.copy ( translate2(x, y));// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates ABWorld.scene.add(thecube);}else// Adding miss target cube{
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: miss_texture });
thecube.position.copy ( translate2(x, y));// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates ABWorld.scene.add(thecube);}}functionTargetMaker(x, y){// Created the target cube used to know what position you want to attack on the attack board
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: target_texture });
thecube.position.copy ( translate2(x, y));// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates ABWorld.scene.add(thecube);return[x, y];}functionHitConfirm(x, y){// Adding the hit confirm cube to show that postition is hitvar loader3 =new THREE.TextureLoader();
loader3.load ( hitbox,function( hitbox ){
hitbox.minFilter = THREE.LinearFilter;
hit_texture = hitbox;if( asynchFinished()){
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: hit_texture });
thecube.position.copy ( translate2(x, y));// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates ABWorld.scene.add(thecube);}});}functionGridMaker(){// Created the two grids// set up boats gridfor( i =0; i < gridsize ; i++)for( j =0; j < gridsize ; j++)if(( i<=gridsize-1)||( j<=gridsize-1)){
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: tile_texture });
thecube.position.copy ( translate1(i,j));// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates ABWorld.scene.add(thecube);}// set up attack gridfor( i =0; i < gridsize ; i++)for( j =0; j < gridsize ; j++)if(( i<=gridsize-1)||( j<=gridsize-1)){
shape =new THREE.BoxGeometry( squaresize, squaresize, squaresize );
thecube =new THREE.Mesh( shape );
thecube.material =new THREE.MeshBasicMaterial({ map: tile_texture });
thecube.position.copy ( translate2(i,j));// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates ABWorld.scene.add(thecube);}}function buildboat1( object ){// Building boat 1
object.scale.multiplyScalar (100);// make 3d object n times bigger
object.traverse( paintBoat );
boat1 = object;
threeworld.scene.add( boat1);
positioning1.push(drawBoat1(boat1));// Adding the position of boat to list of positions}function buildboat2( object ){// Building boat 2
object.scale.multiplyScalar (100);// make 3d object n times bigger
object.traverse( paintBoat );
boat2 = object;
threeworld.scene.add( boat2);
positioning1.push(drawBoat2(boat2));// Adding the position of boat to list of positions}function buildboat3( object ){// Building boat 3
object.scale.multiplyScalar (100);// make 3d object n times bigger
object.traverse( paintBoat );
boat3 = object;
boat3.rotateY(1.6);
threeworld.scene.add( boat3);
positioning1.push(drawBoat3(boat3));// Adding the position of boat to list of positions}function buildboat4( object ){// Building boat 4
object.scale.multiplyScalar (100);// make 3d object n times bigger
object.traverse( paintBoat );
boat4 = object;
boat4.rotateY(1.6);
threeworld.scene.add( boat4);
positioning1.push(drawBoat4(boat4));// Adding the position of boat to list of positions}function paintBoat ( child ){// Used to add a texture to boatsif( child instanceof THREE.Mesh){
child.material.map = THREE.ImageUtils.loadTexture("/uploads/aaroncrawford/wood.jpg");}}function drawBoat1(){// Choosing the position of boat
b1j = getRandomPositionVerticleZ();
b1i = getRandomPositionVerticleX();var b1x = translateBoats ( b1i * squaresize );// left to rightvar b1z = translateBoats ( b1j * squaresize );// z looking flat away from camvar b1y =(1.2* squaresize );
boat1.position.x = b1x;
boat1.position.y = b1y;
boat1.position.z = b1z;
b1j =5- b1j;// Ensuring boat is spawning on boardreturn[b1i, b1j];// Returning boat pos}function drawBoat2(){// Choosing the position of boat (cannot spawn on boat 1)
b1i = getRandomPositionVerticleX();
b1j = getRandomPositionVerticleZ();if(b1i == positioning1[0][0]){// Checking that position is not already takenwhile(5- b1j >= positioning1[0][1]-2&&5- b1j <= positioning1[0][1]+2){
b1j = getRandomPositionVerticleZ();}}var b2x = translateBoats ( b1i * squaresize );// left to rightvar b2z = translateBoats ( b1j * squaresize );// z looking flat away from camvar b2y =(1.2* squaresize );
boat2.position.x = b2x;
boat2.position.y = b2y;
boat2.position.z = b2z;
b1j =5- b1j;return[b1i, b1j];}function drawBoat3(){// Choosing the position of boat (cannot spawn on boat 1 & 2)
b1j = getRandomPositionHorizontalZ();
b1i = getRandomPositionHorizontalX();if(b1i >= positioning1[0][0]-1&& b1i <= positioning1[0][0]+1|| b1i >= positioning1[1][0]-1&& b1i <= positioning1[1][0]+1){// Checking that positioning is not already takenwhile(5- b1j >= positioning1[0][1]-1&&5- b1j <= positioning1[0][1]+1||5- b1j >= positioning1[1][1]-1&&5- b1j <= positioning1[1][1]+1){
b1j = getRandomPositionHorizontalZ();}}var b3x = translateBoats ( b1i * squaresize );// left to rightvar b3z = translateBoats ( b1j * squaresize );// z looking flat away from camvar b3y =(1.2* squaresize );
boat3.position.x = b3x;
boat3.position.y = b3y;
boat3.position.z = b3z;
b1j =5- b1j;return[b1i, b1j];}function drawBoat4(){// Choosing the position of boat (cannot spawn on boat 1 & 2 & 3)
b1j = getRandomPositionHorizontalZ();
b1i = getRandomPositionHorizontalX();if(b1i >= positioning1[0][0]-1&& b1i <= positioning1[0][0]+1|| b1i >= positioning1[1][0]-1&& b1i <= positioning1[1][0]+1|| b1i >= positioning1[2][0]-2&& b1i <= positioning1[2][0]+2){// Checking that position is not already takenwhile(5- b1j >= positioning1[0][1]-1&&5- b1j <= positioning1[0][1]+1||5- b1j >= positioning1[1][1]-1&&5- b1j <= positioning1[1][1]+1||5- b1j == positioning1[2][1]){
b1j = getRandomPositionHorizontalZ();}}var b4x = translateBoats ( b1i * squaresize );// left to rightvar b4z = translateBoats ( b1j * squaresize );// z looking flat away from camvar b4y =(1.2* squaresize );
boat4.position.x = b4x;
boat4.position.y = b4y;
boat4.position.z = b4z;
b1j =5- b1j;return[b1i, b1j];}function getRandomPositionVerticleZ(){// Get random pos on Z on vertical
min =Math.ceil(-1);
max =Math.floor(4);returnMath.floor(Math.random()*(max - min +1)+ min);}function getRandomPositionVerticleX(){// Get random pos on X on vertical
min =Math.ceil(0);
max =Math.floor(7);returnMath.floor(Math.random()*(max - min +1)+ min);}function getRandomPositionHorizontalZ(){// Get random pos on Z horizontal
min =Math.ceil(-2);
max =Math.floor(5);returnMath.floor(Math.random()*(max - min +1)+ min);}function getRandomPositionHorizontalX(){// Get random pos on X horizontal
min =Math.ceil(1);
max =Math.floor(6);returnMath.floor(Math.random()*(max - min +1)+ min);}function asynchFinished(){// Function to check if the textures have loadedif( tile_texture )returntrue;elsereturnfalse;}function translate1 ( i, j ){// translate1 function will convert our i and j co-ordinates to the x & z co-ordinates needed var v =new THREE.Vector3();
j -=2;
v.y =0;
v.x =( i * squaresize )-( MAXPOS/2);
v.z =( j * squaresize )-( MAXPOS/2);return v;}function translate2 ( i, j ){// translate1 function will convert our i and j co-ordinates to the x & y co-ordinates neededvar v =new THREE.Vector3();
v.y =( j * squaresize )-( MAXPOS/2)+2000;
v.x =( i * squaresize )-( MAXPOS/2);
v.z =-4000;return v;}function translateBoats ( x ){// Changes x to return the correct co-ordinate neededreturn( x -(MAXPOS/2));}
AB.world.endRun =function(){// Occurs when we want to end the users turn
AB.newSplash ( splashScreenEndMenu());// Calling end screen popconst time =10000;// time in milliseconds when the page reload occurs// Timer to refresh page after time ms
setTimeout(function(){
location.reload();}, time);};function splashScreenStartMenu(){// Rules on the start screenvar description =`<h1>Rules:</h1><ul><li>Both players must select a team before they can begin the game</li><li>Players will take turns</li><li>First player to get12 hits wins the game</li></ul>
NOTE:Both players need to select start before choosing a team!<br>`;return description;}function splashScreenEndMenu(){// End screen text for winner and loservar end_message;if(p1score ==12){
end_message ="<h1 style='text-align: center'>WINNER WINNER CHICKEN DINNER!</h1> <h3 style='text-align: center'>The game is over</h3>";}else{
end_message ="<h1 style='text-align: center'>Mission Failed We'll Get'em Next Time!</h1> <h3 style='text-align: center'>The game is over</h3>";}return( end_message );}
AB.splashClick (function(){// Occurs when we click start on start pop up
AB.runReady =true;
AB.removeSplash();// remove splash screen});
AB.socketIn =function(data){
positioning2 = data[0];// Socket functionality (p2 score)
p2score = data[1];
myturn = data[2];// console.log(myturn + '4');};
AB.socketUserlist =function( array ){// Used to get number of users to check if the match is full
console.log(array.length);
console.log(array);if(array.length >2){
AB.splashHtml(fullMatch());}};function fullMatch(){// Screen for when the match is fullvar text;
text ='<h1>The game is currently full, please try again later</h1>';
text = text +'<button onclick=\'refreshButton();\' class=ab-largenormbutton > Try again </button>';return text;}function refreshButton(){// Used to refresh end screen page
location.reload();}