Code viewer for World: Shooting Range (clone by Dave)

// Cloned by Dave on 8 Nov 2022 from World "Shooting Range" by Enhanced 
// Please leave this clone trail here.
 


// Cloned by Enhanced on 13 Jun 2018 from World "Enhancing Shooting Range (Space To Shoot)" by Mathias Bazin 
// Please leave this clone trail here.
 


// Cloned by Mathias Bazin on 5 Jun 2018 from World "Shooting Range (Space To Shoot)" by Adrian Rabbitte 
// Please leave this clone trail here.
 

//Correct This world




///Shooting Range (Space To Shoot)
/*
Adrian James Rabbitt   14500447

I created a game where the user controls the agent (gun), and its objective is to shoot the 2 animals (Swan,Duck) in the shooting zone. Using AI I designed the movements of duck and the swan so that there aim is to
move to a safe position, The animals will try hide behind a stone or go to the corners to safety. The user must not hit a stone or they lose.



 DESIGN

1) The world consists of a firing range and a shooting zone, a small wall is placed as a barrier between them, The agent and the animals are not able to pass this barrier.
   The firing range is a quater size of the the entire zone.
   The shooting zone is looked upon as a lake/pond repesented by a bluecolour, surrounded by timber walls.

2) Position of Stones:
   I placed the stones constant across the shooting zone to make the game more difficult to shoot the animals.
   

3) Logical Moves of Animals:
   I created the logic for the movements of the animals so that they are always moving away from the gun(agent), and always trying to hide behind a stone.
   The animals will attract towards the corners as it is the furthest point away from the agent. The animal will stay in the corner to hide, here the user (gun) should move 
   back to the corner of its shooting range to hide from the animal , so that the animal will move back out. When an animal is shot a message is displayed on the screen and the animal will 
   stop moving. In some cases the animals moves a number of spaces in one move, this is to create a vision that the animal can fly to certain spots.
   From studying A* algorithms I wanted to do the reverse to find the shortest route away from the agent.  
  
4) Logical Move of Agent.
   The movement of the agent is controled by the the directional pad on the keyboard. I did not use rotations on this as the gun is always shooting forward along the i axis.
   
 
5)MOVE WIDTH.
   I changed the camera view of the agent so it is only showing the tip of the gun. The gun will point first to the duck, when the duck is shot, it points the camera towards the swan.
   This leaves completing the game much easier.
   
6)Bullet.
   When creating the bullet, I used the same detail as if I was making another enemy(animal) starting at the coordinates of the agent and moving forward by decrementing its j value.
   This means that you can shoot a number of bullets during a set interval of time.
   
7)Senors.
   Using i and j corrdinates I was able to get the game to show if the gun shot a stone or an animal by matching its coordanites.

8)Music 
   When the gun is shot there is audio in the background when the bullet is created.This makes the game more realistic.




PROBLEMS FACED

1) Before i undertook implementing the project I spent a lot of time studying javascript , however by actually playing around with worlds I was able to see my actions visually and fix them
 helped me a lot, by doing this project my knoledge and condfidence with javascript improved rapidly. I have created a world which could do with a lot off improvement and which i would love 
 to do in my own spare time.

2) Shooting : when you press space multiple of times it creates a number of bullets that stay still. Here I created the game when you press space it creates a new intancee of bullet each time, this stops the previos bullets.
I hope to fix this in the future.

3)Rotations : I left the rotations to last which turned out to be a problem faced due movements of the animals. I was implementing the rotations so the animals would move in an arc shap to 
give the impression they are swimming.

4)Loading GTA files.

5)Creating objects.



TESTING.
1)If an animal is in a corner and doesnt want to come out, move the gun back to the edge of the shooting range(on the same i axis) to hide, The animal will then move out.
2)Shoot Maze to Lose.
3)Shoot the 2 animals to win.
4)Shoot an animal that is on front of a stone(You Lose)
5)Move the gun to the corner of the shooting range, the animals will move together to the opisite side.
6)MOVE WIDTH , If there is a level of diffuculty in shooting the animals by clicking MOVE WIDTH it will show the camera from the Gun.


OVERALL VIEW.
Overall I enjoyed implementing this project from its learning outcomes to its creation. At the start of the project i had a plan and stuck to it, However I could have did a few improvements 
such as the rotations and the logical moves. I had the logical moves working quite good, but then changed them around to suit different scenarios. The size of the world I could have made bigger
to add more animals to target and to set a set interval of time to shoot each animal. I hope to keep changing the world in future to create a proper game with a lot more competion in it.


CODE
Below is the code. I started off using Snow World where I then implemented my own version to Shooting Range.
I have commented out the code in short sentences. The code is a bit messy as i did not have time at the end to fix .
theagent = gun , theSheep = swan , theenemy = duck.

CREDITS.
http://computing.dcu.ie/~humphrys/ca318/.
http://tf3dm.com/3d-model.
www.google.ie

CHANGES
added smooth movement, music, can shoot more than 1 bullet, more feedback when targets get hit 
*/




