Code viewer for World: Enhanced Space Pong

// Cloned by Enhanced on 18 Jun 2018 from World "Revamped Space Pong" by SinfulSalad 
// Please leave this clone trail here.
 

// Cloned by SinfulSalad on 12 Jun 2018 from World "Space Pong" by Igor Strelkov 
// Please leave this clone trail here.


//-------------------------- TWEAKER'S BOX: ------------------------------------

AB.clockTick  = 33;       // speed of run - move things every n milliseconds

const gridsize = 101;					// number of squares along side of world	   

const squaresize = 100;					// size of square in pixels
const playersize = 1500;					// size of player in pixels
const SPEED_MULTIPLIER = 1.3;           //speed of the ball
const TIME_BEFORE_END = 120;            //number of seconds before the time mode ends
const SCORE_NEEDED = 5;                 //number of points needed to win the score mode

//difficulty multiplicators for each difficulty :
//this multiplicator affect the speed of the enemy's paddle
//as well as how random the direction of it's shots is
const EASY_MODE = 1.1;
const MEDIUM_MODE = 1.5;
const HARD_MODE = 1.9;


//change the files in this array to change the background displayed by the program
const skyboxTexture = ["/uploads/starter/sky_pos_z.jpg",
                        "/uploads/starter/sky_neg_z.jpg",
                        "/uploads/starter/sky_pos_y.jpg",
                        "/uploads/starter/sky_neg_y.jpg",
                        "/uploads/starter/sky_pos_x.jpg",
                        "/uploads/starter/sky_neg_x.jpg"];

const SKYCOLOR 	= 0xffffcc;				// a number, not a string 
const BLANKCOLOR 	= SKYCOLOR ;			// make objects this color until texture arrives (from asynchronous file read)

const MAXPOS = gridsize * squaresize;
const startRadiusConst	 	= MAXPOS * 1 ;		// distance from centre to start the camera at
const skyboxConst			= MAXPOS * 3;
const maxRadiusConst 		= MAXPOS * 100 ;		// maximum distance from camera we will render things 

AB.maxSteps  = 20000;  
 

//-------------------------END OF TWEAKER'S BOX---------------------------------




