const CLOCKTICK =100;// speed of run - move things every n millisecondsconst MAXSTEPS =1000;// length of a run before final scoreconst SCREENSHOT_STEP =50;//---- global constants: -------------------------------------------------------const gridsize =30;// number of squares along side of world const NOBOXES =Math.trunc ((gridsize * gridsize)/10);const squaresize =100;// size of square in pixelsconst MAXPOS = gridsize * squaresize;// length of one side in pixels const SKYCOLOR =0xffffcc;// a number, not a string const BLANKCOLOR = SKYCOLOR ;// make objects this color until texture arrives (from asynchronous file read)const startRadiusConst = MAXPOS *0.8;// distance from centre to start the camera atconst skyboxConst = MAXPOS *3;const maxRadiusConst = MAXPOS *100;// maximum distance from camera we will render things const show3d =false;//--- 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 ACTION_LEFT2 =0;const ACTION_RIGHT2 =1;const ACTION_UP2 =2;const ACTION_DOWN2 =3;// --- 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){returnfalse;}else{returntrue;}}//---- start of World class -------------------------------------------------------functionWorld(){var playerOneScore =0;var playerTwoScore =0;var bounces =0;// most of World can be private // regular "var" syntax means private variables:var GRID =newArray(gridsize);// can query GRID about whether squares are occupied, will in fact be initialised as a 2D array var WALLS =newArray(4* gridsize );// need to keep handle to each wall block object so can find it later to paint it var myPaddle, enemyPaddle, ball;// enemy and agent position on squaresvar si, sj, ai, aj , bi, bj;var direct =0;var goodsteps;var self =this;var audio =newAudio('/uploads/strelki2/bounce1.mp3');var error =newAudio('/uploads/strelki2/error.mp3');// regular "function" syntax means private functions:function initGrid(){for(var i =0; i < gridsize ; i++){
GRID[i]=newArray(gridsize);// each element is an array for(var j =0; j < gridsize ; j++){
GRID[i][j]=false;}}}function occupied ( i, j )// is this square occupied{if(( ai == i )&&( aj == j ))returntrue;if(( si == i )&&( sj == j ))returntrue;if( GRID[i+2][j]===true)returntrue;if( GRID[i-2][j]===true)returntrue;// fixed objectreturnfalse;}function translate ( x ){return( x -( MAXPOS/2));}function initSkybox(){var materialArray =[(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_pos_z.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_neg_z.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_pos_y.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_neg_y.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_pos_x.jpg"), side: THREE.BackSide})),(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_neg_x.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 );// We are inside a giant cube}function loadTextures(){var loader1 =new THREE.TextureLoader();
loader1.load ('/uploads/strelki2/black.jpg',function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
paintWalls (new THREE.MeshBasicMaterial({ map: thetexture }));});var loader2 =new THREE.TextureLoader();
loader2.load ('/uploads/strelki2/pink.jpg',function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
myPaddle.material =new THREE.MeshBasicMaterial({ map: thetexture });});var loader3 =new THREE.TextureLoader();
loader3.load ('/uploads/strelki2/green.jpg',function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
enemyPaddle.material =new THREE.MeshBasicMaterial({ map: thetexture });});var loader4 =new THREE.TextureLoader();
loader4.load ('/uploads/strelki2/blue.jpg',function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
ball.material =new THREE.MeshBasicMaterial({ map: thetexture });});}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]=true;// set up data structure, whether using Three.js or not}}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]==true){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 paintWalls ( material )// paint blank boxes {for(var i =0; i < WALLS.length; i++){if( WALLS[i]) WALLS[i].material = material;}}// --- ball functions -----------------------------------function drawBall()// given ei, ej, draw it {var x = translate ( bi * squaresize );var z = translate ( bj * squaresize );var y =0;var dir =0;var velocity
ball.position.x = x;
ball.position.y = y;
ball.position.z = z;
ball.direction = dir
threeworld.scene.add(ball);}function occupied ( i, j )// is this square occupied{if(( ai == i )&&( aj == j ))returntrue;if(( si == i )&&( sj == j ))returntrue;if( GRID[i+2][j]===true)returntrue;if( GRID[i-2][j]===true)returntrue;// fixed objectreturnfalse;}var ballDeltaX =-1;var ballDeltaY =3;var diameter =3;function processBallMovement(){// --- the coordinates of the ball after it moves------var nextBallLeft = bi + ballDeltaX;var nextBallRight = bi + diameter + ballDeltaX;var nextBallTop = bj + ballDeltaY;var nextBallBottom = bj + diameter + ballDeltaY;// --- what happens when the ball bounces of the top or bottom side-------------if(nextBallTop <1|| nextBallBottom > gridsize){if(audio.duration >0&&!audio.paused){// takes care of the sound when two bounces happen in quick succession
audio.stop();
audio.play();}
audio.play();
ballDeltaY *=-1;// changes the direction of the ball
bounces++;}// --- what happens when the ball bounces of the left side-------------if(nextBallLeft <1){if(audio.duration >0&&!audio.paused){
audio.stop();
audio.play();}
audio.play();
ballDeltaX *=-1;// changes the direction of the ball
bounces++;}// --- what happens when the ball bounces of the right side-------------if(nextBallRight > gridsize){if(audio.duration >0&&!audio.paused){
audio.stop();
audio.play();}
audio.play();
ballDeltaX *=-1;// changes the direction of the ball
bounces++}// --- check if the ball hits players pad (controlled by user)if(bj==27){if(((bi != ai)&&(bi !=(ai+1))&&(bi !=(ai+2))&&(bi !=(ai-1))&&(bi !=(ai-2)))){
error.play();
playerTwoScore++// adds to platers score}}// updates the location of the ball
bi+=ballDeltaX;
bj+=ballDeltaY;}function drawEnemyPaddle()// given ei, ej, draw it {var x = translate ( si * squaresize );var z = translate ( sj * squaresize );var y =0;
enemyPaddle.position.x = x;
enemyPaddle.position.y = y;
enemyPaddle.position.z = z;
threeworld.scene.add(enemyPaddle);}function initLogicalEnemy(){
si =7;// this square will be free
sj =1;// (bug) use Math.trunc or else you get a bad square number if gridsize is odd}function initLogicalBall(){
bi = gridsize/2;// this square will be free
bj = gridsize/2;// (bug) use Math.trunc or else you get a bad square number if gridsize is odd}function initThreeBall(){var sphereMaterial =new THREE.MeshLambertMaterial({color:0xD43001});// Create a ball with sphere geometry
ball =new THREE.Mesh(new THREE.SphereGeometry(100,50,50), sphereMaterial);
drawBall();}function initThreeEnemy(){var shape =new THREE.BoxGeometry(500, squaresize, squaresize );
enemyPaddle =new THREE.Mesh( shape );
enemyPaddle.material.color.setHex( BLANKCOLOR );
drawEnemyPaddle();}function moveLogicalEnemy(){// --- follows the location of the ball on the X axis var i;if( si < bi ) i = randomintAtoB(si, si+2.5);if( si == bi ) i = si;if( si > bi ) i = randomintAtoB(si-2.5, si);// --- check if the ball hits the oponents padif(bj==3){if(((bi != si)&&(bi !=(si+1))&&(bi !=(si+2))&&(bi !=(si-1))&&(bi !=(si-2)))){
error.play();
playerOneScore++// adds to computers score}}if(! occupied(i, sj+2)){
si = i;}}function drawMyPaddle()// given ai, aj, draw it {var x = translate ( ai * squaresize );var z = translate ( aj * squaresize );var y =0;
myPaddle.position.x = x;
myPaddle.position.y = y;
myPaddle.position.z = z;
threeworld.scene.add(myPaddle);}function initLogicalAgent(){// start at same place every time:
ai = gridsize/2-5;
aj =28;}function initThreeAgent(){var shape =new THREE.BoxGeometry(500, squaresize, squaresize );
myPaddle =new THREE.Mesh( shape );
myPaddle.material.color.setHex( BLANKCOLOR );
drawMyPaddle();}function moveLogicalAgent( a )// this is called by the infrastructure that gets action a from the Mind {var i = ai;var j = aj;if( a == ACTION_LEFT ) i--;elseif( a == ACTION_RIGHT ) i++;if(! occupied(i,j)){
ai = i;
aj = j;}}function keyHandler(e)// user control // Note that this.takeAction(a) is constantly running at same time, redrawing the screen.{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 );}// --- score: -----------------------------------var bounces;function updateStatus(){var score = self.getScore();var status ="You: "+ playerOneScore +" Computer: "+ playerTwoScore+" --------------------> Player with highest score wins";
$("#user_span1").html( status );}//--- public functions / interface / API ----------------------------------------------------------// must have this public variable:this.endCondition;// If set to true, run will end. this.newRun =function(){// (subtle bug) must reset variables like these inside newRun (in case do multiple runs)this.endCondition =false;
step =0;// define logical data structure for the World, even if no graphical representation:
initGrid();
initLogicalWalls();
initLogicalAgent();
initLogicalEnemy();
initLogicalBall();// if Three.js graphical representation:if(true){
threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );// Set up blank objects first:
initSkybox();
initThreeWalls();
initThreeAgent();
initThreeEnemy();
initThreeBall();// Then paint them with textures - asynchronous load of textures from files. // The texture file loads return at some unknown future time in some unknown order.// Because of the unknown order, it is probably best to make objects first and later paint them, rather than have the objects made when the file reads return.// It is safe to paint objects in random order, but might not be safe to create objects in random order.
loadTextures();// will return sometime later, but can go ahead and render now
document.onkeydown = keyHandler;}};this.getState =function(){var x =[ ai, aj, si, sj, bi, bj ];return( x );};var win =newAudio('/uploads/jordanm/win.mp3');var lose =newAudio('/uploads/jordanm/lose.mp3');this.nextStep =function(){var a =4;
moveLogicalEnemy();
processBallMovement();if(true){
drawMyPaddle();
drawEnemyPaddle();
drawBall();
updateStatus();// ends the game when either computer or user reaches 10 points if(playerOneScore ===5){
win.play();this.endCondition =true;}if(playerTwoScore ===5){
lose.play();this.endCondition =true;}}};this.endRun =function(){if(true){if(playerTwoScore>playerOneScore){
$("#user_span6").html(" <font color=red> <B> Computer has Won </B> </font>");}elseif((playerTwoScore<playerOneScore)){
$("#user_span6").html(" <font color=red> <B> Congratulations. You have Won </B> </font>");}else{
$("#user_span6").html(" <font color=red> <B> Its a draw </B> </font>");}}};this.getScore =function(){return goodsteps;};}