threeworld.drawCameraControls = false;

AB.drawRunControls = false;



//---- global constants: -------------------------------------------------------

 
const	 	CLOCKTICK 	= 100;					// speed of run - move things every n milliseconds
const		MAXSTEPS 	= 1000;					// length of a run before final score
const  SCREENSHOT_STEP = 50;    
const  LIGHTCOLOR 	= 0xffffff;
const shortDistance = 30;


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

const NOBOXES =  8

const squaresize = 30;					// size of square in pixels
const MAXPOS = gridsize * squaresize;		// length of one side in pixels 
	
const SKYCOLOR 	= 0x009933;				// a number, not a string 
const BLANKCOLOR 	= 0x009933 ;
const grey = 0x808080;
const red = SKYCOLOR            // make objects this color until texture arrives (from asynchronous file read)




const show3d = true;						// Switch between 3d and 2d view (both using Three.js) 
 
const startRadiusConst	 	= MAXPOS * 0.8 ;		// distance from centre to start the camera at
const skyboxConst			= MAXPOS * 3 ;		// where to put skybox 
const maxRadiusConst 		= MAXPOS * 10  ;		// maximum distance from camera we will render things  
const BACKWALLPOS = -299;





//--- 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;

// in initial view, (smaller-larger) on i axis is aligned with (left-right)
// in initial view, (smaller-larger) on j axis is aligned with (away from you - towards you)



// contents of a grid square

const GRID_BLANK 	= 0;
const GRID_WALL 	= 1;
const GRID_MAZE 	= 2;
const GRID_BOTTOM   = 3;
const GRID_BOTTOM2  = 4;
const GRID_STONE = 5
 
 




 
// --- 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; }
}







//---- start of World class -------------------------------------------------------
 
function World() { 


// most of World can be private 
// regular "var" syntax means private variables:


var BOXHEIGHT;		// 3d or 2d box height 


var GRID 	= new Array(gridsize);	
var GRID2   = new Array(gridsize);
var GRID3   = 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 );
var WALLS2 = new Array ( 4 * gridsize );// need to keep handles to wall and maze objects so can find them later to paint them 
var MAZE 	= new Array ( NOBOXES );
var STONE 	= new Array ( NOBOXES );
var BOTTOM = new Array (gridsize ) // created an array for the bottom of the shooting zone.
var BOTTOM2 = new Array (gridsize )// created an array for the bottom of the firing range.
var theagent, theenemy,theSheep;// inializing agent enemy sheep
var agentVelocity = new THREE.Vector3(0,0,0);  
var animals = [];
var bullets = [];

var meatShape             = new THREE.BoxGeometry ( squaresize, squaresize, squaresize);
var meatTexture = new THREE.ImageUtils.loadTexture ( "/uploads/mathias/meat.jpg" );
meatTexture.minFilter = THREE.LinearFilter;

const DEATHQUACK = "/uploads/mathias/deathQuack.mp3"
var quack = new Audio(DEATHQUACK);


const MUSIC = "/uploads/mathias/kalimba.mp3"

var music = new Audio(MUSIC);

// enemy and agent position on squares
var ei, ej, ai, aj, si, sj,bi,bj; // coordinates for agent enemy sheep and bullet.

var badsteps;
var goodsteps;
var  step;

var self = this;						// needed for private fn to call public fn - see below  

 


// regular "function" syntax means private functions:


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 initGrid2()
{
 for (var i = 0; i < gridsize ; i++) 
 {
  GRID2[i] = new Array(gridsize);		// each element is an array for the bottom part of the grid.

  for (var j = 0; j < gridsize ; j++) 
  {
   GRID2[i][j] = GRID_BLANK ;
  }
 }
}



function occupied ( i, j )		// is this square occupied
{
 if ( ( ei == i ) && ( ej == j ) ) return true;		// variable objects 
 if ( ( ai == i ) && ( aj == j ) ) return true;
 if ( ( si == i ) && ( sj == j ) ) return true;       // booleans to check id sppace on the map is free.

 if ( GRID[i][j] == GRID_WALL) return true;	
 if ( GRID[i][j] == GRID_MAZE) return true;// fixed objects	 // added booleans for Maze and Stone.
if ( GRID[i][j] == GRID_STONE) return true;		 
	 
 return false;
}

 
// logically, coordinates are: y=0, x and z all positive (no negative)    
// logically my dimensions are all positive 0 to MAXPOS
// to centre everything on origin, subtract (MAXPOS/2) from all dimensions 

