// Cloned by Lakshita Dubey on 1 Dec 2023 from World "Looney Tunes Chase (A* AI)" by Sean Sinnott // Please leave this clone trail here.// This game involves you controlling Bugs Bunny, and the objective is to burrow through the first two floors and reach the Carrot object on floor 1 //// without being caught by Yosemite Sam. For the best gaming experience, please use the 'Move With' option while playing. //// Yosemite Sam tracks Bugs Bunny's location using an A* Pathfinding Algorithm so I have slowed him down to only move every 3 steps you take in order //// to make the game more playable (otherwise it's quite difficult). ////-------------------------------------------------------------------------------------------------------------------------------------------------------//const CLOCKTICK =100;// move things every 100 millisecondsconst MAXSTEPS =1000;// allowed 1000 steps before game is overconst SCREENSHOT_STEP =50;//-------------------- global constants --------------------//const GRIDSIZE =50;// number of squares along side of world const NOBOXES =Math.trunc ((GRIDSIZE * GRIDSIZE)/10);// density of mazeconst SQUARESIZE =100;// size of square in pixelsconst MAXPOS = GRIDSIZE * SQUARESIZE;// length of one side in pixels const SKYCOLOR =0xddffdd;// a number, not a string const BLANKCOLOR = SKYCOLOR ;// make objects this color until texture arrivesconst LIGHTCOLOR =0x000000;// colour of ambient light used laterconst STARTRADIUSCONST = MAXPOS *1;// distance from centre to start the camera atconst SKYBOXCONST = MAXPOS *3;// where to put skybox const MAXRADIUSCONST = MAXPOS *10;// maximum distance from camera we will render things //-------------------- mind can pick on of these actions --------------------//const ACTION_LEFT =0;const ACTION_RIGHT =1;const ACTION_UP =2;const ACTION_DOWN =3;const ACTION_STAYSTILL =4;//-------------------- contents of a grid square --------------------//const GRID_BLANK =0;const GRID_WALL =1;const GRID_MAZE =2;const GRID_GROUND =3;//-------------------- random functions --------------------//function randomfloatAtoB ( A, B ){return( A +(Math.random()*(B-A)));}function randomintAtoB ( A, B ){return(Math.round ( randomfloatAtoB ( A, B )));}//-------------------- START OF WORLD CLASS --------------------//functionWorld(){var GRID1 =newArray(GRIDSIZE);// grid 1, 2 and 3 represent the 3 floorsvar GRID2 =newArray(GRIDSIZE);// in the game and can be used to check ifvar GRID3 =newArray(GRIDSIZE);// a square is occupied etc.var UNDERSIDE =newArray(GRIDSIZE);// used as the bottom of the floor on which objects and characters standvar FLOOR_1_WALLS =newArray(4* GRIDSIZE );// wall for floorsvar FLOOR_2_WALLS =newArray(4* GRIDSIZE );// 1, 2 and 3var FLOOR_3_WALLS =newArray(4* GRIDSIZE );// respectivelyvar FLOOR_1_MAZE =newArray( NOBOXES );// maze for floorsvar FLOOR_2_MAZE =newArray( NOBOXES );// 1, 2 and 3var FLOOR_3_MAZE =newArray( NOBOXES );// respectivelyvar FLOOR_1_GROUND =newArray(GRIDSIZE * GRIDSIZE);// ground for floorsvar FLOOR_2_GROUND =newArray(GRIDSIZE * GRIDSIZE);// 1, 2 and 3var FLOOR_3_GROUND =newArray(GRIDSIZE * GRIDSIZE);// respectivelyvar theagent, theenemy, thecamera, thecarrot, topfloorburrow, midfloorburrow;// will be used to represent the object after which they are namedvar enemyFloor =1950;// the floor on which the enemy is initialised -> 1950 is the 3rd floorvar agentFloor =1950;// the floor on which the agent is initialisedvar ei, ej;// enemy position on squaresvar ai, aj;// agent position on squaresvar ci, cj;// camera position on squares (will be behind and above Bugs Bunny)var ti, tj;// carrot position on squaresvar b1i, b1j;// top floor burrow position on squaresvar b2i, b2j;// middle floor burrow position on squares// booleans used to identify what direction Bugs Bunny is facing at any given timevar bugsLookingForward =true;var bugsLookingBack =false;var bugsLookingLeft =false;var bugsLookingRight =false;// booleans used to identify what direction Yosemite Sam is facing at any given timevar samLookingForward =true;var samLookingBack =false;var samLookingLeft =false;var samLookingRight =false;// will be used as array of size 2 marking the coordinates of Bugs Bunny and Yosemite Sam in Pathfinding Algorithmvar currentAgentPosition;var currentEnemyPosition;var step;// number of steps in game so farvar self =this;// needed for private fn to call public fn// initialise the 3 floorsfunction initGrid(){for(var i =0; i < GRIDSIZE ; i++){
GRID1[i]=newArray(GRIDSIZE);
GRID2[i]=newArray(GRIDSIZE);
GRID3[i]=newArray(GRIDSIZE);for(var j =0; j < GRIDSIZE ; j++){
GRID1[i][j]= GRID_BLANK ;
GRID2[i][j]= GRID_BLANK ;
GRID3[i][j]= GRID_BLANK ;}}}// initialise the bottom of the 3 floorsfunction initUnderside(){for(var i =0; i < GRIDSIZE ; i++){
UNDERSIDE[i]=newArray(GRIDSIZE);// each element is an array for(var j =0; j < GRIDSIZE ; j++){
UNDERSIDE[i][j]= GRID_BLANK ;}}}// checks if given coordinates are currently occupied by an objectfunction occupied ( i, j ){if( GRID1[i][j]== GRID_WALL)returntrue;if( GRID1[i][j]== GRID_MAZE && agentFloor ==-50)returntrue;if( GRID2[i][j]== GRID_WALL)returntrue;if( GRID2[i][j]== GRID_MAZE && agentFloor ==950)returntrue;if( GRID3[i][j]== GRID_WALL)returntrue;if( GRID3[i][j]== GRID_MAZE && agentFloor ==1950)returntrue;returnfalse;}// similar to above, but doesn't consider where the agent is, this method prevents the burrows/carrot being places in same position as a maze objectfunction cannotPlaceObject(i,j){if( GRID1[i][j]== GRID_WALL)returntrue;if( GRID1[i][j]== GRID_MAZE)returntrue;if( GRID2[i][j]== GRID_WALL)returntrue;if( GRID2[i][j]== GRID_MAZE && agentFloor)returntrue;if( GRID3[i][j]== GRID_WALL)returntrue;if( GRID3[i][j]== GRID_MAZE && agentFloor)returntrue;returnfalse;}// checks to see if Bugs Bunny is standing on a Burrow object and can move down to the next floorfunction canBurrow (){if( b1i == ai && b1j == aj && agentFloor ==1950)returntrue;// fixed objectsif( b2i == ai && b2j == aj && agentFloor ==950)returntrue;returnfalse;}// translates objects to Three.js coordinatesfunction translate ( x ){return( x -( MAXPOS/2));}// initialises the skybox. credit: http://korzonrocknet.deviantart.com/art/Skybox-446554846function initSkybox(){var materialArray =[(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seansinnott/skybox_right.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seansinnott/skybox_left.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seansinnott/skybox_top.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seansinnott/skybox_bottom.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seansinnott/skybox_near.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/seansinnott/skybox_far.jpg"), side: THREE.BackSide})),];var skyGeometry =new THREE.CubeGeometry( SKYBOXCONST, SKYBOXCONST, SKYBOXCONST );var skyMaterial =new THREE.MeshFaceMaterial( materialArray );var theskybox =new THREE.Mesh( skyGeometry, skyMaterial );
threeworld.scene.add( theskybox );}//-------------------- START OF LOAD TEXTURES & OBJECTS --------------------//function loadTextures(){// load in Bugs Bunny object. credit: https://www.models-resource.com/wii/looneytunesacmearsenal/model/9874/var m =new THREE.MTLLoader();
m.setTexturePath ("/uploads/seansinnott/");
m.setPath ("/uploads/seansinnott/");
m.load("bugs.mtl",function( materials ){
materials.preload();var o =new THREE.OBJLoader();
o.setMaterials ( materials );
o.setPath ("/uploads/seansinnott/");
o.load("bugs.obj",function( object ){
addagent ( object );});});// load in Yosemite Sam object. credit: https://www.models-resource.com/wii/looneytunesacmearsenal/model/15925/var n =new THREE.MTLLoader();
n.setTexturePath ("/uploads/seansinnott/");
n.setPath ("/uploads/seansinnott/");
n.load("yosemite.mtl",function( materials ){
materials.preload();var p =new THREE.OBJLoader();
p.setMaterials ( materials );
p.setPath ("/uploads/seansinnott/");
p.load("yosemite.obj",function( object ){
addenemy ( object );});});// load in carrot object. credit: https://www.models-resource.com/custom_edited/mariocustoms/model/8638/var s =new THREE.MTLLoader();
s.setTexturePath ("/uploads/seansinnott/");
s.setPath ("/uploads/seansinnott/");
s.load("carrot.mtl",function( materials ){
materials.preload();var t =new THREE.OBJLoader();
t.setMaterials ( materials );
t.setPath ("/uploads/seansinnott/");
t.load("carrot.obj",function( object ){
addcarrot ( object );});});// load in both burrow objects. credit: https://www.models-resource.com/pc_computer/harrypottertheprisonerofazkaban/model/14837/var x =new THREE.MTLLoader();
x.setTexturePath ("/uploads/seansinnott/");
x.setPath ("/uploads/seansinnott/");
x.load("burrow.mtl",function( materials ){
materials.preload();var y =new THREE.OBJLoader();
y.setMaterials ( materials );
y.setPath ("/uploads/seansinnott/");
y.load("burrow.obj",function( object ){
addmidburrow ( object );});});var q =new THREE.MTLLoader();
q.setTexturePath ("/uploads/seansinnott/");
q.setPath ("/uploads/seansinnott/");
q.load("burrow.mtl",function( materials ){
materials.preload();var r =new THREE.OBJLoader();
r.setMaterials ( materials );
r.setPath ("/uploads/seansinnott/");
r.load("burrow.obj",function( object ){
addtopburrow ( object );});});// load in wall texture. credit: https://freestocktextures.com/texture/wood-weathered-plank,421.htmlvar loader1 =new THREE.TextureLoader();
loader1.load ('/uploads/seansinnott/fence.jpg',function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
paintWalls (new THREE.MeshBasicMaterial({ map: thetexture }));});// load in maze texture. credit: https://freestocktextures.com/texture/leaves-plant-nature,686.htmlvar loader2 =new THREE.TextureLoader();
loader2.load ('/uploads/seansinnott/bush.jpg',function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
paintMaze (new THREE.MeshBasicMaterial({ map: thetexture }));});// load in ground texture, used same ground as in skybox above. credit: http://korzonrocknet.deviantart.com/art/Skybox-446554846var loader3 =new THREE.TextureLoader();
loader3.load ('/uploads/seansinnott/skybox_bottom.jpg',function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
paintGround (new THREE.MeshBasicMaterial({ map: thetexture }));});}//-------------------- END OF LOAD TEXTURES & OBJECTS --------------------//// add Bugs Bunny object into worldfunction addagent ( object ){
object.scale.multiplyScalar (20);
theagent = object;
theagent.rotateY(2*(Math.PI /2));
threeworld.scene.add( theagent );}// add Yosemite Sam object into worldfunction addenemy ( object ){
object.scale.multiplyScalar (30);
theenemy = object;
theenemy.rotateY(2*(Math.PI /2));
threeworld.scene.add( theenemy );}// add Carrot object into worldfunction addcarrot ( object ){
object.scale.multiplyScalar (2);
thecarrot = object;
thecarrot.rotateY(2*(Math.PI /2));
threeworld.scene.add( thecarrot );}// add Top Burrow object into worldfunction addtopburrow ( object ){
object.scale.multiplyScalar (1);
topfloorburrow = object;
threeworld.scene.add( topfloorburrow );}// add Middle Burrow object into worldfunction addmidburrow ( object ){
object.scale.multiplyScalar (1);
midfloorburrow = object;
threeworld.scene.add( midfloorburrow );}//-------------------- START OF WALL FUNCTIONS --------------------////initialise the walls logicallyfunction initLogicalWalls(){for(var i =0; i < GRIDSIZE ; i++)for(var j =0; j < GRIDSIZE ; j++)if(( i==0)||( i==GRIDSIZE-1)||( j==0)||( j==GRIDSIZE-1)){
GRID1[i][j]= GRID_WALL ;
GRID2[i][j]= GRID_WALL ;
GRID3[i][j]= GRID_WALL ;}}// initialise the walls in terms of Three.jsfunction initThreeWalls(){var t =0;for(var i =0; i < GRIDSIZE ; i++){for(var j =0; j < GRIDSIZE ; j++){if( GRID1[i][j]== GRID_WALL ){var shape =new THREE.BoxGeometry( SQUARESIZE, SQUARESIZE, SQUARESIZE );var thecube1 =new THREE.Mesh( shape );var thecube2 =new THREE.Mesh( shape );var thecube3 =new THREE.Mesh( shape );
thecube1.material.color.setHex( BLANKCOLOR );
thecube2.material.color.setHex( BLANKCOLOR );
thecube3.material.color.setHex( BLANKCOLOR );
thecube1.position.x = translate ( i * SQUARESIZE );
thecube1.position.z = translate ( j * SQUARESIZE );
thecube1.position.y =0;
thecube2.position.x = translate ( i * SQUARESIZE );
thecube2.position.z = translate ( j * SQUARESIZE );
thecube2.position.y =1000;
thecube3.position.x = translate ( i * SQUARESIZE );
thecube3.position.z = translate ( j * SQUARESIZE );
thecube3.position.y =2000;
threeworld.scene.add(thecube1);
threeworld.scene.add(thecube2);
threeworld.scene.add(thecube3);
FLOOR_1_WALLS[t]= thecube1;
FLOOR_2_WALLS[t]= thecube2;
FLOOR_3_WALLS[t]= thecube3;
t++;}}}}// paint the wallsfunction paintWalls ( material ){for(var i =0; i < FLOOR_1_WALLS.length; i++){if( FLOOR_1_WALLS[i]){
FLOOR_1_WALLS[i].material = material;
FLOOR_2_WALLS[i].material = material;
FLOOR_3_WALLS[i].material = material;}}}//-------------------- END OF WALL FUNCTIONS --------------------////-------------------- START OF GROUND FUNCTIONS --------------------////initialise the ground logicallyfunction initLogicalGround(){for(var i =0; i < GRIDSIZE ; i++)for(var j =0; j < GRIDSIZE ; j++)
UNDERSIDE[i][j]= GRID_GROUND;}// initialise the ground in terms of Three.jsfunction initThreeGround(){var t =0;for(var i =0; i < GRIDSIZE ; i++){for(var j =0; j < GRIDSIZE ; j++){if( UNDERSIDE[i][j]== GRID_GROUND ){var shape =new THREE.BoxGeometry( SQUARESIZE, SQUARESIZE, SQUARESIZE );var thecube1 =new THREE.Mesh( shape );var thecube2 =new THREE.Mesh( shape );var thecube3 =new THREE.Mesh( shape );
thecube1.material.color.setHex( BLANKCOLOR );
thecube2.material.color.setHex( BLANKCOLOR );
thecube3.material.color.setHex( BLANKCOLOR );
thecube1.position.x = translate ( i * SQUARESIZE );
thecube1.position.z = translate ( j * SQUARESIZE );
thecube1.position.y =-100;
thecube2.position.x = translate ( i * SQUARESIZE );
thecube2.position.z = translate ( j * SQUARESIZE );
thecube2.position.y =900;
thecube3.position.x = translate ( i * SQUARESIZE );
thecube3.position.z = translate ( j * SQUARESIZE );
thecube3.position.y =1900;
threeworld.scene.add(thecube1);
threeworld.scene.add(thecube2);
threeworld.scene.add(thecube3);
FLOOR_1_GROUND[t]= thecube1;
FLOOR_2_GROUND[t]= thecube2;
FLOOR_3_GROUND[t]= thecube3;
t++;}}}}// paint the groundfunction paintGround ( material ){for(var i =0; i < FLOOR_1_GROUND.length; i++){if( FLOOR_1_GROUND[i]) FLOOR_1_GROUND[i].material = material;if( FLOOR_2_GROUND[i]) FLOOR_2_GROUND[i].material = material;if( FLOOR_3_GROUND[i]) FLOOR_3_GROUND[i].material = material;}}//-------------------- END OF GROUND FUNCTIONS --------------------////-------------------- START OF MAZE FUNCTIONS --------------------//// initialise the maze logically, all three floors have a different randomised mazefunction initLogicalMaze(){for(var c=1; c <= NOBOXES ; c++){var i = randomintAtoB(1,GRIDSIZE-2);var j = randomintAtoB(1,GRIDSIZE-2);
GRID1[i][j]= GRID_MAZE ;var m = randomintAtoB(1,GRIDSIZE-2);var n = randomintAtoB(1,GRIDSIZE-2);
GRID2[m][n]= GRID_MAZE ;var t = randomintAtoB(1,GRIDSIZE-2);var u = randomintAtoB(1,GRIDSIZE-2);
GRID3[t][u]= GRID_MAZE ;}}// initialise the maze in terms of Three.js, need separate for loops to ensure that all maze objects on all floors can be recognised and painted etc.function initThreeMaze(){var t =0;var u =0;var v =0;for(var i =0; i < GRIDSIZE ; i++){for(var j =0; j < GRIDSIZE ; j++){if( GRID1[i][j]== GRID_MAZE ){var shape =new THREE.BoxGeometry( SQUARESIZE, SQUARESIZE, SQUARESIZE );var thecube1 =new THREE.Mesh( shape );
thecube1.material.color.setHex( BLANKCOLOR );
thecube1.position.x = translate ( i * SQUARESIZE );
thecube1.position.z = translate ( j * SQUARESIZE );
thecube1.position.y =0;
threeworld.scene.add(thecube1);
FLOOR_1_MAZE[t]= thecube1;
t++;}}}for(var m =0; m < GRIDSIZE ; m++){for(var n =0; n < GRIDSIZE ; n++){if( GRID2[m][n]== GRID_MAZE ){var shape =new THREE.BoxGeometry( SQUARESIZE, SQUARESIZE, SQUARESIZE );var thecube2 =new THREE.Mesh( shape );
thecube2.material.color.setHex( BLANKCOLOR );
thecube2.position.x = translate ( m * SQUARESIZE );
thecube2.position.z = translate ( n * SQUARESIZE );
thecube2.position.y =1000;
threeworld.scene.add(thecube2);
FLOOR_2_MAZE[u]= thecube2;
u++;}}}for(var x =0; x < GRIDSIZE ; x++){for(var y =0; y < GRIDSIZE ; y++){if( GRID3[x][y]== GRID_MAZE ){var shape =new THREE.BoxGeometry( SQUARESIZE, SQUARESIZE, SQUARESIZE );var thecube3 =new THREE.Mesh( shape );
thecube3.material.color.setHex( BLANKCOLOR );
thecube3.position.x = translate ( x * SQUARESIZE );
thecube3.position.z = translate ( y * SQUARESIZE );
thecube3.position.y =2000;
threeworld.scene.add(thecube3);
FLOOR_3_MAZE[v]= thecube3;
v++;}}}}// paint the mazefunction paintMaze ( material ){for(var i =0; i < FLOOR_1_MAZE.length; i++){if( FLOOR_1_MAZE[i]) FLOOR_1_MAZE[i].material = material;if( FLOOR_2_MAZE[i]) FLOOR_2_MAZE[i].material = material;if( FLOOR_3_MAZE[i]) FLOOR_3_MAZE[i].material = material;}}//-------------------- END OF MAZE FUNCTIONS --------------------////-------------------- START OF AGENT (BUGS BUNNY) FUNCTIONS --------------------//// used to draw Bugs Bunny into the world at a certain positionfunction drawAgent(){if(theagent){var x = translate ( ai * SQUARESIZE );var z = translate ( aj * SQUARESIZE );var y = agentFloor;
theagent.position.x = x;
theagent.position.y = y;
theagent.position.z = z;
threeworld.lookat.copy ( theagent.position );}}// initialise Bugs Bunny logically at a random positionfunction initLogicalAgent(){var i, j;do{
i = randomintAtoB(1,GRIDSIZE-2);
j = randomintAtoB(1,GRIDSIZE-2);}while( cannotPlaceObject(i,j));
ai = i;
aj = j;
currentAgentPosition =[ai,aj];// remember the position Bugs is currently at}// moves Bugs Bunny around the world and also rotates him to face the direction that he is currently moving infunction moveLogicalAgent( a ){var i = ai;var j = aj;// if moving left, face the correct direction and moveif( a == ACTION_LEFT ){if(bugsLookingForward){
theagent.rotateY(1*(Math.PI /2));
bugsLookingLeft =true;
bugsLookingForward =false;}elseif(bugsLookingBack){
theagent.rotateY(3*(Math.PI /2));
bugsLookingLeft =true;
bugsLookingBack =false;}elseif(bugsLookingRight){
theagent.rotateY(2*(Math.PI /2));
bugsLookingLeft =true;
bugsLookingRight =false;}
i--;}// if moving right, face the correct direction and moveelseif( a == ACTION_RIGHT ){if(bugsLookingForward){
theagent.rotateY(3*(Math.PI /2));
bugsLookingRight =true;
bugsLookingForward =false;}elseif(bugsLookingBack){
theagent.rotateY(1*(Math.PI /2));
bugsLookingRight =true;
bugsLookingBack =false;}elseif(bugsLookingLeft){
theagent.rotateY(2*(Math.PI /2));
bugsLookingRight =true;
bugsLookingLeft =false;}
i++;}// if moving forward, face the correct direction and moveelseif( a == ACTION_UP ){if(bugsLookingRight){
theagent.rotateY(3*(Math.PI /2));
bugsLookingBack =true;
bugsLookingRight =false;}elseif(bugsLookingForward){
theagent.rotateY(2*(Math.PI /2));
bugsLookingBack =true;
bugsLookingForward =false;}elseif(bugsLookingLeft){
theagent.rotateY(1*(Math.PI /2));
bugsLookingBack =true;
bugsLookingLeft =false;}
j++;}// if moving backward, face the correct direction and moveelseif( a == ACTION_DOWN ){if(bugsLookingRight){
theagent.rotateY(1*(Math.PI /2));
bugsLookingForward =true;
bugsLookingRight =false;}elseif(bugsLookingBack){
theagent.rotateY(2*(Math.PI /2));
bugsLookingForward =true;
bugsLookingBack =false;}elseif(bugsLookingLeft){
theagent.rotateY(3*(Math.PI /2));
bugsLookingForward =true;
bugsLookingLeft =false;}
j--;}if(! occupied(i,j)){// as long as the desired position isn't occupied// set new position for Bugs
ai = i;
aj = j;// remember the position
currentAgentPosition =[ai,aj];// set the new camera position to follow Bugs
ci = i;
cj = j+4;}}// move Bugs Bunny down to the next floor through a burrow, and make Yosemite Sam follow him to the next floorfunction moveAgentDown(){if(agentFloor !=-50&& canBurrow()){// as long as Bugs is standing on a burrow and isn't on the bottom floor where there is nowhere else to burrow to
agentFloor -=1000;
drawAgent();// draw Bugs on the next floor down
playBugsBurrowing();// play burrowing sound effect
moveEnemyDown();// move Yosemite Sam down too}}//-------------------- END OF AGENT (BUGS BUNNY) FUNCTIONS --------------------////-------------------- START OF ENEMY (YOSEMITE SAM) FUNCTIONS --------------------//// used to draw Yosemite Sam into the world at a certain positionfunction drawEnemy(){if(theenemy){var x = translate ( ei * SQUARESIZE );var z = translate ( ej * SQUARESIZE );var y = enemyFloor;
theenemy.position.x = x;
theenemy.position.y = y;
theenemy.position.z = z;}}//initialise Yosemite Sam logically at a certain positionfunction initLogicalEnemy(){var i, j;do{
i = randomintAtoB(1,GRIDSIZE-2);
j = randomintAtoB(1,GRIDSIZE-2);}while( cannotPlaceObject(i,j));
ei = i;
ej = j;
currentEnemyPosition =[ei,ej];// remember the position Yosemite is currently at}//-------------------- START OF A-STAR ALGORITHM PATHFINDING --------------------//// credit for A-Star Algorithm: mainly 2d version here: http://buildnewgames.com/astar/ // another 2d version here: http://www.briangrinstead.com/blog/astar-search-algorithm-in-javascript// this tutorial: http://www.redblobgames.com/pathfinding/a-star/introduction.html// and this video: https://www.youtube.com/watch?v=-L-WgKMFuhEfunction findPath (startingPosition, finishingPosition){var worldSize = GRIDSIZE * GRIDSIZE;// Manhattan Distance is the distance between two points measured along axes at right angles, so no diagonal movement allowedfunction manhattanDistance(Point,Goal){returnMath.abs(Point.x -Goal.x)+Math.abs(Point.y -Goal.y);}var distanceFunction = manhattanDistance;// this function returns an array of every available empty position North, South, East or West of where you are nowfunctionNeighbours(x,y){var N = y-1;var S = y+1;var E = x+1;var W = x-1;
myN = N >-1&&!occupied(x,N);
myS = S < GRIDSIZE &&!occupied(x,S);
myE = E < GRIDSIZE &&!occupied(E,y);
myW = W >-1&&!occupied(W,y);
result =[];if(myN)
result.push({x:x, y:N});if(myE)
result.push({x:E, y:y});if(myS)
result.push({x:x, y:S});if(myW)
result.push({x:W, y:y});return result;}// this function returns a node object that contains possible next routes and their respective costsfunctionNode(Parent,Point){var newNode ={Parent:Parent,// pointer to another Node object
value:Point.x +(Point.y * GRIDSIZE),// array index of this Node
x:Point.x,// the x coordinates of this Node
y:Point.y,// the y coordinates of this node
f:0,// f is the cost to get to this Node from Yosemite's current position
g:0// g is the cost to get from this Node to Bugs' curent position};return newNode;}// this function finds the best path from Yosemite Sam's position to Bugs Bunny's position using the A* Algorithmfunction calculateBestPath(){var pathStart =Node(null,{x:startingPosition[0], y:startingPosition[1]});// a node from the start coordinatesvar pathEnd =Node(null,{x:finishingPosition[0], y:finishingPosition[1]});// a node from the end coordinatesvarAStar=newArray(worldSize);// an array that will contain all positions in the worldvarOpen=[pathStart];// a list of currently open nodesvarClosed=[];// a list of closed nodesvar result =[];// the array that will be returnedvar myNeighbours;// a reference to a node that is nearbyvar currentNode;// a reference to a node that we are now considering takingvar currentPath;// a reference to a node that starts the current path we are considering// temporary variables used in the calculationsvar length, max, min, a, b;while(length =Open.length){// iterate through the open list until there is nothing left
max = worldSize;
min =-1;// get the max and minfor(a =0; a < length; a++){if(Open[a].f < max){
max =Open[a].f;
min = a;}}
currentNode =Open.splice(min,1)[0];// remove the next node from the open array and put it in currentNode// is it the destination node?if( currentNode.value === pathEnd.value ){// if we have reached our destination node (Bugs Bunny's position)
currentPath = currentNode;do{
result.push([currentPath.x, currentPath.y]);}while(currentPath = currentPath.Parent);AStar=Closed=Open=[];// clear the arrays
result.reverse();// reverse the result so as not to return a list from finish to start instead of start to finish}else{// otherwise, it was not our destination
myNeighbours =Neighbours(currentNode.x, currentNode.y);// find which nearby nodes are available to move tofor(a =0, b = myNeighbours.length; a < b; a++){// test each neighbouring node that hasn't been tested already
currentPath =Node(currentNode, myNeighbours[a]);// add to the current path we are consideringif(!AStar[currentPath.value]){
currentPath.g = currentNode.g + distanceFunction(myNeighbours[a], currentNode);// cost of this current route so far
currentPath.f = currentPath.g + distanceFunction(myNeighbours[a], pathEnd);// cost of the current route all the way to the destination (Bugs' position)Open.push(currentPath);// remember this new path by placing it in the open arrayAStar[currentPath.value]=true;// mark this node as having been visited already so as not to have to check it again}}}}// keep iterating while open is not emptyreturn result;}return calculateBestPath();}//-------------------- END OF A-STAR ALGORITHM PATHFINDING --------------------//// moves Yosemite Sam around the world chasing Bugs Bunny according to the A* Pathfinding Algorithm// and also rotates him to face the direction that he is currently moving infunction findBestPathToAgent(){var newPathArray =[];var i, j;
newPathArray =(findPath(currentEnemyPosition,currentAgentPosition));// find the best path to Bugs' position and store it in newPathArray// store the first best possible move to make to reach bugs in the i and j coordinates
i = newPathArray[1][0];
j = newPathArray[1][1];// if moving left, face the correct direction and moveif( i < ei && j == ej ){if(samLookingForward){
theenemy.rotateY(1*(Math.PI /2));
samLookingLeft =true;
samLookingForward =false;}elseif(samLookingBack){
theenemy.rotateY(3*(Math.PI /2));
samLookingLeft =true;
samLookingBack =false;}elseif(samLookingRight){
theenemy.rotateY(2*(Math.PI /2));
samLookingLeft =true;
samLookingRight =false;}}// if moving right, face the correct direction and moveelseif( i > ei && j == ej ){if(samLookingForward){
theenemy.rotateY(3*(Math.PI /2));
samLookingRight =true;
samLookingForward =false;}elseif(samLookingBack){
theenemy.rotateY(1*(Math.PI /2));
samLookingRight =true;
samLookingBack =false;}elseif(samLookingLeft){
theenemy.rotateY(2*(Math.PI /2));
samLookingRight =true;
samLookingLeft =false;}}// if moving forward, face the correct direction and moveelseif( i == ei && j > ej ){if(samLookingRight){
theenemy.rotateY(3*(Math.PI /2));
samLookingBack =true;
samLookingRight =false;}elseif(samLookingForward){
theenemy.rotateY(2*(Math.PI /2));
samLookingBack =true;
samLookingForward =false;}elseif(samLookingLeft){
theenemy.rotateY(1*(Math.PI /2));
samLookingBack =true;
samLookingLeft =false;}}// if moving backward, face the correct direction and moveelseif( i == ei && j < ej ){if(samLookingRight){
theenemy.rotateY(1*(Math.PI /2));
samLookingForward =true;
samLookingRight =false;}elseif(samLookingBack){
theenemy.rotateY(2*(Math.PI /2));
samLookingForward =true;
samLookingBack =false;}elseif(samLookingLeft){
theenemy.rotateY(3*(Math.PI /2));
samLookingForward =true;
samLookingLeft =false;}}// set new position for Yosemite Sam
ei = i;
ej = j;
currentEnemyPosition =[ei,ej];// remember the position}// move Yosemite Sam down to the next floor to follow Bugs as long as he isn't already on the bottom floorfunction moveEnemyDown(){if(enemyFloor !=-50){// pick a random position to start off in on the next floor downvar i, j;do{
i = randomintAtoB(1,GRIDSIZE-2);
j = randomintAtoB(1,GRIDSIZE-2);}while( cannotPlaceObject(i,j));// search for empty square // set the new position
ei = i;
ej = j;// remember the position
currentEnemyPosition =[ei,ej];// set the new floor
enemyFloor -=1000;// draw Yosemite Sam in his new position on the next floor
drawEnemy();}}//-------------------- END OF ENEMY (YOSEMITE SAM) FUNCTIONS --------------------////-------------------- CAMERA FUNCTIONS --------------------//// draw the camera object that will follow Bugs Bunnyfunction drawCamera(){var x = translate ( ci * SQUARESIZE );var z = translate ( cj * SQUARESIZE );var y = agentFloor+350;// set the camera above Bugs Bunny
thecamera.position.x = x;
thecamera.position.y = y;
thecamera.position.z = z;
threeworld.scene.add(thecamera);
threeworld.follow.copy ( thecamera.position );}// initialise the camera to be 4 steps behind Bugsfunction initLogicalCamera(){
ci = ai;
cj = aj+4;}// initialise the camera in terms of Three.js to avoid errors, basically just make it an invisible box and draw itfunction initThreeCamera(){var shape =new THREE.BoxGeometry(0,0,0);
thecamera =new THREE.Mesh( shape );
drawCamera();}//-------------------- CARROT FUNCTIONS --------------------//// draw the carrot object on the bottom floorfunction drawCarrot(){if(thecarrot){var x = translate ( ti * SQUARESIZE );var z = translate ( tj * SQUARESIZE );var y =-50;
thecarrot.position.x = x;
thecarrot.position.y = y;
thecarrot.position.z = z;}}//initialise the carrot logically in a random positionfunction initLogicalCarrot(){var i, j;do{
i = randomintAtoB(1,GRIDSIZE-2);
j = randomintAtoB(1,GRIDSIZE-2);}while( cannotPlaceObject(i,j));// set the position of the carrot
ti = i;
tj = j;}//-------------------- BURROW FUNCTIONS --------------------//// draw the burrow on the top floorfunction drawTopBurrow(){if(topfloorburrow){var x = translate ( b1i * SQUARESIZE );var z = translate ( b1j * SQUARESIZE );var y =1950;
topfloorburrow.position.x = x;
topfloorburrow.position.y = y;
topfloorburrow.position.z = z;}}// draw the burrow on the middle floorfunction drawMidBurrow(){if(midfloorburrow){var x = translate ( b2i * SQUARESIZE );var z = translate ( b2j * SQUARESIZE );var y =950;
midfloorburrow.position.x = x;
midfloorburrow.position.y = y;
midfloorburrow.position.z = z;}}//initialise the top burrow logically in a random positionfunction initLogicalTopBurrow(){var i, j;do{
i = randomintAtoB(1,GRIDSIZE-2);
j = randomintAtoB(1,GRIDSIZE-2);}while( cannotPlaceObject(i,j));// set the position of the top burrow
b1i = i;
b1j = j;}//initialise the middle burrow logically in a random positionfunction initLogicalMidBurrow(){var i, j;do{
i = randomintAtoB(1,GRIDSIZE-2);
j = randomintAtoB(1,GRIDSIZE-2);}while( cannotPlaceObject(i,j));// set the position of the middle burrow
b2i = i;
b2j = j;}// this function handles user controls to move Bugs around the worldfunction keyHandler(e){if(e.keyCode ==37)
moveLogicalAgent ( ACTION_LEFT );if(e.keyCode ==38)
moveLogicalAgent ( ACTION_DOWN );if(e.keyCode ==39)
moveLogicalAgent ( ACTION_RIGHT );if(e.keyCode ==40)
moveLogicalAgent ( ACTION_UP );if(e.keyCode ==83)
moveAgentDown();}//-------------------- GENERAL GAME FUNCTIONS, RULES, INTERFACE ETC. --------------------// // checks if Yosemite Sam has caught Bugsfunction bugsCaught(){return(ai == ei && aj == ej);}// checks if Bugs has reached the carrotfunction reachedCarrot(){return(ai == ti && aj == tj);}// returns the floor that bugs is currently onfunction getBugsFloor(){var printFloor;if(agentFloor ==1950){
printFloor =3;}elseif(agentFloor ==950){
printFloor =2;}else{
printFloor =1;}return printFloor;}// this is called before anyone has moved on this step, agent has just proposed an actionfunction updateStatusBefore(a){// show the current step and floorvar status =" <b> Step: "+ step +" Floor: <b> "+ getBugsFloor();
$("#user_span3").html( status );}// new state after both have movedfunction updateStatusAfter(){var status ="..... Click 'Move With' for best gaming experience";
$("#user_span4").html( status );var status ="..... Burrow to Floor 1 and Get the Carrot without being Caught to win ..... Press 's' to burrow";
$("#user_span5").html( status );}this.endCondition;// if set to true the run will end. this.newRun =function(){this.endCondition =false;
step =0;// whether graphical run or not, initialise all of these:
initGrid();
initUnderside();
initLogicalWalls();
initLogicalMaze();
initLogicalAgent();
initLogicalGround();
initLogicalEnemy();
initLogicalCamera();
initLogicalCarrot();
initLogicalTopBurrow();
initLogicalMidBurrow();// for graphical runs initialise these:if(true){
threeworld.init3d ( STARTRADIUSCONST, MAXRADIUSCONST, SKYCOLOR );// add in ambient light to the worldvar ambient =new THREE.AmbientLight();
threeworld.scene.add( ambient );var thelight =new THREE.DirectionalLight( LIGHTCOLOR,3);
thelight.position.set( STARTRADIUSCONST, STARTRADIUSCONST, STARTRADIUSCONST );
threeworld.scene.add(thelight);
initSkybox();
initMusic();
initThreeWalls();
initThreeMaze();
initThreeGround();
initThreeCamera();
loadTextures();
document.onkeydown = keyHandler;}};this.getState =function(){var x =[ ai, aj, ei, ej ];return( x );};this.nextStep =function(){var a =4;
step++;if(true)
updateStatusBefore(a);// show status line before moves
moveLogicalAgent(a);if(( step %3)==0)// slow the enemy down to every 3rd step the user takes
findBestPathToAgent();// chase Bugsif(true){// draw all of these:
drawAgent();
drawEnemy();
drawCamera();
drawCarrot();
drawTopBurrow();
drawMidBurrow();
updateStatusAfter();// show status line after moves }// if Bugs Bunny has been caughtif( bugsCaught()){this.endCondition =true;if(true){
musicPause();// pause the music
playBugsLoses();// play soundbite of Bugs being upset}}// if Bugs has reached the carrotif( reachedCarrot()){this.endCondition =true;if(true){
musicPause();// pause the music
playBugsWins();// play soundbite of Bugs being happy}}};this.endRun =function(){if(true){
musicPause();if(this.endCondition ){// if Bugs was caught, print this message to the screen:if( bugsCaught())
$("#user_span6").html("<br> <font color=red> <B> You've been caught! You Reached floor "+ getBugsFloor()+"</B> </font>");// if Bugs reached the carrot, print this message to the screen:if( reachedCarrot())
$("#user_span6").html("<br> <font color=red> <B> You Got The Carrot! You Win! </B> </font>");}// otherwise, the user ran our of steps, so print this message:else
$("#user_span6").html("<br> <font color=red> <B> You Ran out of steps! . </B> </font> ");}};}//-------------------- END OF WORLD CLASS --------------------////-------------------- MUSIC AND SOUND EFFECTS --------------------//// credit: http://junglevibe23.net/tracks/barber_of_seville.htmlfunction initMusic(){// put music element in one of the spansvar x ="<audio id=theaudio src=/uploads/seansinnott/barberofseville.mp3 autoplay loop> </audio>";
$("#user_span1").html( x );}function musicPlay(){
document.getElementById('theaudio').play();}function musicPause(){
document.getElementById('theaudio').pause();}// credit: http://www.nonstick.com/bugs-bunny-sounds/function playBugsWins(){var x ="<audio src=/uploads/seansinnott/bugswins.mp3 autoplay > </audio>";
$("#user_span2").html( x );}// credit: http://www.nonstick.com/bugs-bunny-sounds/function playBugsLoses(){var x ="<audio src=/uploads/seansinnott/bugsloses.mp3 autoplay > </audio>";
$("#user_span2").html( x );}// credit: http://www.sounddogs.com/previews/2213/mp3/349472_SOUNDDOGS__di.mp3function playBugsBurrowing(){var x ="<audio src=/uploads/seansinnott/burrowing.mp3 autoplay > </audio>";
$("#user_span2").html( x );}