//Due to time constraints, parts of the code are very long as I didnt have time to identify any redundant code and remove it.
//I hope the comments and naming conventions make it as clear as possible, Thank you.
const CLOCKTICK = 150; // speed of run - move things every n milliseconds
const MAXSTEPS = 1000; // length of a run before final score
const SCREENSHOT_STEP = 50;
//---- global constants: -------------------------------------------------------
const gridsize = 15; // number of squares along side of world
const squaresize = 100; // size of square in pixels
const MAXPOS = gridsize * squaresize; // length of one side in pixels
const NOBOXES = Math.trunc ( (gridsize * gridsize) / 15 );
const SKYCOLOR = 0xffffcc; // a number, not a string
const BLANKCOLOR = SKYCOLOR; // make objects this color until texture arrives (from asynchronous file read)
const LIGHTCOLOR = 0xffffff;
const startRadiusConst = MAXPOS * 0.8; // distance from centre to start the camera at
const skyboxConst = MAXPOS * 3; // where to put skybox
const maxRadiusConst = MAXPOS * 5; // maximum distance from camera we will render things
//--- Mind can pick one of these actions -----------------
const ACTION_LEFT = 0;
const ACTION_RIGHT = 1;
const ACTION_UP = 2;
const ACTION_DOWN = 3;
const ACTION_STAYSTILL = 4;
const DROP_BOMB = 5;
// contents of a grid square
const GRID_BLANK = 0;
const GRID_WALL = 1;
const GRID_MAZE = 2;
const GRID_WEAK = 3; //Weak walls can be blown up with bombs
const GRID_BOMB = 4;
// --- some useful random functions -------------------------------------------
function randomfloatAtoB ( A, B )
{
return ( A + ( Math.random() * (B-A) ) );
}
function randomintAtoB ( A, B )
{
return ( Math.round ( randomfloatAtoB ( A, B ) ) );
}
function randomBoolean()
{
if ( Math.random() < 0.5 )
return false;
else
return true;
}
function randomPick ( a, b )
{
if ( randomBoolean() )
return a;
else
return b;
}
//---- start of World class -------------------------------------------------------
function World() {
// most of World can be private
// regular "var" syntax means private variables:
var GRID = new Array (gridsize); // can query GRID about whether squares are occupied, will in fact be initialised as a 2D array
var WALLS = new Array ( 4 * gridsize ); // need to keep handle to each wall block object so can find it later to paint it
var STRONGCUBES = new Array ( NOBOXES );
var WEAKCUBES = new Array ( NOBOXES );
var EXPLOSIONS = new Array ( NOBOXES );
var theagent, theenemy, agentBomb, enemyBomb;
var agentRotation = 0;
var enemyRotation = 0; // with 3D models, current rotation away from default orientation
// enemy and agent position on squares
var ei , ej, ai, aj, agentbombi, agentbombj, enemybombi, enemybombj;
var self = this; // needed for private fn to call public fn - see below
var steps;
var agentbombExploding = false;
var enemybombExploding = false;
var enemyBombPlaced = false;
var agentmiddle; //Explosion in four diections
var agentleftBlock;
var agentrightBlock;
var agentupBlock;
var agentdownBlock;
var enemymiddle; //Explosion in four diections
var enemyleftBlock;
var enemyrightBlock;
var enemyupBlock;
var enemydownBlock;
function initGrid()
{
for (var i = 0; i < gridsize ; i++)
{
GRID[i] = new Array(gridsize); // each element is an array
for (var j = 0; j < gridsize ; j++)
{
GRID[i][j] = GRID_BLANK ;
}
}
}
function occupied ( i, j ) // is this square occupied
{
// variable objects
if ( ( ei == i ) && ( ej == j ) )
return true; // variable objects
if ( ( ai == i ) && ( aj == j ) )
return true;
if ( ( agentbombi == i ) && ( agentbombj == j ) )
return true;
if ( ( enemybombi == i ) && ( enemybombj == j ) )
return true;
if ( GRID[i][j] == GRID_WEAK )
return true;
// fixed objects
if ( GRID[i][j] == GRID_WALL )
return true;
if ( GRID[i][j] == GRID_MAZE )
return true;
return false;
}
function translate ( x )
{
return ( x - ( MAXPOS/2 ) );
}
function loadTextures()
{
var manager = new THREE.LoadingManager();
var loader = new THREE.OBJLoader( manager );
// load OBJ plus MTL (plus TGA files)
THREE.Loader.Handlers.add( /.tga$/i, new THREE.TGALoader() );
var m = new THREE.MTLLoader();
m.setTexturePath ( "/uploads/starter/" );
m.setPath ( "/uploads/starter/" );
m.load( "Peter_Parker.mtl", function( materials ) {
materials.preload();
var o = new THREE.OBJLoader();
o.setMaterials ( materials );
o.setPath ( "/uploads/starter/" );
o.load( "Peter_Parker.obj", function ( object ) {
buildenemy ( object );
} );
} );
// load OBJ plus MTL (plus TGA files)
m.load( "Peter_Parker.mtl", function( materials ) {
materials.preload();
var o = new THREE.OBJLoader();
o.setMaterials ( materials );
o.setPath ( "/uploads/starter/" );
o.load( "Peter_Parker.obj", function ( object ) {
buildagent ( object );
} );
} );
//change path
m.setPath ( "/uploads/mcadamm4/" );
m.load( "bomb.mtl", function( materials ) {
materials.preload();
var o = new THREE.OBJLoader();
o.setMaterials ( materials );
o.setPath ( "/uploads/mcadamm4/" );
o.load( "bomb.obj", function ( object ) {
buildAgentBomb ( object );
} );
} );
m.load( "bomb.mtl", function( materials ) {
materials.preload();
var o = new THREE.OBJLoader();
o.setMaterials ( materials );
o.setPath ( "/uploads/mcadamm4/" );
o.load( "bomb.obj", function ( object ) {
buildEnemyBomb ( object );
} );
} );
var loader1 = new THREE.TextureLoader();
loader1.load ( '/uploads/mcadamm4/novaexplosion.jpg', function ( thetexture ) {
thetexture.minFilter = THREE.LinearFilter;
paintExplosion ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
} );
var loader2 = new THREE.TextureLoader();
loader2.load ( '/uploads/mcadamm4/blocks.jpg', function ( thetexture ) {
thetexture.minFilter = THREE.LinearFilter;
paintWalls ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
} );
var loader3 = new THREE.TextureLoader();
loader3.load ( '/uploads/mcadamm4/blocks.jpg', function ( thetexture ) {
thetexture.minFilter = THREE.LinearFilter;
paintStrongBlocks ( new THREE.MeshBasicMaterial( { map: thetexture } ));
} );
var loader4 = new THREE.TextureLoader();
loader4.load ( '/uploads/mcadamm4/wood.jpg', function ( thetexture ) {
thetexture.minFilter = THREE.LinearFilter;
paintWeakBlocks ( new THREE.MeshBasicMaterial( { map: thetexture } ));
} );
}
function initSkybox()
{
// urban photographic skyboxes, credit:
// http://opengameart.org/content/urban-skyboxes
var materialArray = [
( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/dawnmountain-xpos.png" ), side: THREE.BackSide } ) ),
( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/dawnmountain-xneg.png" ), side: THREE.BackSide } ) ),
( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/dawnmountain-ypos.png" ), side: THREE.BackSide } ) ),
( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/dawnmountain-yneg.png" ), side: THREE.BackSide } ) ),
( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/dawnmountain-zpos.png" ), side: THREE.BackSide } ) ),
( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/dawnmountain-zneg.png" ), 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 ); // We are inside a giant cube
}
function initLogicalWalls() // set up logical walls in data structure, whether doing graphical run or not
{
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 ) )
{
GRID[i][j] = GRID_WALL;
}
}
function initThreeWalls() // graphical run only, set up blank boxes, painted later
{
var t = 0;
for (var i = 0; i < gridsize ; i++)
for (var j = 0; j < gridsize ; j++)
if ( GRID[i][j] == GRID_WALL )
{
var shape = new THREE.BoxGeometry( squaresize, squaresize, squaresize );
var thecube = new THREE.Mesh( shape );
thecube.material.color.setHex( BLANKCOLOR );
thecube.position.x = translate ( i * squaresize ); // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates
thecube.position.z = translate ( j * squaresize );
thecube.position.y = 0;
threeworld.scene.add(thecube);
WALLS[t] = thecube; // save it for later
t++;
}
}
function initThreeMaze()
{
var t1 = 0;
var t2 = 0;
for (var i = 0; i < gridsize ; i++)
for (var j = 0; j < gridsize ; j++)
if ( GRID[i][j] == GRID_MAZE )
{
var strongShape = new THREE.BoxGeometry( squaresize, squaresize, squaresize );
var strongCube = new THREE.Mesh( strongShape );
strongCube.material.color.setHex( BLANKCOLOR );
strongCube.position.x = translate ( i * squaresize );
strongCube.position.z = translate ( j * squaresize );
strongCube.position.y = 0;
threeworld.scene.add(strongCube);
STRONGCUBES[t1] = strongCube; // save it for later
t1++;
}
else if ( GRID[i][j] == GRID_WEAK )
{
var weakShape = new THREE.BoxGeometry( squaresize, squaresize, squaresize );
var weakCube = new THREE.Mesh( weakShape );
weakCube.material.color.setHex( BLANKCOLOR );
weakCube.position.x = translate ( i * squaresize );
weakCube.position.z = translate ( j * squaresize );
weakCube.position.y = 0;
threeworld.scene.add(weakCube);
WEAKCUBES[t2] = weakCube; // save it for later
t2++;
}
}
var strongArray = new Array(7); //This sets out the positions of the strong blocks on the grid
strongArray[0] = [5,9];
strongArray[1] = [2,4,5,6,8,9,10,12];
strongArray[2] = [2,12];
strongArray[3] = [2,3,5,6,8,9,11,12];
strongArray[4] = [5,9]
strongArray[5] = [2,3,5,7,9,11,12];
strongArray[6] = [1,2,7,12,13];
function initLogicalStrongBlocks() //Strong blocks cannot be blown up
{
var i = 0;
for(var j=1; j<=7; j++) //Top half of grid
{
for(var n=0; n<strongArray[i].length; n++)
{
GRID[strongArray[i][n]][j] = GRID_MAZE;
}
i++;
}
var k=0;
for(var l=13; l>=8; l--) //Bottom half of grid
{
for(var m=0; m<strongArray[k].length; m++)
{
GRID[strongArray[k][m]][l] = GRID_MAZE;
}
k++;
}
}
var weakArray = new Array(7); //This sets out the positions of the weak blocks on the grid
weakArray[0] = [8];
weakArray[1] = [1,3,7,11,13];
weakArray[2] = [5,9];
weakArray[3] = [1,7];
weakArray[4] = [2,3,11,12]
weakArray[5] = [6,8];
weakArray[6] = [4,10];
function initLogicalWeakBlocks() //Weak blocks can be blown up
{
var i = 0;
for(var j=1; j<=7; j++) //Top half of the grid
{
for(var n=0; n<weakArray[i].length; n++)
{
GRID[weakArray[i][n]][j] = GRID_WEAK;
}
i++;
}
var k=0;
for(var l=13; l>=8; l--) //Bottom half of the grid
{
for(var m=0; m<weakArray[k].length; m++)
{
GRID[weakArray[k][m]][l] = GRID_WEAK;
}
k++;
}
}
//PAINT
function paintEnemy ( child )
{
if ( child instanceof THREE.Mesh )
{
child.material.map = THREE.ImageUtils.loadTexture( "/uploads/starter/ghost.3.png" );
}
}
function paintAgent ( child )
{
if ( child instanceof THREE.Mesh )
{
child.material.map = THREE.ImageUtils.loadTexture( "/uploads/starter/pacman.jpg" );
}
}
function paintWalls ( material )
{
for ( var i = 0; i < WALLS.length; i++ )
{
if ( WALLS[i] )
WALLS[i].material = material;
}
}
function paintStrongBlocks ( material )
{
for ( var i = 0; i < STRONGCUBES.length; i++ )
{
if ( STRONGCUBES[i] )
STRONGCUBES[i].material = material;
}
}
function paintWeakBlocks ( material )
{
for ( var i = 0; i < WEAKCUBES.length; i++ )
{
if ( WEAKCUBES[i] )
WEAKCUBES[i].material = material;
}
}
function paintExplosion( material )
{
for(var i=0; i<=10; i++)
{
var shape = new THREE.SphereGeometry( 80, 80, 80 );
var sphere = new THREE.Mesh( shape );
sphere.material.color.setHex( BLANKCOLOR );
EXPLOSIONS[i] = sphere;
EXPLOSIONS[i].material = material;
}
}
// --- ENEMY -----------------------------------
function initLogicalEnemy()
{
ei = 1;
ej = 1;
}
function buildenemy ( object )
{
object.scale.multiplyScalar ( 50 ); // make 3d object n times bigger
object.traverse( paintEnemy );
theenemy = object;
//Starting Position of enemy one
theenemy.position.x = translate ( 1 * squaresize );
theenemy.position.y = ( -50 );
theenemy.position.z = translate ( 1 * squaresize );
threeworld.scene.add( theenemy );
}
function drawEnemy() // given ei, ej, draw it
{
if ( theenemy )
{
var x = translate ( ei * squaresize );
var z = translate ( ej * squaresize );
var y = -50;
theenemy.position.x = x;
theenemy.position.y = y;
theenemy.position.z = z;
threeworld.lookat.copy ( theenemy.position ); // if camera moving, look back at where the enemy is
threeworld.lookat.y = ( squaresize * 1.5 ); // point camera higher up
}
}
function igetAction()
{
if ( ei < ai )
return ( ACTION_RIGHT );
if ( ei > ai )
return ( ACTION_LEFT );
return ( ACTION_STAYSTILL );
}
function jgetAction()
{
if ( ej < aj )
return ( ACTION_UP );
if ( ej > aj )
return ( ACTION_DOWN );
return ( ACTION_STAYSTILL );
}
function enemyGetAction()
{
return randomPick ( igetAction(), jgetAction() );
}
function moveLogicalEnemy()
{
if(!enemyBombPlaced) //Enemy moves randomly until he sets a bomb, then he must escape the bombs blast
var a = enemyGetAction();
var i = ei;
var j = ej;
var bool = false;
if( occupiedByAgentBomb((ei-1),ej) || //Is there an agent bomb nearby that he must escape
occupiedByAgentBomb((ei+1),ej) ||
occupiedByAgentBomb(ei,(ej-1)) ||
occupiedByAgentBomb(ei,(ej+1)))
{
bool = true; //Make sure enemy dosnt move again after escaping
switch (esacpeDirection())
//Quite a few of the cases may be redundant if I have time I can cut the cases down
//by coupling AND's that have equivelant effects in the esacpeDirection() method
{
case 0://Left
i-=2;
ei = i;
ej = j;
break;
case 1://Right
i+=2;
ei = i;
ej = j;
break;
case 2://Up
j-=2;
ei = i;
ej = j;
break;
case 3://Down
j+=2;
ei = i;
ej = j;
break;
case 4://Left & Up
i--;
j--;
ei = i;
ej = j;
break;
case 5://Left & Down
i--;
j++;
ei = i;
ej = j;
break;
case 6://Right & Up
i++;
j--;
ei = i;
ej = j;
break;
case 7://Right & Down
i++;
j++;
ei = i;
ej = j;
break;
case 8://Down & Left
j++;
i--;
ei = i;
ej = j;
break;
case 9://Down & right
j++;
i++;
ei = i;
ej = j;
break;
case 10://Up and left
j--;
i--;
ei = i;
ej = j;
break;
case 11://Up and right
j--;
i++;
ei = i;
ej = j;
break;
case 12:
break;
}
}
if( occupiedByPlayer((ei-1),ej) ||
occupiedByPlayer((ei+1),ej) ||
occupiedByPlayer(ei,(ej-1)) ||
occupiedByPlayer(ei,(ej+1)) ||
occupiedByWeakBox((ei-1),ej) ||
occupiedByWeakBox((ei+1),ej) ||
occupiedByWeakBox(ei,(ej-1)) ||
occupiedByWeakBox(ei,(ej+1)))
{
bool = true;
switch (esacpeDirection())
//Quite a few of the cases may be redundant if I have time I can cut the cases down
//by coupling AND's with equivelant effects in the esacpeDirection() method
{
case 0://Left
i-=2;
enemyDrawBomb( ei, ej );
console.log(i,j);
ei = i;
ej = j;
break;
case 1://Right
i+=2;
enemyDrawBomb( ei, ej );
console.log(i,j);
ei = i;
ej = j;
break;
case 2://Up
j-=2;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 3://Down
j+=2;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 4://Left & Up
i--;
j--;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 5://Left & Down
i--;
j++;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 6://Right & Up
i++;
j--;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 7://Right & Down
i++;
j++;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 8://Down & Left
j++;
i--;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 9://Down & right
j++;
i++;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 10://Up and left
j--;
i--;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 11://Up and right
j--;
i++;
enemyDrawBomb( ei, ej );
ei = i;
ej = j;
break;
case 12:
break;
}
}
if ( a == ACTION_LEFT && !bool) //If just moving randomly and not escaping his bomb
i--;
else if ( a == ACTION_RIGHT && !bool)
i++;
else if ( a == ACTION_UP && !bool)
j++;
else if ( a == ACTION_DOWN && !bool)
j--;
if ( !occupied(i,j) && !bool )
{
if ( true )
{
if ( a == ACTION_LEFT )
rotateEnemyTowards ( 3 * (Math.PI / 2) );
else if ( a == ACTION_RIGHT )
rotateEnemyTowards ( 1 * (Math.PI / 2) );
else if ( a == ACTION_UP )
rotateEnemyTowards ( 0 * (Math.PI / 2) );
else if ( a == ACTION_DOWN )
rotateEnemyTowards ( 2 * (Math.PI / 2) );
}
ei = i;
ej = j;
}
}
function esacpeDirection() //This method allows the enemy to escape the blasts of bombs if there is space
{
if (!occupied((ei-1),ej) && !occupied((ei-2),ej))
return 0; //Left
if(!occupied((ei+1),ej) && !occupied((ei+2),ej))
return 1; //Right
if(!occupied(ei,(ej-1)) && !occupied(ei,(ej-2)))
return 2; //Up
if(!occupied(ei,(ej+1)) && !occupied(ei,(ej+2)))
return 3; //Down
if(!occupied((ei-1),ej) && !occupied((ei-1),(ej-1)))
return 4; //Left & Up
if(!occupied((ei-1),ej) && !occupied((ei-1),(ej+1)))
return 5;//Left & Down
if(!occupied((ei+1),ej) && !occupied((ei+1),(ej-1)))
return 6;//Right & Up
if(!occupied((ei+1),ej) && !occupied((ei+1),(ej+1)))
return 7;//Right & Down
if(!occupied(ei,(ej+1)) && !occupied((ei-1),(ej+1)))
return 8;//Down & Left
if(!occupied(ei,(ej+1)) && !occupied((ei+1),(ej+1)))
return 9;//Down & right
if(!occupied(ei,(ej-1)) && !occupied((ei-1),(ej-1)))
return 10;//Up and left
if(!occupied(ei,(ej-1)) && !occupied((ei+1),(ej-1)))
return 11;//Up and right
else
return 12;//No escape route
}
const INTERIMROT = 10; // number of interim rotations drawn when model turns round
// interim renders not working
// temporary solution - rotate half-way - will continue the rotation later
function rotateEnemyTowards ( newRotation )
{
if ( enemyRotation == newRotation )
return;
var x = ( enemyRotation + newRotation ) / 2;
theenemy.rotation.set ( 0, x, 0 );
enemyRotation = x;
}
function buildAgentBomb( object )
{
object.scale.multiplyScalar ( 300 ); // make 3d object n times bigger
agentBomb = object;
}
function buildEnemyBomb( object )
{
object.scale.multiplyScalar ( 300 ); // make 3d object n times bigger
enemyBomb = object;
}
//DROP A BOMB
function agentDrawBomb( )
{
agentbombi = ai; //Drop bomb at agents position
agentbombj = aj;
agentBomb.position.x = theagent.position.x;
agentBomb.position.y = (theagent.position.y + 50);
agentBomb.position.z = theagent.position.z;
threeworld.scene.add( agentBomb ); // Add a bomb
setTimeout(agentBombExplode, 2000); //Delay the bombs explosion so agent can clear the area
setTimeout(removeAgentBomb, 2000); //Delay the bombs removal to coincide with explosion
}
function enemyDrawBomb( enemyi, enemyj )
{
enemyBombPlaced = true;
enemybombi = enemyi; //Drop bomb at enemy's position
enemybombj = enemyj;
enemyBomb.position.x = theenemy.position.x;
enemyBomb.position.y = (theenemy.position.y + 50);
enemyBomb.position.z = theenemy.position.z;
threeworld.scene.add( enemyBomb ); // Add a bomb
setTimeout(enemyBombExplode, 2000); //Delay the bombs explosion enemy can clear the area
setTimeout(removeEnemyBomb, 2000); //Delay the bombs removal to coincide with explosion
}
function removeAgentBomb()
{
threeworld.scene.remove( agentBomb );
}
function removeEnemyBomb()
{
threeworld.scene.remove( enemyBomb );
enemyBombPlaced = false;
}
function agentBombExplode()
{
agentmiddle = EXPLOSIONS[0]; //Show explosions and then remove them
agentleftBlock = EXPLOSIONS[1];
agentrightBlock = EXPLOSIONS[2];
agentupBlock = EXPLOSIONS[3];
agentdownBlock = EXPLOSIONS[4];
//-------------------------------------------
//The explosions form a cross so five need to be added
var x = translate ( agentbombi * squaresize );
var z = translate ( agentbombj * squaresize );
var y = ( 0 );
agentmiddle.position.x = x;
agentmiddle.position.y = y;
agentmiddle.position.z = z;
threeworld.scene.add(agentmiddle);
//-------------------------------------------
var leftx = translate ( (agentbombi-1) * squaresize );
var leftz = translate ( agentbombj * squaresize );
var lefty = ( 0 );
agentleftBlock.position.x = leftx;
agentleftBlock.position.y = lefty;
agentleftBlock.position.z = leftz;
threeworld.scene.add(agentleftBlock);
//-------------------------------------------
var rightx = translate ( (agentbombi+1) * squaresize );
var rightz = translate ( agentbombj * squaresize );
var righty = ( 0 );
agentrightBlock.position.x = rightx;
agentrightBlock.position.y = righty;
agentrightBlock.position.z = rightz;
threeworld.scene.add(agentrightBlock);
//-------------------------------------------
var upx = translate ( agentbombi * squaresize );
var upz = translate ( (agentbombj-1) * squaresize );
var upy = ( 0 );
agentupBlock.position.x = upx;
agentupBlock.position.y = upy;
agentupBlock.position.z = upz;
threeworld.scene.add(agentupBlock);
//-------------------------------------------
var downx = translate ( agentbombi * squaresize );
var downz = translate ( (agentbombj+1) * squaresize );
var downy = ( 0 );
agentdownBlock.position.x = downx;
agentdownBlock.position.y = downy;
agentdownBlock.position.z = downz;
threeworld.scene.add(agentdownBlock);
setTimeout(removeAgentExplosion, 500);
//-------------------------------------------
//Remove any weak blocks that were hit in the blast
for( var n=0; n<WEAKCUBES.length; n++ )
{
if( WEAKCUBES[n].position.x == leftx && WEAKCUBES[n].position.z == leftz)
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[(agentbombi-1)][agentbombj] = GRID_BLANK;
}
if( WEAKCUBES[n].position.x == rightx && WEAKCUBES[n].position.z == rightz)
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[(agentbombi+1)][agentbombj] = GRID_BLANK;
}
if( WEAKCUBES[n].position.x == upx && WEAKCUBES[n].position.z == upz)
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[agentbombi][(agentbombj-1)] = GRID_BLANK;
}
if( WEAKCUBES[n].position.x == downx && WEAKCUBES[n].position.z == downz )
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[agentbombi][(agentbombj+1)] = GRID_BLANK;
}
agentbombExploding = true;
}
//-------------------------------------------
}
function enemyBombExplode()
{
enemymiddle = EXPLOSIONS[5]; //Show explosions and then remove them
enemyleftBlock = EXPLOSIONS[6];
enemyrightBlock = EXPLOSIONS[7];
enemyupBlock = EXPLOSIONS[8];
enemydownBlock = EXPLOSIONS[9];
//-------------------------------------------
var x = translate ( enemybombi * squaresize );
var z = translate ( enemybombj * squaresize );
var y = ( 0 );
enemymiddle.position.x = x;
enemymiddle.position.y = y;
enemymiddle.position.z = z;
threeworld.scene.add(enemymiddle);
//-------------------------------------------
var leftx = translate ( (enemybombi-1) * squaresize );
var leftz = translate ( enemybombj * squaresize );
var lefty = ( 0 );
enemyleftBlock.position.x = leftx;
enemyleftBlock.position.y = lefty;
enemyleftBlock.position.z = leftz;
threeworld.scene.add(enemyleftBlock);
//-------------------------------------------
var rightx = translate ( (enemybombi+1) * squaresize );
var rightz = translate ( enemybombj * squaresize );
var righty = ( 0 );
enemyrightBlock.position.x = rightx;
enemyrightBlock.position.y = righty;
enemyrightBlock.position.z = rightz;
threeworld.scene.add(enemyrightBlock);
//-------------------------------------------
var upx = translate ( enemybombi * squaresize );
var upz = translate ( (enemybombj-1) * squaresize );
var upy = ( 0 );
enemyupBlock.position.x = upx;
enemyupBlock.position.y = upy;
enemyupBlock.position.z = upz;
threeworld.scene.add(enemyupBlock);
//-------------------------------------------
var downx = translate ( enemybombi * squaresize );
var downz = translate ( (enemybombj+1) * squaresize );
var downy = ( 0 );
enemydownBlock.position.x = downx;
enemydownBlock.position.y = downy;
enemydownBlock.position.z = downz;
threeworld.scene.add(enemydownBlock);
setTimeout(removeEnemyExplosion, 500);
//-------------------------------------------
//Remove any weak blocks that were hit in the blast
for( var n=0; n<WEAKCUBES.length; n++ )
{
if( WEAKCUBES[n].position.x == leftx && WEAKCUBES[n].position.z == leftz)
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[(enemybombi-1)][enemybombj] = GRID_BLANK;
}
if( WEAKCUBES[n].position.x == rightx && WEAKCUBES[n].position.z == rightz)
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[(enemybombi+1)][enemybombj] = GRID_BLANK;
}
if( WEAKCUBES[n].position.x == upx && WEAKCUBES[n].position.z == upz)
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[enemybombi][(enemybombj-1)] = GRID_BLANK;
}
if( WEAKCUBES[n].position.x == downx && WEAKCUBES[n].position.z == downz )
{
threeworld.scene.remove(WEAKCUBES[n]);
GRID[enemybombi][(enemybombj+1)] = GRID_BLANK;
}
enemybombExploding = true; //Stops the enemy moving back into his own bombs blast
}
}
function removeAgentExplosion()
{
threeworld.scene.remove(agentmiddle);
threeworld.scene.remove(agentleftBlock);
threeworld.scene.remove(agentrightBlock);
threeworld.scene.remove(agentupBlock);
threeworld.scene.remove(agentdownBlock);
}
function removeEnemyExplosion()
{
threeworld.scene.remove(enemymiddle);
threeworld.scene.remove(enemyleftBlock);
threeworld.scene.remove(enemyrightBlock);
threeworld.scene.remove(enemyupBlock);
threeworld.scene.remove(enemydownBlock);
}
function agentBlownUp() //Did the Agent get blown up in the explosion
{
if( occupiedByPlayer(agentbombi,agentbombj) ||
occupiedByPlayer((agentbombi-1),agentbombj) ||
occupiedByPlayer((agentbombi+1),agentbombj) ||
occupiedByPlayer(agentbombi,(agentbombj-1)) ||
occupiedByPlayer(agentbombi,(agentbombj+1)))
return true;
agentbombi = 0; //Reset bomb position to outside map
agentbombj = 0;
return false;
}
function enemyBlownUp() //Did the Enemy get blown up in the explosion
{
if( occupiedByPlayer(enemybombi,enemybombj) ||
occupiedByPlayer((enemybombi-1),enemybombj) ||
occupiedByPlayer((enemybombi+1),enemybombj) ||
occupiedByPlayer(enemybombi,(enemybombj-1)) ||
occupiedByPlayer(enemybombi,(enemybombj+1)))
return true;
enemybombi = 14; //Reset bomb position to outside map
enemybombj = 14;
return false;
}
function occupiedByPlayer ( i, j ) // is this square occupied by a player
{
if ( ( ei == i ) && ( ej == j ) )
return true; // variable objects
if ( ( ai == i ) && ( aj == j ) )
return true;
return false;
}
function occupiedByWeakBox( i, j)
{
if( (GRID[i][j] == GRID_WEAK) )
return true;
return false;
}
function occupiedByAgentBomb( i, j)
{
if( (agentbombi==i) && (agentbombj==j) )
return true;
return false;
}
// --- AGENT -----------------------------------
function initLogicalAgent()
{
ai = 13;
aj = 13;
}
function buildagent ( object )
{
object.scale.multiplyScalar ( 50 ); // make 3d object n times bigger
object.traverse( paintAgent );
theagent = object;
//Starting Position of enemy one
theagent.position.x = translate ( 13 * squaresize );
theagent.position.y = ( -50 );
theagent.position.z = translate ( 13 * squaresize );
theagent.rotation.set ( 0, 3, 0 );
threeworld.scene.add( theagent );
}
function drawAgent() // given ai, aj, draw it
{
if ( theagent )
{
var x = translate ( ai * squaresize );
var z = translate ( aj * squaresize );
var y = -50;
theagent.position.x = x;
theagent.position.y = y;
theagent.position.z = z;
threeworld.follow.copy ( theagent.position ); // follow vector = agent position (for camera following agent)
threeworld.follow.y = ( squaresize * 1.5 ); // put camera higher up
}
}
function moveLogicalAgent( a ) //Agent is controlled by the user via keyboard
{
var i = ai;
var j = aj;
if ( a == ACTION_LEFT )
i--;
else if ( a == ACTION_RIGHT )
i++;
else if ( a == ACTION_UP )
j++;
else if ( a == ACTION_DOWN )
j--;
if ( !occupied(i,j) )
{
if ( true )
{
// if going to actually move, then turn body towards move
// rotate by some amount of radians from the normal position
// in degrees: +0, +90, +180, +270
if ( a == ACTION_LEFT )
rotateAgentTowards ( 3 * (Math.PI / 2) );
else if ( a == ACTION_RIGHT )
rotateAgentTowards ( 1 * (Math.PI / 2) );
else if ( a == ACTION_UP )
rotateAgentTowards ( 0 * (Math.PI / 2) );
else if ( a == ACTION_DOWN )
rotateAgentTowards ( 2 * (Math.PI / 2) );
}
ai = i;
aj = j;
}
}
function rotateAgentTowards ( newRotation )
{
if ( agentRotation == newRotation )
return;
var x = ( agentRotation + newRotation ) / 2;
theagent.rotation.set ( 0, x, 0 );
agentRotation = x;
}
function keyHandler(e)
{
// user control
// Note that this.takeAction(a) is constantly running at same time, redrawing the screen.
if (e.keyCode == 32)
agentDrawBomb();
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 );
}
function headerText()
{
var status = "[SPACEBAR] = Drop Bomb , [Arrow Keys] = Move Agent ";
$("#user_span1").html( status );
}
//--- public functions / interface / API ----------------------------------------------------------
this.endCondition; // If set to true, run will end.
this.newRun = function()
{
steps = 0;
this.endCondition = false;
initGrid();
initLogicalWalls();
initLogicalStrongBlocks();
initLogicalWeakBlocks();
initLogicalAgent();
initLogicalEnemy();
if ( true )
{
threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );
// LIGHT
var 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);
// MUSIC
var x = "<audio id=theaudio src=/uploads/mcadamm4/westworld.mp3 autoplay loop> </audio>" ;
$("#user_span2").html( x );
initSkybox();
initThreeWalls();
initThreeMaze();
loadTextures(); // will return sometime later, but can go ahead and render now
document.onkeydown = keyHandler;
}
};
this.getState = function()
{
var x = [ ai, aj, ei, ej ];
return ( x );
};
this.nextStep = function()
{
var a = 4;
steps++;
headerText();
if(steps%5==0)
setTimeout(moveLogicalEnemy,4000);
if ( true )
{
drawAgent();
drawEnemy();
if(agentbombExploding) //Is there a bomb exploding
{
agentbombExploding = false; //Bomb has exploded so reset
if(agentBlownUp()) // Has someone been blown up by the bomb
{
this.endCondition = true;
var x = "<audio id=theaudio src=/uploads/mcadamm4/gameover.mp3 autoplay loop> </audio>" ;
$("#user_span2").html( x );
}
}
if(enemybombExploding) //Is there a bomb exploding
{
enemybombExploding = false; //Bomb has exploded so reset
if(enemyBlownUp()) // Has someone been blown up by the bomb
{
this.endCondition = true;
var x = "<audio id=theaudio src=/uploads/mcadamm4/gameover.mp3 autoplay loop> </audio>" ;
$("#user_span2").html( x );
}
}
}
};
this.endRun = function()
{
var status = "GAME OVER!!";
$("#user_span1").html( status );
};
}
//---- end of World class -------------------------------------------------------