function translate ( x ) 
{
 return ( x - ( MAXPOS/2 ) );
}





//--- skybox ----------------------------------------------------------------------------------------------


function initSkybox() 
{

// x,y,z positive and negative faces have to be in certain order in the array 
 
// mountain skybox, credit:
// http://stemkoski.github.io/Three.js/Skybox.html

 // var materialArray = [
 	//( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/adrian/trees.jpg" ), side: THREE.BackSide } ) ),
 	//( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture("/uploads/adrian/trees.jpg" ), side: THREE.BackSide } ) ),
 	//( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/adrian/sky.jpeg" ), side: THREE.BackSide } ) ),
 	//( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/adrian/grass.jpg" ), side: THREE.BackSide } ) ),
 	//( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/adrian/trees.jpg" ), side: THREE.BackSide } ) ),
 	//( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/adrian/trees.jpg" ), side: THREE.BackSide } ) ),
 //	];
  
   var materialArray = [
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/seanhutchinson/skyrender0001.bmp" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/seanhutchinson/skyrender0004.bmp" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/seanhutchinson/skyrender0003.bmp" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/seanhutchinson/skyrender0006.bmp" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/seanhutchinson/skyrender0005.bmp" ), side: THREE.BackSide } ) ),
 	( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture("/uploads/seanhutchinson/skyrender0002.bmp"), 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
}


// This does the file read the old way using loadTexture.
// (todo) Change to asynchronous TextureLoader. A bit complex:
// Make blank skybox. Start 6 asynch file loads to call 6 return functions.
// Each return function checks if all 6 loaded yet. Once all 6 loaded, paint the skybox.		 


  

function loadtextures2()
{
    var loader8 = new THREE.TextureLoader();
 loader8.load ( '/uploads/adrian/silver.png',	function ( thetexture ) {		// created a second load function seperate for the bullet itself.	 
		thetexture.minFilter = THREE.LinearFilter;
		bullet.material =  new THREE.MeshBasicMaterial( { map: thetexture } );
	} ); 
}

function loadTextures()
{

var manager = new THREE.LoadingManager();		     // loading 3d objects onto map.
	var loader = new THREE.OBJLoader( manager );    
			
 loader.load( "/uploads/adrian/duck.obj", buildenemy ); // duck Object
 loader.load( "/uploads/adrian/swan.obj", buildsheep ); // swan Object
 loader.load( "/uploads/adrian/gunn.obj", buildagent ); // gun object



 var loader1 = new THREE.TextureLoader();
 loader1.load ( '/uploads/adrian/woodp.jpg',		function ( thetexture ) {			 
		thetexture.minFilter = THREE.LinearFilter;                                 //loading colour of walls.
		paintWalls ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
	} ); 
	
	
	
	var loader6 = new THREE.TextureLoader();
 loader6.load ( '/uploads/adrian/waves2.jpg',		function ( thetexture ) {			 
		thetexture.minFilter = THREE.LinearFilter;
		paintBottom2 ( new THREE.MeshBasicMaterial( { map: thetexture } ) );       //loading colour of water
	} ); 
	


 var loader2 = new THREE.TextureLoader();
 loader2.load ( '/uploads/adrian/sand3.jpg',		function ( thetexture ) {			 
		thetexture.minFilter = THREE.LinearFilter;                                 //loading colour of stone.
		paintMaze ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
 	} ); 

 //var loader3 = new THREE.TextureLoader();
 //loader3.load ( '/uploads/adrian/cat.jpg',	function ( thetexture ) {			 
//		thetexture.minFilter = THREE.LinearFilter;
	//	theagent.material =  new THREE.MeshBasicMaterial( { map: thetexture } );
//	} ); 

 var loader4 = new THREE.TextureLoader();
 loader4.load ( '/uploads/adrian/mouce.png',	function ( thetexture ) {			 
		thetexture.minFilter = THREE.LinearFilter;
		theenemy.material =  new THREE.MeshBasicMaterial( { map: thetexture } );
	} ); 
	

	
	
	
 var loader5 = new THREE.TextureLoader();
 loader5.load ( '/uploads/adrian/bm.png',	function ( thetexture ) {			 
		thetexture.minFilter = THREE.LinearFilter;
		theSheep.material =  new THREE.MeshBasicMaterial( { map: thetexture } );
	} ); 


}




 function buildenemy ( object ) 
{ 
	object.scale.multiplyScalar (150,150,150);    	  // make 3d object n times bigger 
	object.traverse( paintEnemy );
	theenemy = object;
	threeworld.scene.add( theenemy );                // adding enemy to the world
}



	


function playBang()
{

	// put music element in one of the spans
  	var x = new Audio("/uploads/adrian/gun.mp3");
  	x.volume = 0.5;
  	x.play();
}