Code viewer for World: 3D Snake
var p1score = 0;        
var p2score = 0;

var max_targets = 1;    // max targets on the screen

var alltargets = new Array(0);  // array of all targets

const gameClock = new THREE.Clock();    // clock for the game

var Invis_grid = [      // invisible grid
    [-200, -100, 190], [-120, -100, 190], [-40, -100, 190], [40, -100, 190], [120, -100, 190], [200, -100, 190],
    [-200, -100, 110], [-120, -100, 110], [-40, -100, 110], [40, -100, 110], [120, -100, 110], [200, -100, 110],
    [-200, -100, 30], [-120, -100, 30], [-40, -100, 30], [40, -100, 30], [120, -100, 30], [200, -100, 30],
    [-200, -100, -50], [-120, -100, -50], [-40, -100, -50], [40, -100, -50], [120, -100, -50], [200, -100, -50],
    [-200, -100, -130], [-120, -100, -130], [-40, -100, -130], [40, -100, -130], [120, -100, -130], [200, -100, -130],
    [-200, -100, -210], [-120, -100, -210], [-40, -100, -210], [40, -100, -210], [120, -100, -210], [200, -100, -210]
    ];

// Creating floor for the game
var floorGeometry = new THREE.PlaneGeometry( 1000, 1000);       // floor geometry
floorGeometry.rotateX( - Math.PI / 2 );     // rotate the floor 90 degrees  
var floorMaterial = new THREE.MeshBasicMaterial({color: "#36b344"});     // floor material
var floor = new THREE.Mesh(floorGeometry, floorMaterial);   // floor mesh
floor.position.set(0,-20,0);    // set the position of the floor