// --- 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 World() {
	
	this.endCondition = false;				  

    var edges = [];
    
    var fileArray = [];
    var textureArray = [];
    
    var player;
    var enemy;
    var ball;
    
    var difficulty = "EASY";
    var gameMode = "SCORE";
    var ready = "set";
    var timer = AB.clockTick*TIME_BEFORE_END;
    
    //is used to display the final score, or the start button, or the timer
    var str6 = "<p align=\"center\"><button id='startButton', style=\"height:30px;width:100px;background-color:#FF0000\"><b>START</b></button></p>";
    
   
    
    function keyDownHandler(e)		
    // user control 
    // Note that this.takeAction(a) is constantly running at same time, redrawing the screen.
    {
        if (e.keyCode == 37)    player.movement = -1;
        if (e.keyCode == 39)    player.movement = 1;
    }
    
    function keyUpHandler(e)		
    // user control 
    // Note that this.takeAction(a) is constantly running at same time, redrawing the screen.
    {
        if (e.keyCode == 37 && player.movement == -1) player.movement = 0;
        else if (e.keyCode == 39 && player.movement == 1) player.movement = 0;
    }
    
    
    
    
    
    function initTextures()
    {
        
        fileArray.push('/uploads/strelki2/black.jpg');
        fileArray.push(skyboxTexture[0]);
        fileArray.push(skyboxTexture[1]);
        fileArray.push(skyboxTexture[2]);
        fileArray.push(skyboxTexture[3]);
        fileArray.push(skyboxTexture[4]);
        fileArray.push(skyboxTexture[5]);
        fileArray.push("/uploads/strelki2/blue.jpg");
        fileArray.push("/uploads/strelki2/pink.jpg");
        fileArray.push("/uploads/strelki2/green.jpg");
        
        textureArray = [fileArray.length];
        for (let i = 0; i < fileArray.length; i++)
        {
            textureArray[i] = new THREE.ImageUtils.loadTexture( fileArray[i] );
        }
        
    	for ( let i = 0; i < textureArray.length; i++ )    // for all textures 
    	{ 
         textureArray[i].minFilter = THREE.LinearFilter;
    	}
        
    }
    
    
    function initEdges()
    {
      for (var i = -gridsize*squaresize/2 ; i <= gridsize*squaresize/2; i += squaresize )
      {
        buildCube(i,-gridsize*squaresize/2);
        buildCube(i, gridsize*squaresize/2);
        buildCube(-gridsize*squaresize/2, i);
        buildCube(gridsize*squaresize/2, i);
      }
    }


    function buildCube(x, z)
    {
        var shape    = new THREE.BoxGeometry( squaresize, squaresize, squaresize );       
        var cube  = new THREE.Mesh( shape );
        cube.position.x = x;
        cube.position.z = z;
        threeworld.scene.add(cube);
        cube.material = new THREE.MeshBasicMaterial({ map: textureArray[0] });
        edges.push(cube);
    }
    
    
    
    function initSkybox() 
    {
        var materialArray = [
     	( new THREE.MeshBasicMaterial ( { map: textureArray[1], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[2], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[3], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[4], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[5], side: THREE.BackSide } ) ),
     	( new THREE.MeshBasicMaterial ( { map: textureArray[6], 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 initBall()
	{
	    var sphereMaterial = new THREE.MeshLambertMaterial({color: 0xD43001});

        ball = new THREE.Mesh(new THREE.SphereGeometry(100,50,50), sphereMaterial);
        
	    ball.material =  new THREE.MeshBasicMaterial( { map: textureArray[7] } );  
	    
	    ball.position.x = 0;
        ball.position.y = 0;
        ball.position.z = 0;
        
        //angle (radian), zero meaning it moves towards the players side
        ball.direction = Math.PI;
        
        //is increased each time there is contact with the ball
        ball.velocity = SPEED_MULTIPLIER;
        
        threeworld.scene.add(ball);
	}
	
	
	
		function resetBall()
	{
	    ball.position.x = 0;
	    ball.position.z = 0;
	    ball.direction = Math.PI;
	    ball.velocity = SPEED_MULTIPLIER;
	}
	
	
	
	
	function initPaddles()
	{
	    var shape    = new THREE.BoxGeometry( playersize, squaresize, squaresize );			 
        player = new THREE.Mesh( shape );
        shape    = new THREE.BoxGeometry( playersize, squaresize, squaresize );			 
        enemy = new THREE.Mesh( shape );
        
        player.material =  new THREE.MeshBasicMaterial( { map: textureArray[8] } );
        enemy.material =  new THREE.MeshBasicMaterial( { map: textureArray[9] } );
        
        player.position.x = 0;
        player.position.y = 0;
        player.position.z = gridsize*squaresize/2-squaresize;
        player.movement = 0;
        player.score = 0;
        
        enemy.position.x = 0;
        enemy.position.y = 0;
        enemy.position.z = -gridsize*squaresize/2+squaresize;
        enemy.movement = 0;
        enemy.score = 0;
        enemy.speed = 1;
        
        threeworld.scene.add(player);
        threeworld.scene.add(enemy);
        
	}
	
	
	
	function enemyMind()
	{
	    if (enemy.position.x > ball.position.x+playersize/10) enemy.movement = -1;
	    else if (enemy.position.x < ball.position.x-playersize/10) enemy.movement = 1;
	    else enemy.movement = 0;
	}
	
	
	function processOpponentsMovement()
	{
	    player.position.x += player.movement*squaresize;
	    if (player.position.x > gridsize*squaresize/2-playersize/2) player.position.x = gridsize*squaresize/2-playersize/2;
	    else if (player.position.x < -gridsize*squaresize/2+playersize/2) player.position.x = -gridsize*squaresize/2+playersize/2;
	    
	    enemy.position.x += enemy.speed*enemy.movement*squaresize;
	    if (enemy.position.x > gridsize*squaresize/2-playersize/2) enemy.position.x = gridsize*squaresize/2-playersize/2;
	    else if (enemy.position.x < -gridsize*squaresize/2+playersize/2) enemy.position.x = -gridsize*squaresize/2+playersize/2;
	}
	
	
	
	function processBallMovement()
	{
	    newX = ball.position.x + squaresize*ball.velocity*Math.sin(ball.direction);
	    newZ = ball.position.z + squaresize*ball.velocity*Math.cos(ball.direction);
	    
	    
	    //collision bottom side
	    if (newZ > gridsize*squaresize/2-squaresize)
	    {
	        ball.velocity += 0.1;
	        ball.direction = Math.PI-ball.direction;
	        processLoss(player);
	    }
	    //collision top side
	    else if (newZ < -gridsize*squaresize/2+squaresize)
	    {
	        ball.velocity += 0.1;
	        ball.direction = -Math.PI-ball.direction;
	        processLoss(enemy);
	    }
	    //collision left and right
	    else if (newX > gridsize*squaresize/2-squaresize || newX < -gridsize*squaresize/2+squaresize)
	    {
	        ball.velocity += 0.1;
	        ball.direction = -ball.direction;
	    }
	    
	    
	    
	    
	    ball.position.x += squaresize*ball.velocity*Math.sin(ball.direction);
	    ball.position.z += squaresize*ball.velocity*Math.cos(ball.direction);
	    
	}
	

	
	function processLoss(opponent)
	{
	    if (opponent.position.x > ball.position.x+playersize/2 || opponent.position.x < ball.position.x-playersize/2)
	    {
	        opponent.score += -1;
	        resetBall();
	        
	    }
	    
	    else
	    {
	        
	        //let's add a little random to make it less predictable
	        //only happens when the enemy hits the ball
	        if (opponent.speed !== undefined) ball.direction += (opponent.speed/1.5+0.5)*randomfloatAtoB (-Math.PI/20, Math.PI/20);
	        
	        else if (opponent.position.x > ball.position.x+playersize/4)
	        {
	            ball.direction += Math.PI/8;
	        }
	        
	        else if (opponent.position.x < ball.position.x-playersize/4)
	        {
	            ball.direction -= Math.PI/8;
	        }

	    }
	}
	
	function updateScore()
	{
	    var playerScore = -enemy.score;
	    var enemyScore = -player.score;
	    var str = "<p align=\"center\"><font size=\"+2\"><b>PLAYER    "+playerScore+" - "+enemyScore+"    ENEMY</b></font></p>";
	    $("#user_span5").html( str );
	}
	
	
	function initOptions()
	{
	    $("#user_span1").html( "<p align=\"center\">Difficulty settings : <b>EASY</b></p>" );
	    var s = "<p align=\"center\"><button id='easyButton'>Easy</button> <button id='mediumButton'>Medium</button> <button id='hardButton'>Hard</button></p>";
     	$("#user_span2").html( s );
     	$("#user_span3").html( "<p align=\"center\">Mode settings : <b>SCORE</b></p>" );
     	s = "<p align=\"center\"><button id='scoreButton'>Score</button> <button id='timeButton'>Time</button></p>";
     	$("#user_span4").html( s );
     	$("#user_span6").html( str6 );
     	$("#user_span7").html( "<p align=\"center\"><font color=\"#C9C9C9\"><b>"+timer/AB.clockTick+" seconds remaining</b></font><p></b></p>" );
     	

        document.getElementById("easyButton").addEventListener("click", setToEasy);
        document.getElementById("mediumButton").addEventListener("click", setToMedium);
        document.getElementById("hardButton").addEventListener("click", setToHard);
        document.getElementById("timeButton").addEventListener("click", setToTime);
        document.getElementById("scoreButton").addEventListener("click", setToScore);
        document.getElementById("startButton").addEventListener("click", startGame);
        
	}
	
	function updateHUD()
	{
	    $("#user_span1").html( "<p align=\"center\">Difficulty settings : <b>"+difficulty+"</b></p>" );
	    $("#user_span3").html( "<p align=\"center\">Mode settings : <b>"+gameMode+"</b></p>" );
	    updateScore();
	    if (gameMode === "TIME")
	    {
	        $("#user_span7").html( "<p align=\"center\"><b>"+Math.floor(timer/AB.clockTick)+" seconds remaining</b><p></b></p>" );
	    }
	    else
	    {
	        $("#user_span7").html("<p align=\"center\"><font color=\"#C9C9C9\"><b>"+Math.floor(timer/AB.clockTick)+" seconds remaining</b></font><p></b></p>");
	    }
	}


    function setToEasy()
    {
        enemy.speed = EASY_MODE;
        difficulty = "EASY";
    }
    
    function setToMedium()
    {
        enemy.speed = MEDIUM_MODE;
        difficulty = "MEDIUM";
    }
    
    function setToHard()
    {
        enemy.speed = HARD_MODE;
        difficulty = "HARD";
    }
    
    function setToTime()
    {
        gameMode = "TIME";
        //TODO
    }
    
    function setToScore()
    {
        gameMode = "SCORE"
        //TODO
    }
    
    function startGame()
    {
        console.log("start pressed");
        ready = "start";
    }
    
    function endGame()
    {
        if (gameMode === "SCORE")
        {
            if (player.score == -SCORE_NEEDED || enemy.score == -SCORE_NEEDED)
            {
                ready = "end";
                updateHUD();
                if (player.score == -SCORE_NEEDED) str6 = "<p align=\"center\"><b>YOU LOSE!</b><p>";
                else str6 = "<p align=\"center\"><b>YOU WIN!</b><p>";
                
                $("#user_span6").html( str6 );
                
            }
        }
        
        else
        {
            if (timer === 0)
            {
                ready = "end";
                updateHUD();
                if (player.score < enemy.score) str6 = "<p align=\"center\"><b>YOU LOSE!</b><p>";
                else if (player.score > enemy.score) str6 = "<p align=\"center\"><b>YOU WIN!</b><p>";
                else str6 = "<p align=\"center\"><b>IT'S A DRAW!</b><p>";
                
                $("#user_span6").html( str6 );
            }
        }
    }
    
   
	
	this.newRun = function()
	{
	    
	    document.onkeydown = keyDownHandler;
	    document.onkeyup = keyUpHandler;
	    
	   
	    
	    threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  );
	    initTextures();
	    initSkybox();
	    initEdges();
	    initPaddles();
	    initBall();
	    initOptions();
	    
	    
	};


	this.nextStep = function()		 
	{
	    if (ready !== "end") updateHUD();
	    
	    if (ready === "start") 
	    {
	        processBallMovement();
            enemyMind();
            processOpponentsMovement();
            endGame();
            timer--;
	    }
        
	};


	this.endRun = function()
	{
	    
	};

}