// Create a splash screen for the start of the game
 AB.newSplash ( splashScreenStart() );  // splashScreenStart() is a function that returns a string with the HTML for the splash screen
 document.getElementById("splashbutton").id = "startsplash";

	AB.world.newRun = function()
	{        
        AB.socketStart();
        initScene();
        AB.runReady = false;
        
    };
	// This function is called when the game is started
	function initScene(){
	    
	    AB.headerWidth(100);    
	 	ABWorld.init3d ( 500, 2000, "#69b2d6");  
	 	
	 	var light = new THREE.AmbientLight("white", 0.8);   // soft white light
	 	ABWorld.scene.add(floor);   
        ABWorld.scene.add(light);
        

	}
	// This function is called every frame
	AB.world.nextStep = function()		 
	{

	    spawnSnake();
	    if(Math.trunc(gameClock.getElapsedTime()) == 99){  // 99 is the time in seconds
	        AB.runReady = false;
	        AB.newSplash ( splashScreenEnd() ); // splashScreenEnd() is a function that returns a string with the HTML for the splash screen
            document.getElementById("splashbutton").innerHTML = "Play Again";
            document.getElementById("splashbutton").onclick = reload;
	    }
	    
	    if (alltargets.length < max_targets){   //if there are less than 1 targets on the screen
    	    spawnApples();                      //spawn a new target
	    }
	    
	    if(AB.socket){                    //if the socket is open                           
	        if(AB.socket.connected){    //and if the socket is connected
	            AB.socketOut(p1score);      //send the score to the server
	            AB.msg("Hit the arrow keys to spawn snake!");
	            AB.msg("P1 Score = " + p1score + " P2 score = " + p2score + "\n Time remaining: " + Math.trunc(99 - gameClock.getElapsedTime()));
	        }
	    }
    };

	var x = 1;
    var y = 1;
	const sn_texture = new THREE.TextureLoader().load("uploads/przemekbiel02/greentx.jpg");
		var snakeArray = new Array(0);
	//
	function spawnSnake(){      // spawns and controls the snake  
	    var j = 0;
	 	var shape = new THREE.SphereGeometry(28, 20, 20);   // shape of the snake
        var cover = new THREE.MeshBasicMaterial({map: sn_texture}); // texture of the snake
        var snake = new THREE.Mesh(shape, cover);                       // snake mesh
        document.onkeydown = function(e){                        // event listener for key presses
            switch (e.keyCode){

            case 37:
            ABWorld.scene.add(snake);                    // add the snake to the scene
            snakeArray.push(snake);                     // add the snake to the snake array
            snake.position.set(x=x-4, -1, y);              // set the position of the snake
            consumeApple(snake);                    // check if the snake hit a target
            break;
            case 38:
            ABWorld.scene.add(snake);
            snakeArray.push(snake);
            snake.position.set(x, -1,y=y-4);
            consumeApple(snake);
            break;
            case 39:
            ABWorld.scene.add(snake);
            snakeArray.push(snake);
            snake.position.set(x=x+4, 0, y);
            consumeApple(snake);
            break;
            case 40:
            ABWorld.scene.add(snake);
            snakeArray.push(snake);
            snake.position.set(x, 0, y=y+4);
            consumeApple(snake);
            break;
            
        }
        for (var i = 0; i < snakeArray.length; i++){        // for every snake in the snake array
            if (snakeArray.length > 5){                     // if the snake array is longer than 5
                ABWorld.scene.remove(snakeArray[i-growth]);     // remove all snake meshes after the growth variable
                }
            }
        };
        return snake;
        }
	

	const ap_texture = new THREE.TextureLoader().load("uploads/przemekbiel02/apple.jpg");
	function spawnApples(){                                         // spawns the targets
	 	var shape = new THREE.SphereGeometry(22, 20, 20);           // shape of the target
        var cover = new THREE.MeshBasicMaterial({map: ap_texture}); // texture of the target
        var target = new THREE.Mesh(shape, cover);                  // target mesh        
	 	var randomIndex = AB.randomIntAtoB(0, Invis_grid.length);   // random index of the invisible grid
        var item = Invis_grid[randomIndex];                         // item in the invisible grid        
	 	target.position.set(item[0], 0, item[2]);                   // set the position of the target        
        
	 	ABWorld.scene.add(target);                                  // add the target to the scene        
	 	Invis_grid.splice(randomIndex, 1);                          // remove the position of the target from the invisible grid                              
	 	alltargets.push(target);                                    // add the target to the target array         
	}
	

    var growth = 30;                                                // Track growth of the snake
    function consumeApple(snake)                                       // checks if the snake hit a target
    {
        if(alltargets.length > 0){                                  // if there are targets on the screen
            for (var i = 0; i < alltargets.length; i++){            // for every target in the target array
                var target = alltargets[i];                         // target in the target array                        
                var snake_pos = snake.getWorldPosition();           // position of the snake
                var target_pos = target.getWorldPosition();         // position of the target        
                if (snake_pos.distanceTo(target_pos) < 30) {        // if the distance between the snake and the target is less than 30  
                    growth = growth + 12;                           // increase the growth variable
                    audioHandler("shoot");                          // play the shoot sound
                    ABWorld.scene.remove(target);                   // remove the target from the scene 
                    alltargets.splice(i, 1);
                    p1score = p1score + 1;                          // increase the score
                    spawnApples();                                  // spawn a new target
                    break;
                    }
            }
        }
        return;
    }

    
    function audioHandler(instance){
        var a;
        if (instance == "shoot"){   // if the instance is shoot
            a = new Audio("uploads/przemekbiel02/ChipscripsCrunchSoundEffectNoise.mp4");// load the shoot sound
	        a.play();   // play the shoot sound
        }
    }

	AB.world.endRun = function()
	{
	};
	
	function splashScreenStart()
    {
    	var s = "<p>Eat as many apples as you can!</p>";
    	
    	s = s + "<p>Move with arrow keys and go over the apples to eat them ;)</p>" ;
    	s = s + "<p>Press arrow key to spawn</p>" ;
    	
    	return ( s );
    	
    }
    
    function splashScreenEnd()
    {
    	var s = "<h2>Game Over!</h2>";
    	
    	if (p1score > p2score){
	    s = s + "<p>Victory Player 1 with a score of " + p1score  + " apples!</p>";
    	}
    	else if (p1score < p2score){
    	    s = s + "<p>Victory Player 2 with a score of " + p2score +  " apples!</p>";
    	}
    	else if (p1score == p2score){
    	    s = s + "<p>Draw!</p>" + p1score;
    	}
    	
    	return (s);
    }
    
    function gameFull(){    // if the game is full
        var s = "<p>Game session is currently full. Please try again later.</p>";
        return (s);
    }

	
	$("#startsplash").click(function() {    // when the start button is clicked
        AB.runReady = true;                 // set the run ready variable to true
        AB.removeSplash();                  // remove the splash screen
        const MUSICFILE = '/uploads/fatogua2/callmemaybe.mp3';
        MUSICFILE.volume = 0.1;
        AB.backgroundMusic ( MUSICFILE );
    });
    
    function reload(){
        location.reload();
    }
	
	AB.socketIn = function (s){             // 
	    p2score = s;
	};
    
    AB.socketUserlist = function ( array ) {        // when the userlist is received
        console.log(array.length);                  // log the length of the userlist   
        if (array.length > 2) {                     // if there are more than 2 users
            AB.runReady = false;                    // set the run ready variable to false
	        AB.newSplash ( gameFull() );            // show the game full splash screen
            document.getElementById("splashbutton").innerHTML = "Try Again"; 
            document.getElementById("splashbutton").onclick = reload;
            
            
        }
        AB.socketUserlist = function(){};
    };
    
    
    // fix timer disparity