Browse Source

implemented game states
bug fix - cursor didnt change when it was over navigation icons (game circleOne)
documented code
some code refactoring
changes in language files
used game.math.isOverIcon in most cases to encapsulate code that checks is mouse is over an icon

laira 3 years ago
parent
commit
f3f7d560fa

BIN
assets/fonts/glyphicons-halflings-regular.eot


File diff suppressed because it is too large
+ 0 - 288
assets/fonts/glyphicons-halflings-regular.svg


BIN
assets/fonts/glyphicons-halflings-regular.ttf


BIN
assets/fonts/glyphicons-halflings-regular.woff


BIN
assets/fonts/glyphicons-halflings-regular.woff2


+ 26 - 26
assets/lang/en_US

@@ -1,26 +1,26 @@
-loading=LOADING
-title=Fractions
-menu_title=SELECT GAME
-difficulty=Difficulty
-level=Level
-game_menu_title=SELECT OPERATION AND DIFFICULTY
-good_job=Good Job
-retry=Try again
-menu_world=LANGUAGE SELECTION
-menu_list=MAIN MENU
-menu_back=GO BACK
-menu_help=SEE SOLUTION
-circle_name=Circles
-square_name=Quadrangles
-label_name=labels
-mode_name=MODE
-show=Show
-insert_name=ENTER YOUR NAME
-ready=READY
-welcome=Welcome
-error_msg=You should select a smaller portion than it's full size
-empty_name=You forgot to type your name
-audio=AUDIO
-sublevel=Sublevel
-continue=Continue
-custom_game=CUSTOMIZE THE CURRENT GAME
+audio=AUDIO
+circle_name=Circles
+continue=Continue
+custom_game=CUSTOMIZE THE CURRENT GAME
+difficulty=Difficulty
+empty_name=You forgot to type your name
+error_msg=You should select a smaller portion than it's full size
+game_menu_title=SELECT OPERATION AND DIFFICULTY
+good_job=Good Job
+insert_name=ENTER YOUR NAME
+label_name=labels
+level=Level
+loading=LOADING
+menu_back=GO BACK
+menu_help=SEE SOLUTION
+menu_list=MAIN MENU
+menu_title=SELECT GAME
+menu_world=LANGUAGE SELECTION
+mode_name=MODE
+ready=READY
+retry=Try again
+show=Show
+square_name=Quadrangles
+sublevel=Sublevel
+title=Fractions
+welcome=Hi

+ 26 - 26
assets/lang/es_PE

@@ -1,26 +1,26 @@
-loading=CARGANDO
-title=Fracciones
-menu_title=SELECCIONE UN JUEGO
-difficulty=Dificultad
-level=Nivel
-game_menu_title=SELECCIONA LA OPERACION Y DIFICULTAD
-good_job=Bien hecho
-retry=Inténtalo de nuevo
-menu_world=SELECCION DE IDIOMA
-menu_list=MENU PRINCIPAL
-menu_back=REGRESAR
-menu_help=VER SOLUCION
-circle_name=Circulos
-square_name=Cuadrilateros
-label_name=etiquetas
-mode_name=MODO
-show=Mostrar
-insert_name=INGRESA TU NOMBRE
-ready=LISTO
-welcome=Hola que tal
-error_msg=Debes seleccionar una porción más pequeña que su tamaño completo
-empty_name=Usted ha olvidado de escribir su nombre
-audio=AUDIO
-sublevel=Subnivel
-continue=Continúa
-custom_game=PERSONALIZAR EL JUEGO ACTUAL
+audio=AUDIO
+circle_name=Circulos
+continue=Continúa
+custom_game=PERSONALIZAR EL JUEGO ACTUAL
+difficulty=Dificultad
+empty_name=Usted ha olvidado de escribir su nombre
+error_msg=Debes seleccionar una porción más pequeña que su tamaño completo
+game_menu_title=SELECCIONA LA OPERACION Y DIFICULTAD
+good_job=Bien hecho
+insert_name=INGRESA TU NOMBRE
+label_name=etiquetas
+level=Nivel
+loading=CARGANDO
+menu_back=REGRESAR
+menu_help=VER SOLUCION
+menu_list=MENU PRINCIPAL
+menu_title=SELECCIONE UN JUEGO
+menu_world=SELECCION DE IDIOMA
+mode_name=MODO
+ready=LISTO
+retry=Inténtalo de nuevo
+show=Mostrar
+square_name=Cuadrilateros
+sublevel=Subnivel
+title=Fracciones
+welcome=Hola

+ 26 - 26
assets/lang/fr_FR

@@ -1,26 +1,26 @@
-loading=CHARGEMENT
-title=Fractions
-menu_title=SÉLECTIONNER UN JEU
-difficulty=Difficulté
-level=Niveau
-game_menu_title=OPERATION SELECT ET DIFFICULTÉ
-good_job=Bon travail
-retry=Réessayer
-menu_world=SÉLECTION DE LA LANGUE
-menu_list=MENU PRINCIPAL
-menu_back=RETOUR
-menu_help=VIEW SOLUTION
-circle_name=Circles
-square_name=Quadrangles
-label_name=étiquettes
-mode_name=MODE
-show=Afficher les
-insert_name=ENTREZ VOTRE NOM
-ready=PRÊT
-welcome=Salut
-error_msg=Vous devriez choisir une portion plus petite que sa taille totale
-empty_name=Vous avez oublié de taper votre nom
-audio=AUDIO
-sublevel=Sous-niveau
-continue=Continuez
-custom_game=PERSONNALISER LE JEU ACTUEL
+audio=AUDIO
+circle_name=Cercles
+continue=Continuez
+custom_game=PERSONNALISER LE JEU ACTUEL
+difficulty=Difficulté
+empty_name=Vous avez oublié de taper votre nom
+error_msg=Vous devriez choisir une portion plus petite que sa taille totale
+game_menu_title=SÉLECTIONNEZ L'OPÉRATION ET LA DIFFICULTÉ
+good_job=Bon travail
+insert_name=ENTREZ VOTRE NOM
+label_name=étiquettes
+level=Niveau
+loading=CHARGEMENT
+menu_back=REVENIR
+menu_help=VOIR LA SOLUTION
+menu_list=MENU PRINCIPAL
+menu_title=SÉLECTIONNEZ UN JEU
+menu_world=SÉLECTIONNEZ UNE LANGUE
+mode_name=MODE
+ready=PRÊT
+retry=Réessayer
+show=Afficher les
+square_name=Quadrangles
+sublevel=Sous-niveau
+title=Fractions
+welcome=Salut

+ 26 - 26
assets/lang/it_IT

@@ -1,26 +1,26 @@
-loading=CARICANDO
-title=Frazioni
-menu_title=SELEZIONA UN GRIOCO
-difficulty=Difficoltá
-level=Livello
-game_menu_title=SELEZIONARE UNA OPERAZIONE E UNA DIFFICOLTÁ
-good_job=Buon lavoro
-retry=Tenta di nuovo
-menu_world=SELEZIONARE IDIOMA
-menu_list=MENÚ PRINCIPALE
-menu_back=INDIETRO
-menu_help=GUARDA SOLUZIONE
-circle_name=Cerchi
-square_name=Quadrilateri
-label_name=legendas
-mode_name=MODO
-show=Mostra le
-insert_name=SCRIVI IL TUO NOME
-ready=OK
-welcome=Ciao
-error_msg=Devi scegliere una porzione minore della grandezza totale
-empty_name=Ti sei dimenticato di digitare il tuo nome
-audio=AUDIO
-sublevel=Sottolivello
-continue=Continua
-custom_game=PERSONALIZZA IL GIOCO ATTUALE
+audio=AUDIO
+circle_name=Cerchi
+continue=Continua
+custom_game=PERSONALIZZA IL GIOCO ATTUALE
+difficulty=Difficoltá
+empty_name=Ti sei dimenticato di digitare il tuo nome
+error_msg=Devi scegliere una porzione minore della grandezza totale
+game_menu_title=SELEZIONARE UNA OPERAZIONE E UNA DIFFICOLTÁ
+good_job=Buon lavoro
+insert_name=SCRIVI IL TUO NOME
+label_name=legendas
+level=Livello
+loading=CARICANDO
+menu_back=INDIETRO
+menu_help=GUARDA SOLUZIONE
+menu_list=MENÚ PRINCIPALE
+menu_title=SELEZIONA UN GRIOCO
+menu_world=SELEZIONARE IDIOMA
+mode_name=MODO
+ready=OK
+retry=Tenta di nuovo
+show=Mostra le
+square_name=Quadrilateri
+sublevel=Sottolivello
+title=Frazioni
+welcome=Ciao

+ 26 - 26
assets/lang/pt_BR

@@ -1,26 +1,26 @@
-loading=CARREGANDO
-title=Frações
-menu_title=SELECIONE UM JOGO
-difficulty=Dificuldade
-level=Nível
-game_menu_title=SELECIONAR OPERAÇÃO E DIFICULDADE
-good_job=Bom trabalho
-retry=Tente novamente
-menu_world=SELECIONAR IDIOMA
-menu_list=MENU PRINCIPAL
-menu_back=VOLTAR
-menu_help=VER SOLUÇÃO
-circle_name=Círculos
-square_name=Quadriláteros
-label_name=legendas
-mode_name=MODO
-show=Mostrar
-insert_name=DIGITE SEU NOME
-ready=PRONTO
-welcome=Olá
-error_msg=Você deve selecionar uma porção menor que o seu tamanho total
-empty_name=Você esqueceu de digitar seu nome
-audio=ÁUDIO
-sublevel=Subnível
-continue=Continue
-custom_game=PERSONALIZE O JOGO ATUAL
+audio=ÁUDIO
+circle_name=Círculos
+continue=Continue
+custom_game=PERSONALIZE O JOGO ATUAL
+difficulty=Dificuldade
+empty_name=Você esqueceu de digitar seu nome
+error_msg=Você deve selecionar uma porção menor que o seu tamanho total
+game_menu_title=SELECIONAR OPERAÇÃO E DIFICULDADE
+good_job=Bom trabalho
+insert_name=DIGITE SEU NOME
+label_name=legendas
+level=Nível
+loading=CARREGANDO
+menu_back=VOLTAR
+menu_help=VER SOLUÇÃO
+menu_list=MENU PRINCIPAL
+menu_title=SELECIONE UM JOGO
+menu_world=SELECIONAR IDIOMA
+mode_name=MODO
+ready=PRONTO
+retry=Tente novamente
+show=Mostrar
+square_name=Quadriláteros
+sublevel=Subnível
+title=Frações
+welcome=Olá

+ 25 - 7
index.html

@@ -57,7 +57,7 @@
 			<div class="panel-body">
 				<!-- iFractions game -->
 				<canvas id="iFractions-canvas"></canvas>
-				<!-- get player name -->
+				<!-- Textbox to get player name -->
 				<div id="textbox" onsubmit="return false">
 					<input type="text" id="textbox-content" value="" size="13" maxlength="36">
 				</div>
@@ -65,7 +65,7 @@
 			</div>
 		</div>
 
-		<div id="div-fps"><!-- display frames per second in debugmode --></div>
+		<div id="display-fps"><!-- Display fps in debugmode --></div>
 
 		<div class="panel panel-info">
 			<div class="panel-heading">TEAM</div>
@@ -94,14 +94,14 @@
 			<div class="panel-heading">TECHNOLOGY</div>
 			<div class="panel-body text-center">
 				<ul>
-					<li> We used <strong>HTML5</strong>, <strong>CSS</strong> and the <strong>Javascript</strong>
-						library <a href="http://phaser.io/" target="_blank"><strong>Phaser.io</strong></a> </li>
+					<li> We used <strong>HTML5</strong>, <strong>CSS</strong> and <strong>Javascript</strong></li>
 				</ul>
 			</div>
 		</div>
 
 	</div>
 
+	<!-- Load all js files -->
 	<script src="js/preMenu.js"></script>
 	<script src="js/menu.js"></script>
 	<script src="js/map.js"></script>
@@ -110,18 +110,36 @@
 	<script src="js/squareTwo.js"></script>
 	<script src="js/gameMechanics.js"></script>
 	<script src="js/globals.js"></script>
-
 	<script>
 		
-		const displayFps = document.getElementById("div-fps");
+		const displayFps = document.getElementById("display-fps");
 
 		const canvas = document.getElementById("iFractions-canvas");
 		canvas.width = defaultWidth; 
 		canvas.height = defaultHeight;
 
 		const context = canvas.getContext("2d");
+		
+		info.start();
+
+		// CREATING GAME STATES
+        game.state.add('boot', bootState);
+        game.state.add('lang', langState);
+        game.state.add('loadLang', loadLangState);
+        game.state.add('name', nameState);
+
+		game.state.add('menu', menuState);
+        game.state.add('customMenu', customMenuState);
+
+        game.state.add('map', mapState);
+        game.state.add('end', endState);
+
+        game.state.add('squareOne', squareOne);
+        game.state.add('circleOne', circleOne);
+        game.state.add('squareTwo', squareTwo);
 
-		boot.preload();
+		// CALLING FIRST GAME STATE
+		game.state.start('boot');
 	
 	</script>
 

+ 141 - 114
js/circleOne.js

@@ -1,70 +1,59 @@
-/*
-
-    GAME LEVELS - CIRCLE I & II: balloon level
-    
-    Name of game state : 'CircleOne' 
-    Shape : circle
-    Character : kid/balloon
-    Theme : flying a balloon
-    Concept : 'How much the kid has to walk to get to the balloon?'
-    Represent fractions as : circles
-
-    # of different difficulties for each level : 5
-
-    Levels can be : 'A' or 'B' (in variable 'levelType')
-
-        A : Player can place balloon position
-            Place balloon in position (so the kid can get to it)
-        B : Player can select # of circles
-            Selects number of circles (that represent distance kid needs to walk to get to the balloon)
-
-    Sublevels can be : 'Plus', 'Minus' or 'Mixed' (in variable 'sublevelType')
-    
-        Plus : addition of fractions
-            Represented by : kid going to the right (floor positions 0..5)
-        Minus : subtraction of fractions
-            Represented by: kid going to the left (floor positions 5..0)
-        Mixed : Mix addition and subtraction of fractions in same 
-            Represented by: kid going to the left (floor positions 0..5)
-*/
-
+/**
+ *  GAME STATE
+ * 
+ *  LEVELS - CIRCLE I & II: balloon level
+ *    
+ *  Name of game state : 'circleOne' 
+ *  Shape : circle
+ *  Character : kid/balloon
+ *  Theme : flying a balloon
+ *  Concept : 'How much the kid has to walk to get to the balloon?'
+ *  Represent fractions as : circles
+ *
+ *  # of different difficulties for each level : 5
+ *
+ *  Levels can be : 'A' or 'B' (in variable 'levelType')
+ *
+ *      A : Player can place balloon position
+ *          Place balloon in position (so the kid can get to it)
+ *      B : Player can select # of circles
+ *          Selects number of circles (that represent distance kid needs to walk to get to the balloon)
+ *
+ *  Sublevels can be : 'Plus', 'Minus' or 'Mixed' (in variable 'sublevelType')
+ *   
+ *      Plus : addition of fractions
+ *          Represented by : kid going to the right (floor positions 0..5)
+ *      Minus : subtraction of fractions
+ *          Represented by: kid going to the left (floor positions 5..0)
+ *      Mixed : Mix addition and subtraction of fractions in same 
+ *          Represented by: kid going to the left (floor positions 0..5)
+ *
+ * @namespace
+ */
 const circleOne = {
 
-    preload: function () {
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
-        // NOTHING TO LOAD HERE
-        circleOne.create();
-
-    },
-
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         // CONTROL VARIABLES
 
         this.availableAnimations = [];
         this.changeAnimationFrames = undefined;
-        this.checkAnswer = false; //Check kid inside ballon's basket
-        this.animate = false; //Start move animation
-        this.animateEnding = false; //Start ballon fly animation
-        this.hasClicked = false; //Air ballon positioned
-        this.result = false; //Game is correct
+        this.checkAnswer = false; // Check kid inside ballon's basket
+        this.animate = false; // Start move animation
+        this.animateEnding = false; // Start ballon fly animation
+        this.hasClicked = false; // Air ballon positioned
+        this.result = false; // Game is correct
         this.count = 0;
 
-        this.divisorsList = ""; // used in func_postScore
+        this.divisorsList = ''; // Used in func_postScore
 
         let hasBaseDifficulty = false; // Will validate that level isnt too easy (has at least one '1/difficulty' fraction)         
 
         const startX = (sublevelType == 'Minus') ? 66 + 5 * 156 : 66;  // Initial 'x' coordinate for the kid and the baloon
-        this.correctX = startX; //Ending position, accumulative
+        this.correctX = startX; // Ending position, accumulative
 
         // BACKGROUND
 
@@ -94,9 +83,9 @@ const circleOne = {
 
         // Calls function that loads navigation icons
         navigationIcons.func_addIcons(
-            true, true, true, // left buttons
-            true, false,      // right buttons
-            menuScreenCustom, this.func_viewHelp
+            true, true, true, // Left buttons
+            true, false,      // Right buttons
+            'customMenu', this.func_viewHelp
         );
 
 
@@ -125,7 +114,7 @@ const circleOne = {
         const min = (sublevelType == 'Mixed' && mapPosition < 2) ? 2 : mapPosition; // Mixed level has at least 2 fractions
         const total = game.math.randomInRange(min, max); // Total number of circles
 
-        // levelType 'B' exclusive variables
+        // LevelType 'B' exclusive variables
         this.fractionIndex = -1; // Index of clicked circle (game B)
         this.numberOfPlusFractions = game.math.randomInRange(1, total - 1);
 
@@ -140,9 +129,9 @@ const circleOne = {
 
             const divisor = game.math.randomInRange(1, gameDifficulty); // Set fraction 'divisor' (depends on difficulty)
 
-            if (divisor == gameDifficulty) hasBaseDifficulty = true; // true if after for ends has at least 1 '1/difficulty' fraction
+            if (divisor == gameDifficulty) hasBaseDifficulty = true; // True if after for ends has at least 1 '1/difficulty' fraction
 
-            this.divisorsList += divisor + ","; // Add this divisor to the list of divisors (for func_postScore)
+            this.divisorsList += divisor + ','; // Add this divisor to the list of divisors (for func_postScore)
 
             // Set each circle direction
             let direction;
@@ -157,7 +146,7 @@ const circleOne = {
             }
             this.circles.direction[i] = direction;
 
-            // set each circle color
+            // Set each circle color
             let lineColor, anticlockwise;
 
             if (direction == 'Right') {
@@ -192,7 +181,7 @@ const circleOne = {
 
                 let degree = 360 / divisor;
 
-                if (direction == 'Right') degree = 360 - degree; // anticlockwise equivalent
+                if (direction == 'Right') degree = 360 - degree; // Anticlockwise equivalent
 
                 circle = game.add.graphic.arc(startX, 490 - i * this.circles.diameter, this.circles.diameter,
                     0, game.math.degreeToRad(degree), anticlockwise,
@@ -211,7 +200,7 @@ const circleOne = {
 
             circle.rotate = 90;
 
-            //If game is type B (select fractions)
+            // If game is type B (select fractions)
             if (levelType == 'B') {
                 circle.alpha = 0.5;
                 circle.index = i;
@@ -224,20 +213,20 @@ const circleOne = {
 
         }
 
-        //Calculate next circle
+        // Calculate next circle
         this.nextX = startX + this.circles.distance[0] * this.circles.direc[0];
 
 
 
-        // check if need to restart
-        let restart = false;
+        // Check if need to restart
+        this.restart = false;
 
-        //If top circle position is out of bounds (when on the ground) or game doesnt have base difficulty, restart
+        // If top circle position is out of bounds (when on the ground) or game doesnt have base difficulty, restart
         if (this.correctX < 66 || this.correctX > 66 + 3 * 260 || !hasBaseDifficulty) {
-            restart = true;
+            this.restart = true;
         }
 
-        //If game is type B, selectiong a random balloon place
+        // If game is type B, selectiong a random balloon place
         if (levelType == 'B') {
 
             this.balloonPlace = startX;
@@ -247,9 +236,9 @@ const circleOne = {
                 this.balloonPlace += this.circles.distance[i] * this.circles.direc[i];
             }
 
-            //If balloon position is out of bounds, restart
+            // If balloon position is out of bounds, restart
             if (this.balloonPlace < 66 || this.balloonPlace > 66 + 5 * distanceBetweenPoints) {
-                restart = true;
+                this.restart = true;
             }
 
         }
@@ -281,39 +270,36 @@ const circleOne = {
         this.basket = game.add.image(this.balloonPlace, 472, 'balloon_basket');
         this.basket.anchor(0.5, 0.5);
 
-        // help pointer
+        // Help pointer
         this.help = game.add.image(0, 0, 'help_pointer', 0.5);
         this.help.anchor(0.5, 0);
         this.help.alpha = 0;
 
 
 
-        if (restart) {
-            circleOne.preload();
-        } else {
-            game.render.all();
-
+        if (!this.restart) {
             game.timer.start(); // Set a timer for the current level (used in func_postScore)
 
-            game.event.add('click', circleOne.func_onInputDown);
-            game.event.add('mousemove', circleOne.func_onInputOver);
-
-            game.loop.start(this);
+            game.event.add('click', this.func_onInputDown);
+            game.event.add('mousemove', this.func_onInputOver);
         }
 
     },
 
+    /**
+     * Game loop
+     */
     update: function () {
 
         self.count++;
 
-        //Start animation
+        // Start animation
         if (self.animate) {
 
             let cur = self.circles.cur;
             let DIREC = self.circles.direc[cur];
 
-            if (self.count % 2 == 0) { // lowers animation
+            if (self.count % 2 == 0) { // Lowers animation
 
                 // Move kid
                 self.kid.x += 2 * DIREC;
@@ -341,7 +327,7 @@ const circleOne = {
 
                     lowerCircles = self.circles.all[cur].x <= self.nextX;
 
-                    // if just changed from 'right' to 'left' inform to change direction of kid animation
+                    // If just changed from 'right' to 'left' inform to change direction of kid animation
                     if (self.changeAnimationFrames == undefined && cur > 0 && self.circles.direction[cur - 1] == 'Right') {
                         self.changeAnimationFrames = true;
                     }
@@ -370,7 +356,7 @@ const circleOne = {
                     self.kid.y += self.circles.diameter; // Lower kid
 
 
-                    self.circles.cur++; // update current circle
+                    self.circles.cur++; // Update current circle
 
                     cur = self.circles.cur;
                     DIREC = self.circles.direc[cur];
@@ -388,7 +374,7 @@ const circleOne = {
 
         }
 
-        //Check if kid is inside the basket
+        // Check if kid is inside the basket
         if (self.checkAnswer) {
 
             game.timer.stop();
@@ -396,14 +382,14 @@ const circleOne = {
             game.animation.stop(self.kid.animation[0]);
 
             if (self.func_checkOverlap(self.basket, self.kid)) {
-                self.result = true; // answer is correct
+                self.result = true; // Answer is correct
                 self.kid.curFrame = (self.kid.curFrame < 12) ? 24 : 25;
                 if (audioStatus) game.audio.okSound.play();
                 game.add.image(defaultWidth / 2, defaultHeight / 2, 'ok').anchor(0.5, 0.5);
                 completedLevels++;
-                if (debugMode) console.log("completedLevels = " + completedLevels);
+                if (debugMode) console.log('completedLevels = ' + completedLevels);
             } else {
-                self.result = false; // answer is incorrect
+                self.result = false; // Answer is incorrect
                 if (audioStatus) game.audio.errorSound.play();
                 game.add.image(defaultWidth / 2, defaultHeight / 2, 'error').anchor(0.5, 0.5);
             }
@@ -417,7 +403,7 @@ const circleOne = {
 
         }
 
-        // balloon flying animation
+        // Balloon flying animation
         if (self.animateEnding) {
 
             self.balloon.y -= 2;
@@ -430,7 +416,7 @@ const circleOne = {
                 if (self.result) mapMove = true;
                 else mapMove = false;
 
-                mapScreen.preload();
+                game.state.start('map');
 
             }
         }
@@ -442,6 +428,11 @@ const circleOne = {
 
     /* EVENT HANDLER */
 
+    /**
+     * Called by mouse click event 
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
     func_onInputDown: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
@@ -459,8 +450,7 @@ const circleOne = {
         // LEVEL B : click circle
         if (levelType == 'B') {
             self.circles.all.forEach(cur => {
-                const distance = game.math.distanceToPointer(x, cur.xWithAnchor, y, cur.yWithAnchor);
-                const valid = distance <= (cur.diameter / 2) * cur.scale;
+                const valid = game.math.distanceToPointer(x, cur.xWithAnchor, y, cur.yWithAnchor) <= (cur.diameter / 2) * cur.scale;
                 if (valid) self.func_clicked(cur);
             });
         }
@@ -471,6 +461,11 @@ const circleOne = {
 
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
     func_onInputOver: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
@@ -485,14 +480,15 @@ const circleOne = {
                 self.basket.x = x;
             }
 
+            document.body.style.cursor = 'auto';
+
         }
 
         // LEVEL B : hover circle
         if (levelType == 'B' && !self.hasClicked) {
 
             self.circles.all.forEach(cur => {
-                const distance = game.math.distanceToPointer(x, cur.xWithAnchor, y, cur.yWithAnchor);
-                const valid = distance <= (cur.diameter / 2) * cur.scale;
+                const valid = game.math.distanceToPointer(x, cur.xWithAnchor, y, cur.yWithAnchor) <= (cur.diameter / 2) * cur.scale;
                 if (valid) {
                     self.func_overCircle(cur);
                     flag = true;
@@ -502,6 +498,8 @@ const circleOne = {
 
         }
 
+        navigationIcons.func_onInputOver(x, y);
+
         game.render.all();
 
     },
@@ -510,11 +508,17 @@ const circleOne = {
 
     /* CALLED BY EVENT HANDLER */
 
-    // in levelType 'B'
+    /**
+     * (in levelType 'B')
+     * 
+     * Function called when cursor is over a valid circle
+     * 
+     * @param {object} cur circle the cursor is over
+     */
     func_overCircle: function (cur) {
 
         if (!self.hasClicked) {
-            document.body.style.cursor = "pointer";
+            document.body.style.cursor = 'pointer';
             for (let i in self.circles.all) {
                 self.circles.all[i].alpha = (i <= cur.index) ? 1 : 0.5;
             }
@@ -522,11 +526,15 @@ const circleOne = {
 
     },
 
-    // in levelType 'B'
+    /**
+     * (in levelType 'B')
+     * 
+     * Function called when cursor is out of a valid circle
+     */
     func_outCircle: function () {
 
         if (!self.hasClicked) {
-            document.body.style.cursor = "auto";
+            document.body.style.cursor = 'auto';
             self.circles.all.forEach(cur => {
                 cur.alpha = 0.5;
             });
@@ -534,7 +542,13 @@ const circleOne = {
 
     },
 
-    // in levelType 'B'
+    /**
+     * (in levelType 'B')
+     * 
+     * Function called when player clicked over a valid circle
+     * 
+     * @param {number|object} cur clicked circle
+     */
     func_clicked: function (cur) {
 
         if (!self.hasClicked) {
@@ -546,7 +560,7 @@ const circleOne = {
                 // On levelType B
             } else if (levelType == 'B') {
 
-                document.body.style.cursor = "auto";
+                document.body.style.cursor = 'auto';
 
                 for (let i in self.circles.all) {
                     if (i <= cur.index) {
@@ -561,7 +575,7 @@ const circleOne = {
 
             if (audioStatus) game.audio.beepSound.play();
 
-            // hide fractions
+            // Hide fractions
             if (fractionLabel) {
                 self.circles.label.forEach(cur => {
                     cur.forEach(cur => {
@@ -590,17 +604,27 @@ const circleOne = {
 
     /* GAME FUNCTIONS */
 
+    /**
+     * Checks if 2 images overlap
+     * 
+     * @param {object} spriteA image 1
+     * @param {object} spriteB image 2
+     * @returns {boolean}
+     */
     func_checkOverlap: function (spriteA, spriteB) {
 
         const xA = spriteA.x;
         const xB = spriteB.x;
 
-        // consider it comming from both sides
+        // Consider it comming from both sides
         if (Math.abs(xA - xB) > 14) return false;
         else return true;
 
     },
 
+    /**
+     * Display correct answer
+     */
     func_viewHelp: function () {
 
         if (!self.hasClicked) {
@@ -625,21 +649,24 @@ const circleOne = {
 
     /* METADATA FOR GAME */
 
+    /**
+     * Saves players data after level
+     */
     func_postScore: function () {
 
         // Create some variables we need to send to our PHP file
-        const data = "&s_game=" + gameShape
-            + "&s_mode=" + levelType
-            + "&s_oper=" + sublevelType
-            + "&s_leve=" + gameDifficulty
-            + "&s_posi=" + mapPosition
-            + "&s_resu=" + self.result
-            + "&s_time=" + game.timer.elapsed
-            + "&s_deta="
-            + "numCircles:" + self.circles.all.length
-            + ", valCircles: " + self.divisorsList
-            + " balloonX: " + self.basket.x
-            + ", selIndex: " + self.fractionIndex;
+        const data = '&s_game=' + gameShape
+            + '&s_mode=' + levelType
+            + '&s_oper=' + sublevelType
+            + '&s_leve=' + gameDifficulty
+            + '&s_posi=' + mapPosition
+            + '&s_resu=' + self.result
+            + '&s_time=' + game.timer.elapsed
+            + '&s_deta='
+            + 'numCircles:' + self.circles.all.length
+            + ', valCircles: ' + self.divisorsList
+            + ' balloonX: ' + self.basket.x
+            + ', selIndex: ' + self.fractionIndex;
 
         postScore(data);
 

File diff suppressed because it is too large
+ 561 - 240
js/gameMechanics.js


+ 223 - 208
js/globals.js

@@ -16,196 +16,186 @@
 .................................................... 
 */
 
+// Can be: 'squareOne', 'squareTwo' or 'circleOne'
+let gameType, gameTypeString;
+
+// Can be: 'circle' or 'square'
+let gameShape;
+
+// In squareOne/circleOne 	can be: 'A' (click on the floor) or 'B' (click on the amount to go/stacked figures)
+// In squareTwo           	can be: 'C' (comparing fractions)
+let levelType;
+
+// In squareOne		can be: 'Plus' or 'Minus'
+// In circleOne 	can be: 'Plus', 'Minus' or 'Mixed'
+// In squareTwo     can be: 'B' or 'C'
+let sublevelType;
+
+// In squareOne 			can be: 1..3
+// In circleOne/squareTwo	can be: 1..5
+let gameDifficulty;
+
+const medSrc = 'assets/img/'; // Base directory for media
 const defaultWidth = 900;
 const defaultHeight = 600;
-const medSrc = "assets/img/";
-
 const debugMode = false; 	// Turns console messages ON/OFF
 let audioStatus = false; 	// Turns game audio ON/OFF
 let fractionLabel = true; 	// Turns showing fractions in levels ON/OFF
 
 let playerName;
 let langString; 		// String that contains the selected language
-
 let self;				// Current state
-
-let mapPosition;		// character position in the map (1..4 valid, 5 end)
+let mapPosition;		// Character position in the map (1..4 valid, 5 end)
 let mapMove;			// When true, the character can move to next position in the map
 let completedLevels;	// Number of finished levels in the map
 
-/* GAME TYPE (in menu screen)
- * can be: squareOne, 'SquareTwo' or 'CircleOne' */
-let gameType, gameTypeString;
-
-let gameShape;	// can be: 'circle' or 'square'
-
-/* LEVEL TYPE (in menu screen)
- * in squareOne/circleOne 	can be: 'A' (click on the floor) or 'B' (click on the amount to go/stacked figures)
- * in squareTwo           	can be: 'C' (comparing fractions) */
-let levelType;
-
-/* SUBLEVEL TYPE (in difficulty screen)
- * in squareOne		can be: 'Plus' or 'Minus'
- * in circleOne 	can be: 'Plus', 'Minus' or 'Mixed'
- * in squareTwo     can be: 'A', 'B' or 'C' */
-let sublevelType;
-
-/* GAME DIFFICULTY 
- * in squareOne 			can be: 1..3
- * in circleOne/squareTwo	can be: 1..5 */
-let gameDifficulty;
-
+// Informations for each game
 const info = {
 
-	squareOne : {
-		gameShape : 'Square',
-		gameType : 'squareOne',
-		gameTypeUrl : 'game0',
-		levelType : ['A', 'B'],
-		levelTypeUrl : ['level0', 'level1'],
-		sublevelType : ['Plus', 'Minus'],
-		gameDifficulty : 3
+	squareOne: {
+		gameShape: 'square',
+		gameType: 'squareOne',
+		gameTypeUrl: 'game0',
+		levelType: ['A', 'B'],
+		levelTypeUrl: ['level0', 'level1'],
+		sublevelType: ['Plus', 'Minus'],
+		gameDifficulty: 3
 	},
 
-	circleOne : {
-		gameShape : 'Circle',
-		gameType : 'circleOne',
-		gameTypeUrl : 'game1',
-		levelType : ['A', 'B'],
-		levelTypeUrl : ['level2','level3'],
-		sublevelType : ['Plus', 'Minus', 'Mixed'],
-		gameDifficulty : 5
+	circleOne: {
+		gameShape: 'circle',
+		gameType: 'circleOne',
+		gameTypeUrl: 'game1',
+		levelType: ['A', 'B'],
+		levelTypeUrl: ['level2', 'level3'],
+		sublevelType: ['Plus', 'Minus', 'Mixed'],
+		gameDifficulty: 5
 	},
 
-	squareTwo : {
-		gameShape : 'Square',
-		gameType : 'squareTwo',
-		gameTypeUrl : 'game2',
-		levelType : ['C'],
-		levelTypeUrl : [],
-		sublevelType : [/*'A',*/ 'B', 'C'],
-		gameDifficulty : 5
+	squareTwo: {
+		gameShape: 'square',
+		gameType: 'squareTwo',
+		gameTypeUrl: 'game2',
+		levelType: ['C'],
+		levelTypeUrl: [],
+		sublevelType: [/*'A',*/ 'B', 'C'],
+		gameDifficulty: 5
 	},
 
-	gameShape : [],
-	gameType : [],
-	gameTypeUrl : [],
-	levelType : [],
-	levelTypeUrl : [],
-	sublevelType : [],
-	gameDifficulty : [],
-
-	start : function () {
-
-		info.gameShape = [ 
-			info.squareOne.gameShape, 
-			info.circleOne.gameShape, 
+	gameShape: [],
+	gameType: [],
+	gameTypeUrl: [],
+	levelType: [],
+	levelTypeUrl: [],
+	sublevelType: [],
+	gameDifficulty: [],
+
+	/**
+	 * Load values
+	 */
+	start: function () {
+
+		info.gameShape = [
+			info.squareOne.gameShape,
+			info.circleOne.gameShape,
 			info.squareTwo.gameShape
 		];
-	
-		info.gameType = [ 
-			info.squareOne.gameType, 
+
+		info.gameType = [
+			info.squareOne.gameType,
 			info.circleOne.gameType,
 			info.squareTwo.gameType
 		];
-	
-		info.gameTypeUrl = [ 
-			info.squareOne.gameTypeUrl, 
+
+		info.gameTypeUrl = [
+			info.squareOne.gameTypeUrl,
 			info.circleOne.gameTypeUrl,
 			info.squareTwo.gameTypeUrl
 		];
-	
+
 		info.levelType = info.squareOne.levelType.concat(info.circleOne.levelType, info.squareTwo.levelType);
-	
+
 		info.levelTypeUrl = info.squareOne.levelTypeUrl.concat(info.circleOne.levelTypeUrl, info.squareTwo.levelTypeUrl);
-	
+
 		info.sublevelType = info.squareOne.sublevelType.concat(info.circleOne.sublevelType, info.squareTwo.sublevelType);
-	
-		info.gameDifficulty = [ 
-			info.squareOne.gameDifficulty, 
-			info.circleOne.gameDifficulty, 
-			info.squareTwo.gameDifficulty 
+
+		info.gameDifficulty = [
+			info.squareOne.gameDifficulty,
+			info.circleOne.gameDifficulty,
+			info.squareTwo.gameDifficulty
 		];
 
-	},
+	}
 
 };
 
 // Colors
 const colors = {
-
-	// blues
-
-	blueBckg: "#cce5ff", // background color 
-	blueBckgOff: "#adc8e6",
-	blueBckgInsideLevel: "#a8c0e6", // background color in squareOne (used for floor gap)
-	blue: "#003cb3", // subtitle
-	blueMenuLine: "#b7cdf4",
-	darkBlue: "#183780", // linecolor that indicates right and fraction numbers
-
-	// reds
-
-	red: "#b30000", // linecolor that indicates left
-	lightRed: "#d27979", // squareTwo figures
-	darkRed: "#330000", // squareTwo figures and some titles
-
-	// greens
-
-	green: "#00804d", // title
-	lightGreen: "#83afaf", // squareTwo figures
-	darkGreen: "#1e2f2f", // squareTwo figures
-	intenseGreen: "#00d600",
-
-	// neutrals
-	
-	white: "#efeff5",
-	gray: "#708090",
-	black: "#000",
-	yellow: "#fff570",
+	// Blues
+	blueBckg: '#cce5ff', // Background color 
+	blueBckgOff: '#adc8e6',
+	blueBckgInsideLevel: '#a8c0e6', // Background color in squareOne (used for floor gap)
+	blue: '#003cb3', // Subtitle
+	blueMenuLine: '#b7cdf4',
+	darkBlue: '#183780', // Line color that indicates right and fraction numbers
+
+	// Reds
+	red: '#b30000', // Linecolor that indicates left
+	lightRed: '#d27979', // squareTwo figures
+	darkRed: '#330000', // squareTwo figures and some titles
+
+	// Greens
+	green: '#00804d', // Title
+	lightGreen: '#83afaf', // squareTwo figures
+	darkGreen: '#1e2f2f', // squareTwo figures
+	intenseGreen: '#00d600',
+
+	// Basics
+	white: '#efeff5',
+	gray: '#708090',
+	black: '#000',
+	yellow: '#fff570'
 };
 
 // Text styles
 const textStyles = {
-
-	h1_green: { font: "32px Arial,sans-serif", fill: colors.green, align: "center" }, // menu title
-	h2_green: { font: "26px Arial,sans-serif", fill: colors.green, align: 'center' }, // flag labels (langScreen)
-
-	h1_white: { font: '32px Arial,sans-serif', fill: colors.white, align: 'center' }, // ok button (nameScreen)
-	h2_white: { font: '26px Arial,sans-serif', fill: colors.white, align: 'center' }, // difficulty buttons (menuScreen)
-	h4_white: { font: '20px Arial,sans-serif', fill: colors.white, align: 'center' }, // difficulty numbers (menuScreen)
-	p_white: { font: '14px Arial,sans-serif', fill: colors.white, align: 'center' }, // enter button (menuScreen)
-
-	h2_brown: { font: "26px Arial,sans-serif", fill: colors.darkRed, align: "center" }, // map difficulty label
-	h4_brown: { font: "20px Arial,sans-serif", fill: colors.darkRed, align: "center" }, // menu overtitle
-
-	h2_blue_2: { font: "26px Arial,sans-serif", fill: colors.blue, align: "center" }, // menu subtitle
-	h4_blue_2: { font: "20px Arial,sans-serif", fill: colors.blue, align: "center" }, // menu subtitle
-	h2_blue: { font: '26px Arial,sans-serif', fill: colors.darkBlue, align: 'center' }, // fractions
-	h4_blue: { font: '20px Arial,sans-serif', fill: colors.darkBlue, align: 'center' }, // fractions
-	p_blue: { font: '14px Arial,sans-serif', fill: colors.darkBlue, align: 'center' }, // fractions
-
+	h1_green: { font: '32px Arial,sans-serif', fill: colors.green, align: 'center' }, // Menu title
+	h2_green: { font: '26px Arial,sans-serif', fill: colors.green, align: 'center' }, // Flag labels (langState)
+
+	h1_white: { font: '32px Arial,sans-serif', fill: colors.white, align: 'center' }, // Ok button (nameState)
+	h2_white: { font: '26px Arial,sans-serif', fill: colors.white, align: 'center' }, // Difficulty buttons (menuState)
+	h4_white: { font: '20px Arial,sans-serif', fill: colors.white, align: 'center' }, // Difficulty numbers (menuState)
+	p_white: { font: '14px Arial,sans-serif', fill: colors.white, align: 'center' }, // Enter button (menuState)
+
+	h2_brown: { font: '26px Arial,sans-serif', fill: colors.darkRed, align: 'center' }, // Map difficulty label
+	h4_brown: { font: '20px Arial,sans-serif', fill: colors.darkRed, align: 'center' }, // Menu overtitle
+
+	h2_blue_2: { font: '26px Arial,sans-serif', fill: colors.blue, align: 'center' }, // Menu subtitle
+	h4_blue_2: { font: '20px Arial,sans-serif', fill: colors.blue, align: 'center' }, // Menu subtitle
+	h2_blue: { font: '26px Arial,sans-serif', fill: colors.darkBlue, align: 'center' }, // Fractions
+	h4_blue: { font: '20px Arial,sans-serif', fill: colors.darkBlue, align: 'center' }, // Fractions
+	p_blue: { font: '14px Arial,sans-serif', fill: colors.darkBlue, align: 'center' } // Fractions
 };
 
-
 // List of media URL
-url = {
+const url = {
 	boot: {
 		image: [
 			// Scene
 			['bgimage', medSrc + 'scene/bg.jpg'],
-			['bgmap', 	medSrc + 'scene/bg_map.png'],
-			['bush', 	medSrc + 'scene/bush.png'],
-			['cloud', 	medSrc + 'scene/cloud.png'],
-			['floor', 	medSrc + 'scene/floor.png'],
-			['place_off', 	medSrc + 'scene/place_off.png'],
-			['place_on', 	medSrc + 'scene/place_on.png'],
-			['rock', 	medSrc + 'scene/rock.png'],
-			['road', 	medSrc + 'scene/road.png'],
-			['sign', 	medSrc + 'scene/sign.png'],
-			['tree1', 	medSrc + 'scene/tree.png'],
-			['tree2', 	medSrc + 'scene/tree2.png'],
-			['tree3', 	medSrc + 'scene/tree3.png'],
-			['tree4', 	medSrc + 'scene/tree4.png'],
+			['bgmap', medSrc + 'scene/bg_map.png'],
+			['bush', medSrc + 'scene/bush.png'],
+			['cloud', medSrc + 'scene/cloud.png'],
+			['floor', medSrc + 'scene/floor.png'],
+			['place_off', medSrc + 'scene/place_off.png'],
+			['place_on', medSrc + 'scene/place_on.png'],
+			['rock', medSrc + 'scene/rock.png'],
+			['road', medSrc + 'scene/road.png'],
+			['sign', medSrc + 'scene/sign.png'],
+			['tree1', medSrc + 'scene/tree.png'],
+			['tree2', medSrc + 'scene/tree2.png'],
+			['tree3', medSrc + 'scene/tree3.png'],
+			['tree4', medSrc + 'scene/tree4.png'],
 			// Flags
 			['flag_BR', medSrc + 'flag/BRAZ.jpg'],
 			['flag_FR', medSrc + 'flag/FRAN.jpg'],
@@ -213,29 +203,29 @@ url = {
 			['flag_PE', medSrc + 'flag/PERU.jpg'],
 			['flag_US', medSrc + 'flag/UNST.jpg'],
 			// Navigation icons on the top of the page
-			['back', 		medSrc + 'navig_icon/back.png'],
-			['help', 		medSrc + 'navig_icon/help.png'],
-			['home', 		medSrc + 'navig_icon/home.png'],
-			['language', 	medSrc + 'navig_icon/language.png'],
-			['menu', 		medSrc + 'navig_icon/menu.png'],
+			['back', medSrc + 'navig_icon/back.png'],
+			['help', medSrc + 'navig_icon/help.png'],
+			['home', medSrc + 'navig_icon/home.png'],
+			['language', medSrc + 'navig_icon/language.png'],
+			['menu', medSrc + 'navig_icon/menu.png'],
 			// Interactive icons
-			['arrow_down', 		medSrc + 'interac_icon/down.png'],
-			['error', 			medSrc + 'interac_icon/error.png'],
-			['help_pointer', 	medSrc + 'interac_icon/pointer.png'],
-			['ok',				medSrc + 'interac_icon/ok.png'],
+			['arrow_down', medSrc + 'interac_icon/down.png'],
+			['error', medSrc + 'interac_icon/error.png'],
+			['help_pointer', medSrc + 'interac_icon/pointer.png'],
+			['ok', medSrc + 'interac_icon/ok.png'],
 			// Non-interactive icons
-			['arrow_double', 	medSrc + 'non_interac_icon/double.png'],
-			['arrow_left', 		medSrc + 'non_interac_icon/left_arrow.png'],
-			['arrow_right', 	medSrc + 'non_interac_icon/right_arrow.png'],
-			['equal', 			medSrc + 'non_interac_icon/equal.png']
+			['arrow_double', medSrc + 'non_interac_icon/double.png'],
+			['arrow_left', medSrc + 'non_interac_icon/left_arrow.png'],
+			['arrow_right', medSrc + 'non_interac_icon/right_arrow.png'],
+			['equal', medSrc + 'non_interac_icon/equal.png']
 		],
 		sprite: [
 			// Game Sprites
-			['kid_walk', 	medSrc + 'character/kid/walk.png', 26],
+			['kid_walk', medSrc + 'character/kid/walk.png', 26],
 			// Navigation icons on the top of the page
-			['audio', 		medSrc + 'navig_icon/audio.png', 2],
+			['audio', medSrc + 'navig_icon/audio.png', 2],
 			// Interactive icons
-			['select', 		medSrc + 'interac_icon/selectionBox.png', 2]
+			['select', medSrc + 'interac_icon/selectionBox.png', 2]
 		],
 		audio: [
 			// Sound effects
@@ -250,15 +240,15 @@ url = {
 			['game0', medSrc + 'levels/squareOne.png'], // Square I
 			['game1', medSrc + 'levels/circleOne.png'], // Circle I
 			['game2', medSrc + 'levels/squareTwo.png'], // Square II
-			// level
+			// Level
 			['level0', medSrc + 'levels/squareOne_1.png'], // Square I : A
 			['level1', medSrc + 'levels/squareOne_2.png'], // Square I : B
 			['level2', medSrc + 'levels/circleOne_1.png'], // Circle I : A
 			['level3', medSrc + 'levels/circleOne_2.png'], // Circle I : B
 			['level4', medSrc + 'levels/squareTwo.png'],  // Square II : C
-			// sublevel
-			['sublevel_right', medSrc + 'levels/sublevel_right.png'], // Square I/II : left
-			['sublevel_left', medSrc + 'levels/sublevel_left.png'], // Square I/II : right
+			// Sublevel
+			['sublevel_right', medSrc + 'levels/sublevel_right.png'], // Square/circle I : right
+			['sublevel_left', medSrc + 'levels/sublevel_left.png'], // Square/circle I : left
 			['sublevel_mixed', medSrc + 'levels/sublevel_mixed.png'], // Circle I : mixed
 			['sublevel_top', medSrc + 'levels/sublevel_top.png'], // Square II : top
 			['sublevel_bottom', medSrc + 'levels/sublevel_bottom.png']  // Square II : bottom
@@ -269,8 +259,8 @@ url = {
 	squareOne: {
 		image: [
 			// Scene
-			['farm', 	medSrc + 'scene/farm.png'],
-			['garage', 	medSrc + 'scene/garage.png']
+			['farm', medSrc + 'scene/farm.png'],
+			['garage', medSrc + 'scene/garage.png']
 		],
 		sprite: [
 			// Game sprites
@@ -281,13 +271,13 @@ url = {
 	squareTwo: {
 		image: [
 			// Scene
-			['house', 	medSrc + 'scene/house.png'],
-			['school', 	medSrc + 'scene/school.png']
+			['house', medSrc + 'scene/house.png'],
+			['school', medSrc + 'scene/school.png']
 		],
 		sprite: [
 			// Game sprites
-			['kid_standing', 	medSrc + 'character/kid/lost.png', 6],
-			['kid_run', 		medSrc + 'character/kid/run.png', 12]
+			['kid_standing', medSrc + 'character/kid/lost.png', 6],
+			['kid_run', medSrc + 'character/kid/run.png', 12]
 		],
 		audio: []
 	},
@@ -311,14 +301,23 @@ url = {
 // Navigation icons on the top of the screen
 const navigationIcons = {
 
-	// Add navigation icons on the top of the screen based on parameters
-
-	func_addIcons: function (left_btn0, left_btn1, left_btn2, 	// first 3 icon spaces
-		right_btn0, right_btn1, 			// last 2 icon spaces
-		level, helpBtn) { 					// auxiliar variables
+	/**
+	 * Add navigation icons.
+	 * The icons on the left are ordered from left to right.
+	 * The icons on the right are ordered from right to left.
+	 * 
+	 * @param {boolean} leftIcon0 1st left icon 
+	 * @param {boolean} leftIcon1 2nd left icon
+	 * @param {boolean} leftIcon2 3rd left icon
+	 * @param {boolean} rightIcon0 1st right icon
+	 * @param {boolean} rightIcon1 2nd right icon
+	 * @param {string} level state to be called by the 'back' button
+	 * @param {function} help function in the current state that display correct answer
+	 */
+	func_addIcons: function (leftIcon0, leftIcon1, leftIcon2, rightIcon0, rightIcon1, level, help) {
 
 		this.level = level;
-		this.helpBtn = helpBtn;
+		this.help = help;
 
 		let left_x = 10;
 		let right_x = defaultWidth - 50 - 10;
@@ -327,25 +326,27 @@ const navigationIcons = {
 
 		// 'Descriptive labels' for the navigation icons
 
-		this.left_text = game.add.text(left_x, 73, "", textStyles.h4_brown, 'left');
+		this.left_text = game.add.text(left_x, 73, '', textStyles.h4_brown, 'left');
+
+		this.right_text = game.add.text(right_x + 50, 73, '', textStyles.h4_brown, 'right');
+
 
-		this.right_text = game.add.text(right_x + 50, 73, "", textStyles.h4_brown, 'right');
 
 		// 'Icons' on the LEFT side of the page
 
-		if (left_btn0) { // Return to select difficulty screen
+		if (leftIcon0) { // Return to select difficulty screen
 			const icon_back = game.add.image(left_x, 10, 'back');
 			this.iconsList.push(icon_back);
 			left_x += 50; // Offsets value of x for next icon
 		}
 
-		if (left_btn1) { // Return to main menu screen
+		if (leftIcon1) { // Return to main menu screen
 			const icon_list = game.add.image(left_x, 10, 'menu');
 			this.iconsList.push(icon_list);
 			left_x += 50; // Offsets value of x for next icon
 		}
 
-		if (left_btn2) { // In some levels, shows solution to the game
+		if (leftIcon2) { // In some levels, shows solution to the game
 			const icon_help = game.add.image(left_x, 10, 'help');
 			this.iconsList.push(icon_help);
 			left_x += 50; // Offsets value of x for next icon
@@ -353,14 +354,14 @@ const navigationIcons = {
 
 		// 'Icons' on the RIGHT side of the page
 
-		if (right_btn0) { // Turns game audio on/off
+		if (rightIcon0) { // Turns game audio on/off
 			this.icon_audio = game.add.sprite(right_x, 10, 'audio', 1);
 			audioStatus ? this.icon_audio.curFrame = 0 : this.icon_audio.curFrame = 1;
 			this.iconsList.push(this.icon_audio);
 			right_x -= 50; // Offsets value of x for next icon
 		}
 
-		if (right_btn1) { // Return to select language screen
+		if (rightIcon1) { // Return to select language screen
 			icon_world = game.add.image(right_x, 10, 'language');
 			this.iconsList.push(icon_world);
 			right_x -= 50; // Offsets value of x for next icon
@@ -368,31 +369,39 @@ const navigationIcons = {
 
 	},
 
-	func_CallScreen: function (screen) {
+	/**
+	 * When back icon is clicked go this state
+	 * 
+	 * @param {string} state name of the next state
+	 */
+	func_CallState: function (state) {
 
 		if (audioStatus) game.audio.beepSound.play();
 
 		game.event.clear(self);
 
-		screen.preload();
+		game.state.start(state);
 
 	},
 
+	/**
+	 * Called by mouse click event 
+	 * 
+	 * @param {number} x contains the mouse x coordinate
+	 * @param {number} y contains the mouse y coordinate
+	 */
 	func_onInputDown: function (x, y) {
 
 		navigationIcons.iconsList.forEach(cur => {
 
-			const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-				(x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-			if (valid) {
+			if (game.math.isOverIcon(x, y, cur)) {
 				const name = cur.name;
 				switch (name) {
-					case 'back' : navigationIcons.func_CallScreen(navigationIcons.level); break;
-					case 'menu' : navigationIcons.func_CallScreen(menuScreen); break;
-					case 'help' : navigationIcons.helpBtn(); break;
-					case 'language' : navigationIcons.func_CallScreen(langScreen); break;
-					case  'audio' :
+					case 'back': navigationIcons.func_CallState(navigationIcons.level); break;
+					case 'menu': navigationIcons.func_CallState('menu'); break;
+					case 'help': navigationIcons.help(); break;
+					case 'language': navigationIcons.func_CallState('lang'); break;
+					case 'audio':
 						if (audioStatus) {
 							audioStatus = false;
 							navigationIcons.icon_audio.curFrame = 1;
@@ -402,22 +411,25 @@ const navigationIcons = {
 						}
 						game.render.all();
 						break;
-					default: console.log("Game error: error in navigation icon")
+					default: console.log('Game error: error in navigation icon');
 				}
 			}
 		});
 	},
 
+	/**
+	 * Called by mouse move event
+	 * 
+	 * @param {number} x contains the mouse x coordinate
+	 * @param {number} y contains the mouse y coordinate
+	 */
 	func_onInputOver: function (x, y) {
 
 		let flag = false;
 
 		navigationIcons.iconsList.forEach(cur => {
 
-			const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-				(x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-			if (valid) {
+			if (game.math.isOverIcon(x, y, cur)) {
 
 				flag = true;
 
@@ -433,32 +445,36 @@ const navigationIcons = {
 		});
 
 		if (!flag) {
-			navigationIcons.left_text.name = "";
-			navigationIcons.right_text.name = "";
+			navigationIcons.left_text.name = '';
+			navigationIcons.right_text.name = '';
 		} else {
-			document.body.style.cursor = "pointer";
+			document.body.style.cursor = 'pointer';
 		}
 
 	}
 
 };
 
-// Send game information to database 
+/**
+ * Sends game information to database
+ *  
+ * @param {string} extraData player information for the current game
+ */
 const postScore = function (extraData) {
 
 	// Create some variables we need to send to our PHP file
-	const data = "s_ip=143.107.45.11"
-		+ "&s_name=" + playerName
-		+ "&s_lang=" + langString
+	const data = 's_ip=143.107.45.11'
+		+ '&s_name=' + playerName
+		+ '&s_lang=' + langString
 		+ extraData;
 
-	const url = "php/save.php";
+	const url = 'php/save.php';
 
 	const hr = new XMLHttpRequest();
 
-	hr.open("POST", url, true);
+	hr.open('POST', url, true);
 
-	hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+	hr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
 
 	hr.onreadystatechange = function () {
 		if (debugMode) console.log(hr);
@@ -467,11 +483,10 @@ const postScore = function (extraData) {
 		}
 	}
 
-	// Send the data to PHP now... and wait for response to update the status div
 	hr.send(data); // Actually execute the request
 
 	if (debugMode) {
-		console.log("processing...");
+		console.log('processing...');
 		console.log(data);
 	}
 

+ 72 - 83
js/map.js

@@ -1,41 +1,32 @@
-// MAP SCREEN: game map where character advances as he passes a level
-const mapScreen = {
-
-    preload: function () {
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
-        // NOTHING TO LOAD HERE 
-        mapScreen.create();
-
-    },
-
+/**
+ * MAP STATE: game map where character advances as he passes a level
+ * 
+ * @namespace
+ */
+const mapState = {
+
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         // Background color
         game.add.graphic.rect(0, 0, 900, 600, undefined, 0, colors.blueBckg, 1);
 
-        // map
+        // Map
         game.add.image(0, 40, 'bgmap');
 
         // Calls function that loads navigation icons
-        navigationIcons.func_addIcons(true, true, false, // left icons
-            false, false, // right icons
-            menuScreenCustom, false);
+        navigationIcons.func_addIcons(true, true, false, // Left icons
+            false, false, // Right icons
+            'customMenu', false);
 
         // Progress bar
         const percentText = 4 * 25;
 
         if (completedLevels == 4) game.add.graphic.rect(660, 10, completedLevels * 37.5, 35, undefined, 0, colors.intenseGreen, 0.5);
         else game.add.graphic.rect(660, 10, completedLevels * 37.5, 35, undefined, 0, colors.yellow, 0.9);
-        
+
         game.add.graphic.rect(661, 11, 149, 34, colors.blue, 3, undefined, 1);
         game.add.text(820, 38, percentText + '%', textStyles.h2_blue, 'left');
         game.add.text(650, 38, game.lang.difficulty + ' ' + gameDifficulty, textStyles.h2_blue, 'right');
@@ -46,15 +37,15 @@ const mapScreen = {
             y: [486, 422, 358, 294, 230, 166]
         };
 
-        if (gameTypeString == "squareOne") {
-            //Garage
+        if (gameTypeString == 'squareOne') {
+            // Garage
             game.add.image(this.points.x[0], this.points.y[0], 'garage', 0.4).anchor(0.5, 1);
-            //Farm
+            // Farm
             game.add.image(this.points.x[5], this.points.y[5], 'farm', 0.6).anchor(0.1, 0.7);
         } else {
-            //House
+            // House
             game.add.image(this.points.x[0], this.points.y[0], 'house', 0.7).anchor(0.7, 0.8);
-            //School
+            // School
             game.add.image(this.points.x[5], this.points.y[5], 'school', 0.35).anchor(0.2, 0.7);
         }
 
@@ -99,14 +90,14 @@ const mapScreen = {
         }
 
         // Game Character 
-        if (gameTypeString == "squareOne") {
+        if (gameTypeString == 'squareOne') {
 
             if (sublevelType == 'Plus') {
                 this.character = game.add.sprite(this.points.x[mapPosition], this.points.y[mapPosition], 'tractor', 0, 0.5);
-                this.character.animation = ["green_tractor", [0, 1, 2, 3, 4], 3];
+                this.character.animation = ['green_tractor', [0, 1, 2, 3, 4], 3];
             } else {
                 this.character = game.add.sprite(this.points.x[mapPosition], this.points.y[mapPosition], 'tractor', 10, 0.5);
-                this.character.animation = ["red_tractor", [10, 11, 12, 13, 14], 3];
+                this.character.animation = ['red_tractor', [10, 11, 12, 13, 14], 3];
             }
 
             this.character.rotate = -30; // 25 anticlock
@@ -114,14 +105,13 @@ const mapScreen = {
         } else {
 
             this.character = game.add.sprite(this.points.x[mapPosition], this.points.y[mapPosition], 'kid_run', 0, 0.4);
-            this.character.animation = ["kid", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3];
+            this.character.animation = ['kid', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3];
 
         }
 
         this.character.anchor(0.5, 1);
         game.animation.play(this.character.animation[0]);
 
-
         this.count = 0;
 
         const speed = 60;
@@ -132,15 +122,14 @@ const mapScreen = {
         self.speedX = (xB - xA) / speed;
         self.speedY = (yA - yB) / speed;
 
-        game.event.add("click", mapScreen.func_onInputDown);
-        game.event.add("mousemove", mapScreen.func_onInputOver);
-
-        game.render.all();
-
-        game.loop.start(this);
+        game.event.add('click', this.func_onInputDown);
+        game.event.add('mousemove', this.func_onInputOver);
 
     },
 
+    /**
+     * Game loop
+     */
     update: function () {
 
         let endUpdate = false;
@@ -149,12 +138,12 @@ const mapScreen = {
 
         if (self.count > 60) { // Wait 1 second before moving or staring a game
 
-            if (mapMove) { // move character on screen for 1 second
+            if (mapMove) { // Move character on screen for 1 second
                 self.character.x += self.speedX;
                 self.character.y -= self.speedY;
-                if (Math.ceil(self.character.x) >= self.points.x[mapPosition + 1]) { // reached next map position
+                if (Math.ceil(self.character.x) >= self.points.x[mapPosition + 1]) { // Reached next map position
                     mapMove = false;
-                    mapPosition++; //set new next position
+                    mapPosition++; // Set new next position
                 }
             }
 
@@ -178,53 +167,54 @@ const mapScreen = {
 
     /* EVENT HANDLER */
 
+    /**
+     * Called by mouse click event
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
     func_onInputDown: function (mouseEvent) {
-
         navigationIcons.func_onInputDown(mouseEvent.offsetX, mouseEvent.offsetY);
-
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
     func_onInputOver: function (mouseEvent) {
-
         navigationIcons.func_onInputOver(mouseEvent.offsetX, mouseEvent.offsetY);
-
     },
 
 
 
     /* GAME FUNCTIONS */
 
+    /**
+     * Calls game state
+     */
     func_loadGame: function () {
 
         if (audioStatus) game.audio.beepSound.play();
 
-        if (mapPosition <= 4) gameType.preload();
-        else endScreen.preload();
+        if (mapPosition <= 4) game.state.start('' + gameTypeString + '');
+        else game.state.start('end');
 
     },
 
 };
 
-// ENDING SCREEN: animation after a full level is completed
-const endScreen = {
-
-    preload: function () {
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
-        // NOTHING TO LOAD HERE
-        endScreen.create();
-
-    },
+/**
+ * ENDING STATE: animation after a full level is completed
+ * 
+ * @namespace
+ */
+const endState = {
 
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
         self.preAnimate = false;
         self.animate = true;
 
@@ -234,17 +224,17 @@ const endScreen = {
         // Background
         game.add.image(0, 0, 'bgimage');
 
-        //Clouds
+        // Clouds
         game.add.image(300, 100, 'cloud');
         game.add.image(660, 80, 'cloud');
         game.add.image(110, 85, 'cloud', 0.8);
 
-        //Floor
+        // Floor
         for (let i = 0; i < 9; i++) { game.add.image(i * 100, 501, 'floor'); }
 
         // Progress bar
-        game.add.graphic.rect(660, 10, 4 * 37.5, 35, undefined, 0, colors.intenseGreen, 0.5); // progress
-        game.add.graphic.rect(661, 11, 149, 34, colors.blue, 3, undefined, 1); // box
+        game.add.graphic.rect(660, 10, 4 * 37.5, 35, undefined, 0, colors.intenseGreen, 0.5); // Progress
+        game.add.graphic.rect(661, 11, 149, 34, colors.blue, 3, undefined, 1); // Box
         game.add.text(820, 38, '100%', textStyles.h2_blue, 'left');
         game.add.text(650, 38, game.lang.difficulty + ' ' + gameDifficulty, textStyles.h2_blue, 'right');
 
@@ -258,15 +248,15 @@ const endScreen = {
                 this.preAnimate = true;
                 this.animate = false;
 
-                //School
+                // School
                 game.add.image(600, 222, 'school', 0.7);
 
-                //kid
+                // Kid
                 this.character = game.add.sprite(0, -152, 'kid_run', 0, 0.7);
                 this.character.anchor(0.5, 0.5);
                 this.character.animation = ['move', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 3];
 
-                // balloon
+                // Balloon
                 this.balloon = game.add.image(0, -260, 'balloon');
                 this.balloon.anchor(0.5, 0.5);
 
@@ -277,10 +267,10 @@ const endScreen = {
 
             case 'squareTwo':
 
-                //School
+                // School
                 game.add.image(600, 222, 'school', 0.7);
 
-                //kid
+                // Kid
                 this.character = game.add.sprite(0, 460, 'kid_run', 6, 0.7);
                 this.character.anchor(0.5, 0.5);
                 this.character.animation = ['move', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 3];
@@ -289,10 +279,10 @@ const endScreen = {
 
             case 'squareOne':
 
-                //Farm
+                // Farm
                 game.add.image(650, 260, 'farm', 1.1);
 
-                //tractor
+                // Tractor
                 this.character = game.add.sprite(0, 490, 'tractor', 0, 0.7);
                 this.character.anchor(0.5, 0.5);
                 if (sublevelType == 'Plus') {
@@ -310,12 +300,11 @@ const endScreen = {
 
         game.add.image(30, 585, 'tree4', 0.85).anchor(0, 1);
 
-        game.render.all();
-
-        game.loop.start(this);
-
     },
 
+    /**
+     * Game loop
+     */
     update: function () {
 
         // Balloon falling
@@ -341,7 +330,7 @@ const endScreen = {
 
         }
 
-        // character running
+        // Character running
         if (self.animate) {
 
             if (self.character.x <= 700) {
@@ -353,7 +342,7 @@ const endScreen = {
                 animate = false;
                 completedLevels = 0;
                 game.animation.stop(self.character.animation[0]);
-                menuScreen.preload();
+                game.state.start('menu');
 
             }
 

+ 197 - 151
js/menu.js

@@ -1,42 +1,43 @@
-// MENU SCREEN: main menu - player can select the game he wants to play
-const menuScreen = {
-
+/**
+ * MAIN MENU STATE: main menu - player can select the game he wants to play 
+ * 
+ * @namespace
+ */
+const menuState = {
+
+    /**
+     * Preloads media for current state
+     */
     preload: function () {
 
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
         // LOADING MEDIA
         game.load.image(url.menu.image);
 
     },
 
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         // BACKGROUND
 
         game.add.graphic.rect(0, 0, 900, 600, undefined, 0, colors.blueBckg, 1);
 
-        for (let i = 0; i < defaultWidth / 100; i++) { 
-            game.add.image(i * 100, 501, 'floor'); 
+        for (let i = 0; i < defaultWidth / 100; i++) {
+            game.add.image(i * 100, 501, 'floor');
         }
 
         // LABELS
 
-        // h4_brown: Welcome, <player name>!
-        game.add.text(defaultWidth / 2, 40, game.lang.welcome + ", " + playerName + "!", textStyles.h4_brown);
+        // Overtitle: Welcome, <player name>!
+        game.add.text(defaultWidth / 2, 40, game.lang.welcome + ', ' + playerName + '!', textStyles.h4_brown);
 
         // Title : Select a game
         game.add.text(defaultWidth / 2, 80, game.lang.menu_title, textStyles.h1_green);
 
         // Subtitle : <game mode> 
-        this.lbl_game = game.add.text(defaultWidth / 2, 110, "", textStyles.h2_blue_2);
+        this.lbl_game = game.add.text(defaultWidth / 2, 110, '', textStyles.h2_blue_2);
 
         // NAVIGATION ICONS
 
@@ -49,10 +50,10 @@ const menuScreen = {
         // -------------------- GAME ICONS 
         this.menuIcons = [];
 
-        const offset = defaultWidth / (info.gameType.length + 1);    
+        const offset = defaultWidth / (info.gameType.length + 1);
 
         for (let i = 0, x = offset; i < info.gameType.length; i++, x += offset) {
-            
+
             const icon = game.add.image(x, defaultHeight / 2 - 70, info.gameTypeUrl[i], 1);
             icon.anchor(0.5, 0.5);
 
@@ -65,16 +66,79 @@ const menuScreen = {
 
         // EVENTS
 
-        game.event.add("click", this.func_onInputDown);
-        game.event.add("mousemove", this.func_onInputOver);
+        game.event.add('click', this.func_onInputDown);
+        game.event.add('mousemove', this.func_onInputOver);
 
-        game.render.all();
+    },
 
+
+
+    /* EVENTS */
+
+    /**
+     * Called by mouse click event
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
+    func_onInputDown: function (mouseEvent) {
+        const x = mouseEvent.offsetX, y = mouseEvent.offsetY;
+
+        // Check menu icons
+        for (let i in self.menuIcons) {
+            // If mouse is within the bounds of an icon
+            if (game.math.isOverIcon(x, y, self.menuIcons[i])) {
+                // Click first valid icon
+                self.func_load(self.menuIcons[i]);
+                break;
+            }
+        }
+
+        // Check navigation icons
+        navigationIcons.func_onInputDown(x, y);
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
+    func_onInputOver: function (mouseEvent) {
+        const x = mouseEvent.offsetX, y = mouseEvent.offsetY;
+        let flag = false;
+
+        // Check menu icons
+        self.menuIcons.forEach(cur => {
+            if (game.math.isOverIcon(x, y, cur)) {
+                cur.scale = 1.08;
+                self.func_showTitle(cur);
+                flag = true;
+            } else {
+                cur.scale = 1;
+            }
+        });
+
+        if (flag) {
+            document.body.style.cursor = 'pointer';
+        } else {
+            document.body.style.cursor = 'auto';
+        }
+
+        // Check navigation icons
+        navigationIcons.func_onInputOver(x, y);
+
+        game.render.all();
+    },
+
+
+
     /* GAME FUNCTIONS */
 
-    func_click: function (icon) {
+    /**
+     * Saves info from selected game and goes to next state
+     * 
+     * @param {object} icon clicked icon
+     */
+    func_load: function (icon) {
 
         if (audioStatus) game.audio.beepSound.play();
 
@@ -84,110 +148,72 @@ const menuScreen = {
             case 'squareOne': gameType = squareOne; break;
             case 'squareTwo': gameType = squareTwo; break;
             case 'circleOne': gameType = circleOne; break;
-            default: console.error("Game error: the name of the game is not valid");
+            default: console.error('Game error: the name of the game is not valid');
         }
 
         self.menuIcons = self.lbl_game.name;
 
-        menuScreenCustom.preload();
+        game.state.start('customMenu');
 
     },
 
+    /**
+     * Display the name of the game on screen
+     * 
+     * @param {object} icon icon for the game
+     */
     func_showTitle: function (icon) {
 
         let title;
 
-        switch (icon.gameShape){
-            case 'Circle' : title = game.lang.circle_name; break;
-            case 'Square' : title = game.lang.square_name; break;
+        switch (icon.gameShape) {
+            case 'circle': title = game.lang.circle_name; break;
+            case 'square': title = game.lang.square_name; break;
         }
 
         const type = icon.gameType.substring(icon.gameType.length - 3);
 
-        switch (type){
-            case 'One' : title += ' I'; break;
-            case 'Two' : title += ' II'; break;
+        switch (type) {
+            case 'One': title += ' I'; break;
+            case 'Two': title += ' II'; break;
         }
 
         self.lbl_game.name = title;
-        
-    },
 
-    func_clearTitle: function () { 
-        self.lbl_game.name = ''; 
     },
 
-    /* EVENTS */
-
-    func_onInputDown: function (mouseEvent) {
-        const x = mouseEvent.offsetX, y = mouseEvent.offsetY;
-
-        // check menu icons
-        for (let i in self.menuIcons) {
-            // if mouse is within the bounds of an icon
-            if ( game.math.isOverIcon(x, y, self.menuIcons[i]) ) {
-                // click first valid icon
-                self.func_click(self.menuIcons[i]);
-                break;
-            }
-        }
-
-        // check navigation icons
-        navigationIcons.func_onInputDown(x, y);
+    /**
+     * Remove the name of the game from screen
+     */
+    func_clearTitle: function () {
+        self.lbl_game.name = '';
     },
 
-    func_onInputOver: function (mouseEvent) {
-        const x = mouseEvent.offsetX, y = mouseEvent.offsetY;
-        let flag = false;
-
-        // check menu icons
-        self.menuIcons.forEach( cur => {
-            if ( game.math.isOverIcon(x, y, cur) ) {
-                cur.scale = 1.08;
-                self.func_showTitle(cur);
-                flag = true;
-            } else {
-                cur.scale = 1;
-            }
-        });
-
-        if (flag) { 
-            document.body.style.cursor = "pointer";
-        } else {
-            document.body.style.cursor = "auto";
-           // menuScreen.func_clearTitle();
-        }
-
-        // check navigation icons
-        navigationIcons.func_onInputOver(x, y);
-
-        game.render.all();
-    },
-    
 };
 
-// IN MENU SCREEN: player can select level, sublevel and difficulty
-const menuScreenCustom = {
+/**
+ * SECUNDARY MENU STATE: player can select level, sublevel and difficulty
+ * 
+ * @namespace
+ */
+const customMenuState = {
 
+    /**
+     * Preloads media for current state
+     */
     preload: function () {
 
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
         // LOADING MEDIA
         game.load.sprite(url[gameTypeString].sprite);
         game.load.image(url[gameTypeString].image);
 
     },
 
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         let x, y, width, height, offsetH, offsetW;
         const iconScale = 0.5;
 
@@ -196,22 +222,22 @@ const menuScreenCustom = {
 
         // Floor
         for (let i = 0; i < defaultWidth / 100; i++) { game.add.image(i * 100, 501, 'floor'); }
-        
+
         // LABELS
 
         // Add Title : Select a game
         game.add.text(defaultWidth / 2, 80, game.lang.custom_game, textStyles.h1_green);
 
         // Selected game
-        game.add.text(defaultWidth / 2, 40, menuScreen.menuIcons, textStyles.h4_brown);
+        game.add.text(defaultWidth / 2, 40, menuState.menuIcons, textStyles.h4_brown);
 
         // Loads animation icons
         navigationIcons.func_addIcons(
             true, false, false,
             true, true,
-            menuScreen, false);
+            'menu', false);
+
 
-        
         this.menuIcons = [];
 
         offsetW = 600 / 6;
@@ -228,27 +254,27 @@ const menuScreenCustom = {
         game.add.text(x + 5 * offsetW, y, game.lang.difficulty, textStyles.h2_blue_2);
 
         // Horizontal line
-        game.add.graphic.rect(x , y + 10, 600, width, undefined, 0, colors.blueMenuLine).anchor(0,0.5);
+        game.add.graphic.rect(x, y + 10, 600, width, undefined, 0, colors.blueMenuLine).anchor(0, 0.5);
 
         // Vertical line
-        game.add.graphic.rect(x + 2 * offsetW, y - 25, width, height, undefined, 0, colors.blueMenuLine).anchor(0.5,0);
-        game.add.graphic.rect(x + 4 * offsetW, y - 25, width, height, undefined, 0, colors.blueMenuLine).anchor(0.5,0);
+        game.add.graphic.rect(x + 2 * offsetW, y - 25, width, height, undefined, 0, colors.blueMenuLine).anchor(0.5, 0);
+        game.add.graphic.rect(x + 4 * offsetW, y - 25, width, height, undefined, 0, colors.blueMenuLine).anchor(0.5, 0);
 
         // --------------------------- TURN ON/OFF FRACTION LABELS
 
         if (gameTypeString == 'squareTwo') {
-            
+
             sublevelLabel.alpha = 0.3;
 
         } else {
 
             // Horizontal line
-            game.add.graphic.rect(x + 4 * offsetW, y + 136, 200, width, undefined, 0, colors.blueMenuLine).anchor(0,0.5);
+            game.add.graphic.rect(x + 4 * offsetW, y + 136, 200, width, undefined, 0, colors.blueMenuLine).anchor(0, 0.5);
 
             // Label 'Show Fractions'
             game.add.text(x + 5 * offsetW, y + 102, game.lang.show, textStyles.h4_blue_2);
             game.add.text(x + 5 * offsetW, y + 102 + 24, game.lang.title, textStyles.h2_blue_2);
-            
+
             const frame = (fractionLabel) ? 1 : 0;
 
             // Selection box
@@ -258,7 +284,7 @@ const menuScreenCustom = {
             selectionBox.iconType = 'selectionBox';
             selectionBox.originalScale = 0.1;
             this.menuIcons.push(selectionBox);
-        } 
+        }
 
         // ---------------------------- LEVEL ICONS
 
@@ -273,7 +299,7 @@ const menuScreenCustom = {
             icon.anchor(0.5, 0.5);
 
             icon.levelType = info[gameTypeString].levelType[i];
-            icon.iconType = "level";
+            icon.iconType = 'level';
             icon.originalScale = iconScale;
             if (i == 0) {
                 levelType = icon.levelType;
@@ -283,7 +309,7 @@ const menuScreenCustom = {
             this.menuIcons.push(icon);
 
         }
-            
+
         // ---------------------------- SUBLEVEL ICONS
 
         offsetH = this.func_getOffset(height, info[gameTypeString].sublevelType.length);
@@ -295,15 +321,15 @@ const menuScreenCustom = {
         let aux = [];
         aux['squareOne'] = [
             ['sublevel_right', 'Plus'],
-            ['sublevel_left', 'Minus']  
+            ['sublevel_left', 'Minus']
         ];
         aux['circleOne'] = [
-            ['sublevel_right', 'Plus'], 
-            ['sublevel_left', 'Minus'], 
+            ['sublevel_right', 'Plus'],
+            ['sublevel_left', 'Minus'],
             ['sublevel_mixed', 'Mixed']
         ];
         aux['squareTwo'] = [
-            //['sublevel_top', 'A'],
+            // ['sublevel_top', 'A'],
             ['sublevel_bottom', 'B'],
             ['sublevel_top', 'C'],
         ];
@@ -315,11 +341,11 @@ const menuScreenCustom = {
             icon.alpha = 1;
 
             icon.sublevelType = aux[gameTypeString][i][1];
-            icon.iconType = "sublevel";
+            icon.iconType = 'sublevel';
             icon.originalScale = iconScale;
 
-            if ( i == 0 ) {
-                sublevelType = icon.sublevelType;  
+            if (i == 0) {
+                sublevelType = icon.sublevelType;
                 icon.shadow = true;
             }
 
@@ -328,7 +354,7 @@ const menuScreenCustom = {
         }
 
         // --------------------------- DIFFICULTY ICONS
-                
+
         x = (gameTypeString == 'squareOne') ? 600 : 570;
         y = 235;
 
@@ -339,7 +365,7 @@ const menuScreenCustom = {
 
             // Difficulty menuIcons
             const icon = game.add.graphic.rect(curX, y, 30, 30, undefined, 0, colors.green, 1);
-            icon.anchor(0.5,0.5);
+            icon.anchor(0.5, 0.5);
             icon.difficulty = i + 1;
             icon.iconType = 'difficulty';
             icon.originalScale = 1;
@@ -361,7 +387,7 @@ const menuScreenCustom = {
         y = defaultHeight - 110;
 
         const enterIcon = game.add.image(x, y, 'bush');
-        enterIcon.anchor(0.5,0.5);
+        enterIcon.anchor(0.5, 0.5);
         enterIcon.iconType = 'enter';
         enterIcon.originalScale = 0.9;
 
@@ -371,25 +397,28 @@ const menuScreenCustom = {
 
         // EVENTS
 
-        game.render.all();
-
-        game.event.add("click", this.func_onInputDown);
-        game.event.add("mousemove", this.func_onInputOver);
+        game.event.add('click', this.func_onInputDown);
+        game.event.add('mousemove', this.func_onInputOver);
 
     },
 
     /* GAME FUNCTIONS */
 
+    /**
+     * Saves information selected by the player 
+     * 
+     * @param {object} icon selected icon
+     */
     func_load: function (icon) {
 
         if (audioStatus) game.audio.beepSound.play();
 
         const type = icon.iconType;
         switch (type) {
-            case 'level' : levelType = icon.levelType; break;
-            case 'sublevel' : sublevelType = icon.sublevelType; break;
-            case 'difficulty' : gameDifficulty = icon.difficulty; break;
-            case 'selectionBox' :
+            case 'level': levelType = icon.levelType; break;
+            case 'sublevel': sublevelType = icon.sublevelType; break;
+            case 'difficulty': gameDifficulty = icon.difficulty; break;
+            case 'selectionBox':
                 if (icon.curFrame == 0) {
                     icon.curFrame = 1;
                     fractionLabel = true;
@@ -399,28 +428,40 @@ const menuScreenCustom = {
                 }
                 game.render.all();
                 break;
-            case 'enter' :    
-                if (debugMode) console.log("Game State: " + gameTypeString + ", " + levelType);
+            case 'enter':
+                if (debugMode) console.log('Game State: ' + gameTypeString + ', ' + levelType);
                 mapPosition = 0;      // Map position
                 mapMove = true;       // Move no next point
                 completedLevels = 0;  // Reset the game progress when entering a new level
-                mapScreen.preload();
+                game.state.start('map');
                 break;
         }
 
     },
 
-    func_getOffset : function (width, numberOfIcons) {
+    /**
+     * Calculate spacing for icons on the menu screen
+     * 
+     * @param {number} width width of the available part of the screen
+     * @param {number} numberOfIcons number or icons to be put on the screen
+     * @returns {number}
+     */
+    func_getOffset: function (width, numberOfIcons) {
         return width / (numberOfIcons + 1);
-    },  
+    },
 
     /* EVENTS */
 
+    /**
+     * Called by mouse click event
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
     func_onInputDown: function (mouseEvent) {
         const x = mouseEvent.offsetX, y = mouseEvent.offsetY;
         let overIcon;
 
-        // check if clicked on an icon
+        // Check if clicked on an icon
         for (let i in self.menuIcons) {
             if (game.math.isOverIcon(x, y, self.menuIcons[i])) {
                 overIcon = i;
@@ -428,13 +469,13 @@ const menuScreenCustom = {
             }
         }
 
-        // update gui
-        if (overIcon) { 
+        // Update gui
+        if (overIcon) {
 
-            document.body.style.cursor = "pointer";
-                
-            self.menuIcons.forEach( cur => {
-                if ( cur.iconType == self.menuIcons[overIcon].iconType ) {
+            document.body.style.cursor = 'pointer';
+
+            self.menuIcons.forEach(cur => {
+                if (cur.iconType == self.menuIcons[overIcon].iconType) {
                     if (cur == self.menuIcons[overIcon]) {
                         cur.shadow = true;
                     } else {
@@ -442,10 +483,10 @@ const menuScreenCustom = {
                     }
                 }
             });
-        
+
             self.func_load(self.menuIcons[overIcon]);
 
-        } else document.body.style.cursor = "auto";
+        } else document.body.style.cursor = 'auto';
 
         navigationIcons.func_onInputDown(x, y);
 
@@ -453,43 +494,48 @@ const menuScreenCustom = {
 
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
     func_onInputOver: function (mouseEvent) {
         const x = mouseEvent.offsetX, y = mouseEvent.offsetY;
         let overIcon;
 
-        // check if pointer is over an icon
+        // Check if pointer is over an icon
         for (let i in self.menuIcons) {
             if (game.math.isOverIcon(x, y, self.menuIcons[i])) {
                 overIcon = i;
-                break; 
+                break;
             }
         }
 
-        // update gui
-        if (overIcon) { 
-            document.body.style.cursor = "pointer";
-            
-            self.menuIcons.forEach( cur => {
-                if ( cur.iconType == self.menuIcons[overIcon].iconType ) {
-                    if (cur == self.menuIcons[overIcon] ) {
+        // Update gui
+        if (overIcon) {
+            document.body.style.cursor = 'pointer';
+
+            self.menuIcons.forEach(cur => {
+                if (cur.iconType == self.menuIcons[overIcon].iconType) {
+                    if (cur == self.menuIcons[overIcon]) {
                         cur.scale = cur.originalScale * 1.1;
                     } else {
-                        cur.scale = cur.originalScale; 
+                        cur.scale = cur.originalScale;
                     }
                 }
             });
         } else {
-            self.menuIcons.forEach( cur => {
-                cur.scale = cur.originalScale; 
+            self.menuIcons.forEach(cur => {
+                cur.scale = cur.originalScale;
             });
-            document.body.style.cursor = "auto";
+            document.body.style.cursor = 'auto';
         }
 
-        // check navigation icons
+        // Check navigation icons
         navigationIcons.func_onInputOver(x, y);
 
         game.render.all();
-        
+
     },
 
 }

+ 113 - 115
js/preMenu.js

@@ -1,17 +1,15 @@
-// Only called once
-const boot = {
-
+/**
+ * BOOT STATE: First state called. Loads main media
+ * 
+ * @namespace
+ */
+const bootState = {
+
+    /**
+     * Preloads media for current state
+     */
     preload: function () {
 
-        info.start();
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
         // LOADING MEDIA
         game.load.audio(url.boot.audio);
         game.load.image(url.boot.image);
@@ -19,43 +17,38 @@ const boot = {
 
     },
 
+    /**
+     * Main code
+     */
     create: function () {
         // Calls first screen seen by the player
-        langScreen.preload();
+        game.state.start('lang');
+
     }
 
 };
 
 
 
-// LANGUAGE SCREEN: the player can choose a preferred language for the game text to be displayed
-const langScreen = {
-
-    preload: function () {
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
-        // NOTHING TO LOAD HERE
-        langScreen.create();
-
-    },
+/**
+ * LANGUAGE STATE: the player can choose a preferred language for the text to be displayed in the game
+ * 
+ * @namespace
+ */
+const langState = {
 
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         // Background color
         game.add.graphic.rect(0, 0, 900, 600, colors.white, 0, colors.blueBckg, 1);
 
         // Parameters for the elements on the screen
-        langScreen.listOfFlags = [];
+        this.listOfFlags = [];
 
-        langScreen.langs = {
+        this.langs = {
             text: ['FRAÇÕES  ', 'FRAZIONI  ', 'FRACTIONS  ', 'FRACCIONES  ', 'FRACTIONS  '], // Language names
             flag: ['flag_BR', 'flag_IT', 'flag_US', 'flag_PE', 'flag_FR'], // Icon names
             lang: ['pt_BR', 'it_IT', 'en_US', 'es_PE', 'fr_FR'], // Parameters sent for language object
@@ -76,10 +69,8 @@ const langScreen = {
             this.listOfFlags.push(flag);
         }
 
-        game.event.add("click", this.func_onInputDown);
-        game.event.add("mousemove", this.func_onInputOver);
-
-        game.render.all();
+        game.event.add('click', this.func_onInputDown);
+        game.event.add('mousemove', this.func_onInputOver);
 
     },
 
@@ -87,38 +78,42 @@ const langScreen = {
 
     /* EVENT HANDLER*/
 
+    /**
+     * Called by mouse click event
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
     func_onInputDown: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
         const y = mouseEvent.offsetY;
 
-        langScreen.listOfFlags.forEach(cur => {
-
-            const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-            if (valid) {
-                for (let i in langScreen.langs.flag) {
-                    if (langScreen.langs.flag[i] == cur.name) {
-                        langScreen.func_setLang(self.langs.lang[i]);
+        self.listOfFlags.forEach(cur => {
+            if (game.math.isOverIcon(x, y, cur)) {
+                for (let i in self.langs.flag) {
+                    if (self.langs.flag[i] == cur.name) {
+                        self.func_setLang(self.langs.lang[i]);
+                        break;
                     }
                 }
             }
         });
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
     func_onInputOver: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
         const y = mouseEvent.offsetY;
         let flag = false;
 
-        langScreen.listOfFlags.forEach(cur => {
+        self.listOfFlags.forEach(cur => {
 
-            const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-            if (valid) {
+            if (game.math.isOverIcon(x, y, cur)) {
                 flag = true;
                 cur.scale = cur.scale = 1.05;
             } else {
@@ -126,8 +121,8 @@ const langScreen = {
             }
         });
 
-        if (flag) document.body.style.cursor = "pointer";
-        else document.body.style.cursor = "auto";
+        if (flag) document.body.style.cursor = 'pointer';
+        else document.body.style.cursor = 'auto';
 
         game.render.all();
 
@@ -137,44 +132,52 @@ const langScreen = {
 
     /* GAME FUNCTIONS */
 
-    // Calls loading screen while loads language
+    /**
+     * Calls state that loads selected language
+     * 
+     * @param {string} selectedLang language selected by player
+     */
     func_setLang: function (selectedLang) {
         // Saves language name e.g 'pt_BR'
         langString = selectedLang;
         // Calls loading screen
-        loadLang.preload();
+        game.state.start('loadLang');
     }
 
 };
 
 
 
-// Loads selected language to be able to translate the game text
-const loadLang = {
+/**
+ * LOADING LANGUAGE STATE: Loads selected language to be able to translate the game text 
+ * 
+ *  @namespace
+ */
+const loadLangState = {
 
+    /**
+     * Preloads media for current state
+     */
     preload: function () {
 
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
         // LOADING MEDIA : selected language
         game.load.lang('assets/lang/' + langString);
 
     },
 
+    /**
+     * Main code
+     */
     create: function () {
 
-        if (debugMode) console.log("Language: " + langString);
+        if (debugMode) console.log('Language: ' + langString);
 
         // Make sure to only ask for player name on the first time oppening the game
         if (this.firstTime == undefined) {
             this.firstTime = false;
-            nameScreen.preload(); // first time opening ifractions ('language' >> 'name' >> 'menu')
+            game.state.start('name'); // First time opening ifractions ('language' >> 'name' >> 'menu')
         } else {
-            menuScreen.preload(); // if changing language during the game ('language' >>>> 'menu')         
+            game.state.start('menu'); // If changing language during the game ('language' >> >> 'menu')         
         }
 
     }
@@ -183,27 +186,18 @@ const loadLang = {
 
 
 
-// NAME SCREEN: asks for player's name 
-const nameScreen = {
-
-    preload: function () {
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
-        // NOTHING TO LOAD HERE
-        nameScreen.create();
-
-    },
+/**
+ * NAME STATE: asks for player's name
+ * 
+ * @namespace
+ */
+const nameState = {
 
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         // Background color
         game.add.graphic.rect(0, 0, 900, 600, colors.white, 0, colors.blueBckg, 1);
 
@@ -211,7 +205,7 @@ const nameScreen = {
 
         game.add.text(defaultWidth / 2, defaultHeight / 2 - 100, game.lang.insert_name, textStyles.h1_green);
 
-        this.warningEmptyName = game.add.text(defaultWidth / 2, defaultHeight / 2 - 70, "", textStyles.h4_brown);
+        this.warningEmptyName = game.add.text(defaultWidth / 2, defaultHeight / 2 - 70, '', textStyles.h4_brown);
 
         // Set 'ok' button that gets player's information
         this.okBtn = game.add.graphic.rect(defaultWidth / 2 - 84, defaultHeight / 2 + 70, 168, 60, undefined, 0, colors.gray, 0.6);
@@ -220,23 +214,19 @@ const nameScreen = {
         game.add.text(defaultWidth / 2 + 1, defaultHeight / 2 + 112, game.lang.ready, textStyles.h1_white);
 
         // Makes text field visible
-        document.getElementById("textbox").style.visibility = "visible";
+        document.getElementById('textbox').style.visibility = 'visible';
 
-        // Does the same as the button click when the player presses "enter"
-        document.getElementById("textbox-content").addEventListener('keypress', function (e) {
+        // Does the same as the button click when the player presses 'enter'
+        document.getElementById('textbox-content').addEventListener('keypress', function (e) {
             const keycode = e.key || e.code;
             if (keycode == 'Enter') {
-
                 if (self.func_checkEmptyName()) self.func_saveName();
-
-                game.render.all(); // can show empty name
+                game.render.all(); // Can show empty name
             }
         });
 
-        game.event.add("click", this.func_onInputDown);
-        game.event.add("mousemove", this.func_onInputOver);
-
-        game.render.all();
+        game.event.add('click', this.func_onInputDown);
+        game.event.add('mousemove', this.func_onInputOver);
 
     },
 
@@ -244,6 +234,11 @@ const nameScreen = {
 
     /* EVENT HANDLER*/
 
+    /**
+     * Called by mouse click event
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
     func_onInputDown: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
@@ -251,22 +246,20 @@ const nameScreen = {
 
         const cur = self.okBtn;
 
-        const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-            (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-        if (valid) {
-
+        if (game.math.isOverIcon(x, y, cur)) {
             if (self.func_checkEmptyName()) {
-
                 self.func_saveName();
-
             }
-
         }
 
         game.render.all();
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
     func_onInputOver: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
@@ -274,14 +267,11 @@ const nameScreen = {
 
         const cur = self.okBtn;
 
-        const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-            (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-        if (valid) {
-            document.body.style.cursor = "pointer";
+        if (game.math.isOverIcon(x, y, cur)) {
+            document.body.style.cursor = 'pointer';
             cur.alpha = 0.4;
         } else {
-            document.body.style.cursor = "auto";
+            document.body.style.cursor = 'auto';
             cur.alpha = 0.6;
         }
 
@@ -293,10 +283,15 @@ const nameScreen = {
 
     /* GAME FUNCTIONS */
 
+    /**
+     * Checks if player entered name in text box
+     * 
+     * @returns {boolean}
+     */
     func_checkEmptyName: function () {
 
         // If text field is empty displays error message
-        if (document.getElementById("textbox-content").value == "") {
+        if (document.getElementById('textbox-content').value == '') {
             self.warningEmptyName.name = game.lang.empty_name;
             return false;
         }
@@ -304,21 +299,24 @@ const nameScreen = {
 
     },
 
+    /**
+     * Saves player name and calls next state
+     */
     func_saveName: function () {
 
         // Saves player's input in global variable 'playerName'
-        playerName = document.getElementById("textbox-content").value;
+        playerName = document.getElementById('textbox-content').value;
 
         // Hides and clears text field
-        document.getElementById("textbox").style.visibility = "hidden";
-        document.getElementById("textbox-content").value = "";
+        document.getElementById('textbox').style.visibility = 'hidden';
+        document.getElementById('textbox-content').value = '';
 
         if (audioStatus) game.audio.beepSound.play();
 
-        if (debugMode) console.log("Username: " + playerName);
+        if (debugMode) console.log('Username: ' + playerName);
 
         // Calls 'menu' state
-        menuScreen.preload();
+        game.state.start('menu');
 
     }
 

+ 138 - 133
js/squareOne.js

@@ -1,50 +1,40 @@
-/*
-    GAME LEVELS - SQUARE I & II: tractor level
-    
-    Name of game state : squareOne 
-    Shape : square
-    Character : tractor
-    Theme : farm
-    Concept : Player associates 'blocks carried by the tractor' and 'floor spaces to be filled by them'
-    Represent fractions as : blocks
-
-    # of different difficulties for each level : 3
-
-    Levels can be : 'A' or 'B' (in variable 'levelType')
-
-        A : Player can select # of 'floor blocks' (hole in the ground)
-            Selects size of hole to be made in the ground (to fill with the blocks in front of the truck)
-        B : Player can select # of 'stacked blocks' (in front of the truck)
-            Selects number of blocks in front of the truck (to fill the hole on the ground)
-    
-    Sublevels can be : 'Plus' or 'Minus' (in variable 'sublevelType')
-    
-        Plus : addition of fractions
-            Represented by : tractor going to the right (floor positions 0..8)
-        Minus : subtraction of fractions
-            Represented by: tractor going to the left (floor positions 8..0)
-*/
-
+/**
+ *  GAME STATE
+ * 
+ *  LEVELS - SQUARE I & II: tractor level
+ * 
+ *  Name of game state : squareOne 
+ *  Shape : square
+ *  Character : tractor
+ *  Theme : farm
+ *  Concept : Player associates 'blocks carried by the tractor' and 'floor spaces to be filled by them'
+ *  Represent fractions as : blocks
+ * 
+ *  # of different difficulties for each level : 3
+ * 
+ *  Levels can be : 'A' or 'B' (in variable 'levelType')
+ * 
+ *      A : Player can select # of 'floor blocks' (hole in the ground)
+ *          Selects size of hole to be made in the ground (to fill with the blocks in front of the truck)
+ *      B : Player can select # of 'stacked blocks' (in front of the truck)
+ *          Selects number of blocks in front of the truck (to fill the hole on the ground)
+ * 
+ *  Sublevels can be : 'Plus' or 'Minus' (in variable 'sublevelType')
+ * 
+ *      Plus : addition of fractions
+ *          Represented by : tractor going to the right (floor positions 0..8
+ *      Minus : subtraction of fractions
+ *          Represented by: tractor going to the left (floor positions 8..0)
+ * 
+ * @namespace
+ */
 const squareOne = {
 
-    preload: function () {
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
-        // NOTHING TO LOAD HERE
-        squareOne.create();
-
-    },
-
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         // CONTROL VARIABLES
 
         this.checkAnswer = false;   // When true allows game to run 'check answer' code in update
@@ -54,10 +44,10 @@ const squareOne = {
         this.result = false;        // Checks player 'answer' 
         this.count = 0;             // An 'x' position counter used in the tractor animation        
 
-        this.divisorsList = "";     // Hold the divisors for each fraction on stacked blocks (created for func_postScore)
+        this.divisorsList = '';     // Hold the divisors for each fraction on stacked blocks (created for func_postScore)
 
         this.DIREC_LEVEL = (sublevelType == 'Minus') ? -1 : 1;    // Will be multiplied to values to easily change tractor direction when needed
-        this.animationSpeed = 2 * this.DIREC_LEVEL;   // x distance in which the tractor moves in each iteration of the animation
+        this.animationSpeed = 2 * this.DIREC_LEVEL;   // X distance in which the tractor moves in each iteration of the animation
 
         // GAME VARIABLES
 
@@ -83,9 +73,9 @@ const squareOne = {
 
         // Calls function that loads navigation icons
         navigationIcons.func_addIcons(
-            true, true, true,   // left icons
-            true, false,        // right icons
-            menuScreenCustom, this.func_viewHelp
+            true, true, true,   // Left icons
+            true, false,        // Right icons
+            'customMenu', this.func_viewHelp
         );
 
         // TRACTOR 
@@ -94,10 +84,10 @@ const squareOne = {
 
         if (sublevelType == 'Plus') {
             this.tractor.anchor(1, 0.5);
-            this.tractor.animation = ["move", [0, 1, 2, 3, 4], 4];
+            this.tractor.animation = ['move', [0, 1, 2, 3, 4], 4];
         } else {
             this.tractor.anchor(0, 0.5);
-            this.tractor.animation = ["move", [5, 6, 7, 8, 9], 4];
+            this.tractor.animation = ['move', [5, 6, 7, 8, 9], 4];
             this.tractor.curFrame = 5;
         }
 
@@ -110,7 +100,7 @@ const squareOne = {
 
             index: undefined, // (levelType 'B') index of 'stacked' block selected by player
 
-            // control variables for animation
+            // Control variables for animation
             curIndex: 0, // (needs to be 0)
             curBlockEnd: undefined,
 
@@ -127,21 +117,21 @@ const squareOne = {
 
             index: undefined, // (levelType 'A') index of 'floor' block selected by player
 
-            // control variables for animation
+            // Control variables for animation
             curIndex: -1, // (needs to be -1)
 
             // Correct values
             correctIndex: undefined, // (levelType 'A') index of the CORRECT 'floor' block
 
             correctX: undefined,  // 'x' coordinate of CORRECT 'floor' block
-            correctXA: undefined, // temporary variable 
-            correctXB: undefined, // temporary variable
+            correctXA: undefined, // Temporary variable 
+            correctXB: undefined, // Temporary variable
 
         };
 
         // CREATING STACKED BLOCKS
 
-        const restart = this.func_createStckBlocks();
+        this.restart = this.func_createStckBlocks();
 
         // CREATING FLOOR BLOCKS
 
@@ -150,34 +140,31 @@ const squareOne = {
 
         // SELECTION ARROW
 
-        if (levelType == "A") {
+        if (levelType == 'A') {
             this.arrow = game.add.image(this.startX + this.defaultBlockWidth * this.DIREC_LEVEL, 480, 'arrow_down');
             this.arrow.anchor(0.5, 0.5);
             this.arrow.alpha = 0.5;
         }
 
-        // help pointer
+        // Help pointer
         this.help = game.add.image(0, 0, 'help_pointer', 0.5);
         this.help.anchor(0.5, 0);
         this.help.alpha = 0;
 
 
 
-        if (restart) {
-            squareOne.preload();
-        } else {
-            game.render.all();
-
+        if (!this.restart) {
             game.timer.start(); // Set a timer for the current level (used in func_postScore)
 
-            game.event.add("click", squareOne.func_onInputDown);
-            game.event.add("mousemove", squareOne.func_onInputOver);
-
-            game.loop.start(this);
+            game.event.add('click', this.func_onInputDown);
+            game.event.add('mousemove', this.func_onInputOver);
         }
 
     },
 
+    /**
+     * Game loop
+     */
     update: function () {
 
         // AFTER PLAYER SELECTION
@@ -201,10 +188,10 @@ const squareOne = {
 
             // MANAGE BLOCKS AND FLOOR GAPS
 
-            // if block is 1/n (not 1/1) there's an extra block space to go through before the start of next block
+            // If block is 1/n (not 1/1) there's an extra block space to go through before the start of next block
             const restOfCurBlock = (self.defaultBlockWidth - stck.blocks[stck.curIndex].width) * self.DIREC_LEVEL;
 
-            // check if block falls
+            // Check if block falls
             if ((sublevelType == 'Plus' && stck.blocks[0].x >= (stck.curBlockEnd + restOfCurBlock)) ||
                 (sublevelType == 'Minus' && stck.blocks[0].x <= (stck.curBlockEnd + restOfCurBlock))) {
 
@@ -212,8 +199,8 @@ const squareOne = {
 
                 const curEnd = stck.blocks[0].x + stck.blocks[stck.curIndex].width * self.DIREC_LEVEL;
 
-                // if current index is (A) last stacked index (correct index - fixed)
-                // if current index is (B) selected stacked index
+                // If current index is (A) last stacked index (correct index - fixed)
+                // If current index is (B) selected stacked index
                 if (stck.curIndex == stck.index) {
 
                     // floor.index : (A) selected floor index
@@ -228,17 +215,17 @@ const squareOne = {
 
                 } else {
 
-                    // update to next block end
+                    // Update to next block end
                     stck.curBlockEnd += stck.blocks[stck.curIndex + 1].width * self.DIREC_LEVEL;
 
                 }
 
-                // fill floor gap
+                // Fill floor gap
                 if (lowerBlock) {
 
-                    // until (A) selected floor index
-                    // until (B) last floor index (correct index - fixed)
-                    // updates floor index to be equivalent to stacked index (and change alpha so floor appears to be filled)
+                    // Until (A) selected floor index
+                    // Until (B) last floor index (correct index - fixed)
+                    // Updates floor index to be equivalent to stacked index (and change alpha so floor appears to be filled)
                     for (let i = 0; i <= floor.index; i++) {
 
                         if ((sublevelType == 'Plus' && floor.blocks[i].x < curEnd) || (sublevelType == 'Minus' && floor.blocks[i].x > curEnd)) {
@@ -248,7 +235,7 @@ const squareOne = {
 
                     }
 
-                    // lower
+                    // Lower
                     stck.blocks[stck.curIndex].alpha = 0;
                     stck.blocks.forEach(cur => { cur.y += self.defaultBlockHeight - 2; }); // Lower stacked blocks
 
@@ -291,8 +278,8 @@ const squareOne = {
                 game.add.image(defaultWidth / 2, defaultHeight / 2, 'ok').anchor(0.5, 0.5);
                 if (audioStatus) game.audio.okSound.play();
 
-                completedLevels++; // increases number os passed levels
-                if (debugMode) console.log("completedLevels = " + completedLevels);
+                completedLevels++; // Increases number os passed levels
+                if (debugMode) console.log('completedLevels = ' + completedLevels);
 
             } else { // Incorrect answer
 
@@ -333,7 +320,7 @@ const squareOne = {
                 if (self.result) mapMove = true;
                 else mapMove = false;
 
-                mapScreen.preload();
+                game.state.start('map');
             }
 
         }
@@ -346,6 +333,11 @@ const squareOne = {
 
     /* EVENT HANDLER */
 
+    /**
+     * Called by mouse click event
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
     func_onInputDown: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
@@ -353,19 +345,11 @@ const squareOne = {
 
         if (levelType == 'A') {
             self.floor.blocks.forEach(cur => {
-
-                const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                    (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-                if (valid) self.func_clickSquare(cur);
+                if (game.math.isOverIcon(x, y, cur)) self.func_clickSquare(cur);
             });
         } else {
             self.stck.blocks.forEach(cur => {
-
-                const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                    (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-                if (valid) self.func_clickSquare(cur);
+                if (game.math.isOverIcon(x, y, cur)) self.func_clickSquare(cur);
             });
         }
 
@@ -375,6 +359,11 @@ const squareOne = {
 
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
     func_onInputOver: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
@@ -392,11 +381,7 @@ const squareOne = {
             }
 
             self.floor.blocks.forEach(cur => {
-
-                const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                    (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-                if (valid) {
+                if (game.math.isOverIcon(x, y, cur)) {
                     flagA = true;
                     self.func_overSquare(cur);
                 }
@@ -409,11 +394,7 @@ const squareOne = {
         if (levelType == 'B') {
 
             self.stck.blocks.forEach(cur => {
-
-                const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                    (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-                if (valid) {
+                if (game.math.isOverIcon(x, y, cur)) {
                     flagB = true;
                     self.func_overSquare(cur);
                 }
@@ -435,14 +416,19 @@ const squareOne = {
 
     /* CALLED BY EVENT HANDLER */
 
+    /**
+     * Function called when cursor is over a valid rectangle
+     * 
+     * @param {object} cur rectangle the cursor is over
+     */
     func_overSquare: function (cur) {
 
         if (!self.hasClicked) {
 
-            document.body.style.cursor = "pointer";
+            document.body.style.cursor = 'pointer';
 
             // On leveltype A
-            if (levelType == "A") {
+            if (levelType == 'A') {
 
                 for (let i in self.floor.blocks) {
                     self.floor.blocks[i].alpha = (i <= cur.index) ? 1 : 0.5;
@@ -467,26 +453,29 @@ const squareOne = {
 
     },
 
+    /**
+     * Function called when cursos is out of a valid rectangle
+     */
     func_outSquare: function () {
 
         if (!self.hasClicked) {
 
-            document.body.style.cursor = "auto";
+            document.body.style.cursor = 'auto';
 
-            //on level type A
-            if (levelType == "A") {
+            // On level type A
+            if (levelType == 'A') {
 
                 for (let i in self.floor.blocks) {
-                    self.floor.blocks[i].alpha = 0.5; // back to normal
+                    self.floor.blocks[i].alpha = 0.5; // Back to normal
                 }
 
                 self.floor.index = -1;
 
-                //on level type B
+                // On level type B
             } else {
 
                 for (let i in self.stck.blocks) {
-                    self.stck.blocks[i].alpha = 0.5; // back to normal
+                    self.stck.blocks[i].alpha = 0.5; // Back to normal
                 }
 
                 self.stck.index = -1;
@@ -497,11 +486,14 @@ const squareOne = {
 
     },
 
+    /**
+     * Function called when player clicks on a valid rectangle
+     */
     func_clickSquare: function () {
 
         if (!self.hasClicked && !self.animateEnding) {
 
-            document.body.style.cursor = "auto";
+            document.body.style.cursor = 'auto';
 
             // On leveltype A
             if (levelType == 'A') {
@@ -529,7 +521,7 @@ const squareOne = {
                 // (SELECTION : self.FLOOR.index) save the 'floor' blocks index to compare to the stacked index in update
                 self.floor.index = self.floor.blocks.length - 1;
 
-                // save the updated total stacked blocks to compare in update
+                // Save the updated total stacked blocks to compare in update
                 self.stck.blocks.length = self.stck.index + 1;
 
             }
@@ -564,23 +556,27 @@ const squareOne = {
 
     /* GAME FUNCTIONS */
 
+    /**
+     * Create stacked blocks for the level (called in create())
+     * @returns {boolean}
+     */
     func_createStckBlocks: function () {
 
-        let hasBaseDifficulty = false; // will be true after next for loop if level has at least one '1/difficulty' fraction (if false, restart)
+        let hasBaseDifficulty = false; // Will be true after next for loop if level has at least one '1/difficulty' fraction (if false, restart)
         const max = (levelType == 'B') ? 10 : mapPosition + 4; // Maximum number of stacked blocks for the level
 
         const total = game.math.randomInRange(mapPosition + 2, max); // Current number of stacked blocks for the level
 
         self.floor.correctXA = self.startX + self.defaultBlockWidth * self.DIREC_LEVEL;
 
-        for (let i = 0; i < total; i++) { // for each stacked block
+        for (let i = 0; i < total; i++) { // For each stacked block
 
             let divisor = game.math.randomInRange(1, gameDifficulty); // Set divisor for fraction
             if (divisor == gameDifficulty) hasBaseDifficulty = true;
             if (divisor == 3) divisor = 4; // Make sure valid divisors are 1, 2 and 4 (not 3)
-            self.divisorsList += divisor + ","; // List of divisors (for func_postScore())
+            self.divisorsList += divisor + ','; // List of divisors (for func_postScore())
 
-            const curBlockWidth = self.defaultBlockWidth / divisor; // current width is a fraction of the default
+            const curBlockWidth = self.defaultBlockWidth / divisor; // Current width is a fraction of the default
 
             self.floor.correctXA += curBlockWidth * self.DIREC_LEVEL;
 
@@ -631,14 +627,14 @@ const squareOne = {
 
 
 
-        // will be used as a counter in update, adding in the width of each stacked block to check if the end matches the floor selected position
+        // Will be used as a counter in update, adding in the width of each stacked block to check if the end matches the floor selected position
         self.stck.curBlockEnd = self.startX + self.stck.blocks[0].width * self.DIREC_LEVEL;
 
 
 
         let restart = false;
 
-        // check for errors (level too easy for its difficulty or end position out of bounds)
+        // Check for errors (level too easy for its difficulty or end position out of bounds)
         if (!hasBaseDifficulty ||
             (sublevelType == 'Plus' && (self.floor.correctXA < (self.startX + self.defaultBlockWidth) ||
                 self.floor.correctXA > (self.startX + 8 * self.defaultBlockWidth))) ||
@@ -648,13 +644,16 @@ const squareOne = {
             restart = true; // If any error is found restart the level
         }
 
-        if (debugMode) console.log("Stacked blocks: " + total + " (min: " + (mapPosition + 2) + ", max: " + max + ")");
+        if (debugMode) console.log('Stacked blocks: ' + total + ' (min: ' + (mapPosition + 2) + ', max: ' + max + ')');
 
         return restart;
 
     },
 
-    func_createFloorBlocks: function () { // for each floor block
+    /**
+     * Create floor blocks for the level (called in create())
+     */
+    func_createFloorBlocks: function () { // For each floor block
 
         const divisor = (gameDifficulty == 3) ? 4 : gameDifficulty; // Make sure valid divisors are 1, 2 and 4 (not 3)
 
@@ -665,12 +664,12 @@ const squareOne = {
         // If game is type B, selectiong a random floor x position
         if (levelType == 'B') {
 
-            self.stck.correctIndex = game.math.randomInRange(0, (self.stck.blocks.length - 1)); // correct stacked index
+            self.stck.correctIndex = game.math.randomInRange(0, (self.stck.blocks.length - 1)); // Correct stacked index
 
             self.floor.correctXB = self.startX + self.defaultBlockWidth * self.DIREC_LEVEL;
 
             for (let i = 0; i <= self.stck.correctIndex; i++) {
-                self.floor.correctXB += self.stck.blocks[i].width * self.DIREC_LEVEL; // equivalent x position on the floor
+                self.floor.correctXB += self.stck.blocks[i].width * self.DIREC_LEVEL; // Equivalent x position on the floor
             }
 
         }
@@ -679,7 +678,7 @@ const squareOne = {
 
         let flag = true;
 
-        for (let i = 0; i < total; i++) { // for each floor block
+        for (let i = 0; i < total; i++) { // For each floor block
 
             // 'x' coordinate for floor block
             const x = self.startX + (self.defaultBlockWidth + i * blockWidth) * self.DIREC_LEVEL;
@@ -719,7 +718,7 @@ const squareOne = {
             block.anchor(anchor, 0);
 
             // If game is type A, adding events to floor blocks
-            if (levelType == "A") {
+            if (levelType == 'A') {
                 block.alpha = 0.5;
                 block.index = i;
             }
@@ -743,6 +742,9 @@ const squareOne = {
 
     },
 
+    /**
+     * Display correct answer
+     */
     func_viewHelp: function () {
 
         if (!self.hasClicked) {
@@ -769,21 +771,24 @@ const squareOne = {
 
     /* METADATA FOR GAME */
 
+    /**
+     * Saves players data after level 
+     */
     func_postScore: function () {
 
         // Create some variables we need to send to our PHP file
-        const data = "&s_game=" + gameShape
-            + "&s_mode=" + levelType
-            + "&s_oper=" + sublevelType
-            + "&s_leve=" + gameDifficulty
-            + "&s_posi=" + mapPosition
-            + "&s_resu=" + self.result
-            + "&s_time=" + game.timer.elapsed
-            + "&s_deta="
-            + "numBlocks:" + self.stck.blocks.length
-            + ", valBlocks: " + self.divisorsList // ends in ','
-            + " blockIndex: " + self.stck.index
-            + ", floorIndex: " + self.floor.index;
+        const data = '&s_game=' + gameShape
+            + '&s_mode=' + levelType
+            + '&s_oper=' + sublevelType
+            + '&s_leve=' + gameDifficulty
+            + '&s_posi=' + mapPosition
+            + '&s_resu=' + self.result
+            + '&s_time=' + game.timer.elapsed
+            + '&s_deta='
+            + 'numBlocks:' + self.stck.blocks.length
+            + ', valBlocks: ' + self.divisorsList // Ends in ','
+            + ' blockIndex: ' + self.stck.index
+            + ', floorIndex: ' + self.floor.index;
 
         postScore(data);
 

+ 145 - 141
js/squareTwo.js

@@ -1,59 +1,47 @@
-/*
-    GAME LEVELS - SQUARE III: fraction comparisson level
-    
-    Name of game state : 'SquareTwo' 
-    Shape : square
-    Character : kid
-    Theme : (not themed)
-    Concept : player select equivalent dividends for fractions with different divisors
-    Represent fractions as : subdivided blocks
-
-    # of different difficulties for each level : 5
-
-    Level : 'C' (in variable 'levelType')
-
-        C : Player selects equivalent fractions of both blocks 
-    
-    Sublevels can be : 'A', 'B' or 'C' (in variable 'sublevelType')
-    
-        A : equivalence of fractions (with low opacity blocks under the selectable blocks)
-            top has more subdivisions
-        B : equivalence of fractions 
-            top has more subdivisions
-        C : equivalence of fractions
-            bottom has more subdivisions
-*/
-
+/**
+ *  GAME STATE
+ * 
+ *  LEVELS - SQUARE III: fraction comparisson level
+ *   
+ *  Name of game state : 'squareTwo' 
+ *  Shape : square
+ *  Character : kid
+ *  Theme : (not themed)
+ *  Concept : player select equivalent dividends for fractions with different divisors
+ *  Represent fractions as : subdivided blocks
+ *
+ *  # of different difficulties for each level : 5
+ *
+ *  Level : 'C' (in variable 'levelType')
+ *
+ *      C : Player selects equivalent fractions of both blocks 
+ *  
+ *  Sublevels can be : 'B' or 'C' (in variable 'sublevelType')
+ *  
+ *      B : equivalence of fractions 
+ *          top has more subdivisions
+ *      C : equivalence of fractions
+ *          bottom has more subdivisions
+ * 
+ * @namespace
+ */
 const squareTwo = {
 
-    preload: function () {
-
-        document.body.style.cursor = "auto";
-        game.loop.stop();
-        game.event.clear();
-        game.animation.clear();
-
-        self = this;
-
-        // NOTHING TO LOAD HERE
-        squareTwo.create();
-
-    },
-
+    /**
+     * Main code
+     */
     create: function () {
 
-        game.render.clear();
-
         // CONTROL VARIABLES
 
         this.result = false;    // Check if selected blocks are correct
         this.delay = 0;         // Counter for game dalays
         this.endLevel = false;
 
-        self.A = {
+        this.A = {
             blocks: [],     // List of selection blocks
             auxBlocks: [],  // List of shadow under selection blocks
-            fractions: [],  // fraction numbers
+            fractions: [],  // Fraction numbers
 
             selected: 0,    // Number of selected blocks for A
             hasClicked: false,  // Check if player clicked blocks from A
@@ -62,7 +50,7 @@ const squareTwo = {
             label: undefined,
         };
 
-        self.B = {
+        this.B = {
             blocks: [],
             auxBlocks: [],
             fractions: [],
@@ -89,11 +77,12 @@ const squareTwo = {
         for (let i = 0; i < 9; i++) { game.add.image(i * 100, 501, 'floor'); }
 
         // Calls function that loads navigation icons
-        navigationIcons.func_addIcons(true, true, false,
+        navigationIcons.func_addIcons(
+            true, true, false,
             true, false,
-            menuScreenCustom, false);
+            'customMenu', false);
 
-        //Add kid
+        // Add kid
         this.kidAnimation = game.add.sprite(100, 470, 'kid_standing', 5, 0.8);
         this.kidAnimation.anchor(0.5, 0.7);
 
@@ -123,22 +112,22 @@ const squareTwo = {
 
 
 
-        // number of subdivisions of A and B (blocks)
+        // Number of subdivisions of A and B (blocks)
         const totalBlocksA = points[randomIndex];
         const totalBlocksB = game.math.randomDivisor(totalBlocksA);
 
         if (debugMode) {
-            console.log("----------");
-            console.log("Difficulty " + gameDifficulty + ", ini " + ((gameDifficulty - 1) * 2 + 1) + ", end " + ((gameDifficulty - 1) * 2 + 3));
-            console.log("Rpoint " + randomIndex + ", val " + totalBlocksA);
-            console.log("total blocks A " + totalBlocksA + ", total blocks B ");
+            console.log('----------');
+            console.log('Difficulty ' + gameDifficulty + ', ini ' + ((gameDifficulty - 1) * 2 + 1) + ', end ' + ((gameDifficulty - 1) * 2 + 3));
+            console.log('Rpoint ' + randomIndex + ', val ' + totalBlocksA);
+            console.log('total blocks A ' + totalBlocksA + ', total blocks B ');
         }
 
 
 
         // CREATING TOP FIGURE (A)
 
-        let blockWidth = this.figureWidth / totalBlocksA; // width of each block in A
+        let blockWidth = this.figureWidth / totalBlocksA; // Width of each block in A
         let lineColor = colors.darkGreen;
         let fillColor = colors.lightGreen;
 
@@ -152,13 +141,13 @@ const squareTwo = {
             block.figure = 'A';
             block.index = i;
             block.finalX = xA;
-            self.A.blocks.push(block);
+            this.A.blocks.push(block);
 
             // Auxiliar blocks
             const alpha = (sublevelType == 'A') ? 0.2 : 0;
-            const yAux = yA + figureHeight + 10; // on the bottom of A
+            const yAux = yA + figureHeight + 10; // On the bottom of A
             const auxBlock = game.add.graphic.rect(x, yAux, blockWidth, figureHeight, lineColor, 1, fillColor, alpha);
-            self.A.auxBlocks.push(auxBlock);
+            this.A.auxBlocks.push(auxBlock);
 
         }
 
@@ -171,18 +160,18 @@ const squareTwo = {
         // 'selected blocks/fraction' label for A : at the bottom of A
         yLabel = yA + figureHeight + 34;
 
-        self.A.fractions[0] = game.add.text(xLabel, yLabel, "", textStyles.h4_blue);
-        self.A.fractions[1] = game.add.text(xLabel, yLabel + 21, "", textStyles.h4_blue);
-        self.A.fractions[2] = game.add.text(xLabel, yLabel, "___", textStyles.h4_blue);
-        self.A.fractions[0].alpha = 0;
-        self.A.fractions[1].alpha = 0;
-        self.A.fractions[2].alpha = 0;
+        this.A.fractions[0] = game.add.text(xLabel, yLabel, '', textStyles.h4_blue);
+        this.A.fractions[1] = game.add.text(xLabel, yLabel + 21, '', textStyles.h4_blue);
+        this.A.fractions[2] = game.add.text(xLabel, yLabel, '___', textStyles.h4_blue);
+        this.A.fractions[0].alpha = 0;
+        this.A.fractions[1].alpha = 0;
+        this.A.fractions[2].alpha = 0;
 
 
 
         // CREATING BOTTOM FIGURE (B)
 
-        blockWidth = this.figureWidth / totalBlocksB; // width of each block in B
+        blockWidth = this.figureWidth / totalBlocksB; // Width of each block in B
         lineColor = colors.darkRed;
         fillColor = colors.lightRed;
 
@@ -197,13 +186,13 @@ const squareTwo = {
             block.figure = 'B';
             block.index = i;
             block.finalX = xB;
-            self.B.blocks.push(block);
+            this.B.blocks.push(block);
 
             // Auxiliar blocks
             const alpha = (sublevelType == 'A') ? 0.1 : 0;
-            const yAux = yB + figureHeight + 10; // on the bottom of B
+            const yAux = yB + figureHeight + 10; // On the bottom of B
             const auxBlock = game.add.graphic.rect(x, yAux, blockWidth, figureHeight, lineColor, 1, fillColor, alpha);
-            self.B.auxBlocks.push(auxBlock);
+            this.B.auxBlocks.push(auxBlock);
 
         }
 
@@ -216,31 +205,30 @@ const squareTwo = {
         // Label fraction
         yLabel = yB + figureHeight + 34;
 
-        self.B.fractions[0] = game.add.text(xLabel, yLabel, "", textStyles.h4_blue);
-        self.B.fractions[1] = game.add.text(xLabel, yLabel + 21, "", textStyles.h4_blue);
-        self.B.fractions[2] = game.add.text(xLabel, yLabel, "___", textStyles.h4_blue);
-        self.B.fractions[0].alpha = 0;
-        self.B.fractions[1].alpha = 0;
-        self.B.fractions[2].alpha = 0;
+        this.B.fractions[0] = game.add.text(xLabel, yLabel, '', textStyles.h4_blue);
+        this.B.fractions[1] = game.add.text(xLabel, yLabel + 21, '', textStyles.h4_blue);
+        this.B.fractions[2] = game.add.text(xLabel, yLabel, '___', textStyles.h4_blue);
+        this.B.fractions[0].alpha = 0;
+        this.B.fractions[1].alpha = 0;
+        this.B.fractions[2].alpha = 0;
 
         // Invalid selection text
-        self.A.warningText = game.add.text(defaultWidth / 2, defaultHeight / 2 - 225, "", textStyles.h4_brown);
+        this.A.warningText = game.add.text(defaultWidth / 2, defaultHeight / 2 - 225, '', textStyles.h4_brown);
 
-        self.B.warningText = game.add.text(defaultWidth / 2, defaultHeight / 2 - 45, "", textStyles.h4_brown);
+        this.B.warningText = game.add.text(defaultWidth / 2, defaultHeight / 2 - 45, '', textStyles.h4_brown);
 
 
 
-        game.render.all();
-
         game.timer.start(); // Set a timer for the current level (used in func_postScore)
 
-        game.event.add("click", squareTwo.func_onInputDown);
-        game.event.add("mousemove", squareTwo.func_onInputOver);
-
-        game.loop.start(this);
+        game.event.add('click', this.func_onInputDown);
+        game.event.add('mousemove', this.func_onInputOver);
 
     },
 
+    /**
+     * Game loop
+     */
     update: function () {
 
         // Animate blocks
@@ -267,7 +255,7 @@ const squareTwo = {
 
         }
 
-        // if A and B are already clicked
+        // If A and B are already clicked
         if (self.A.hasClicked && self.B.hasClicked && !self.endLevel) {
 
             game.timer.stop();
@@ -279,27 +267,27 @@ const squareTwo = {
 
                 self.result = (self.A.selected / self.A.blocks.length) == (self.B.selected / self.B.blocks.length);
 
-                // fractions are equivalent : CORRECT
+                // Fractions are equivalent : CORRECT
                 if (self.result) {
 
                     if (audioStatus) game.audio.okSound.play();
 
                     game.add.image(defaultWidth / 2, defaultHeight / 2, 'ok').anchor(0.5, 0.5);
 
-                    mapMove = true; // allow character to move to next level in map state
+                    mapMove = true; // Allow character to move to next level in map state
 
                     completedLevels++;
 
-                    if (debugMode) console.log("completedLevels = " + completedLevels);
+                    if (debugMode) console.log('completedLevels = ' + completedLevels);
 
-                    // fractions are not equivalent : INCORRECT
+                    // Fractions are not equivalent : INCORRECT
                 } else {
 
                     if (audioStatus) game.audio.errorSound.play();
 
                     game.add.image(defaultWidth / 2, defaultHeight / 2, 'error').anchor(0.5, 0.5);
 
-                    mapMove = false; // doesnt allow character to move to next level in map state
+                    mapMove = false; // Doesnt allow character to move to next level in map state
 
                 }
 
@@ -307,7 +295,7 @@ const squareTwo = {
 
                 self.endLevel = true;
 
-                // reset delay values for next delay
+                // Reset delay values for next delay
                 self.delay = 0;
 
             }
@@ -320,7 +308,7 @@ const squareTwo = {
             self.delay++;
 
             if (self.delay >= 80) {
-                mapScreen.preload();
+                game.state.start('map');
             }
 
         }
@@ -333,32 +321,38 @@ const squareTwo = {
 
     /* EVENT HANDLER */
 
+    /**
+     * Called by mouse click event
+     * 
+     * @param {object} mouseEvent contains the mouse click coordinates
+     */
     func_onInputDown: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
         const y = mouseEvent.offsetY;
 
-        // click block in A
+        // Click block in A
         self.A.blocks.forEach(cur => {
-
-            const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) && (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-            if (valid) self.func_clickSquare(cur);
+            if (game.math.isOverIcon(x, y, cur)) self.func_clickSquare(cur);
         });
 
-        // click block in B
+        // Click block in B
         self.B.blocks.forEach(cur => {
-
-            const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) && (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-            if (valid) self.func_clickSquare(cur);
+            if (game.math.isOverIcon(x, y, cur)) self.func_clickSquare(cur);
         });
 
-        // click navigation icons
+        // Click navigation icons
         navigationIcons.func_onInputDown(x, y);
 
         game.render.all();
 
     },
 
+    /**
+     * Called by mouse move event
+     * 
+     * @param {object} mouseEvent contains the mouse move coordinates
+     */
     func_onInputOver: function (mouseEvent) {
 
         const x = mouseEvent.offsetX;
@@ -366,37 +360,29 @@ const squareTwo = {
         let flagA = false;
         let flagB = false;
 
-        // mouse over A : show fraction
+        // Mouse over A : show fraction
         self.A.blocks.forEach(cur => {
-
-            const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-            if (valid) {
+            if (game.math.isOverIcon(x, y, cur)) {
                 flagA = true;
                 self.func_overSquare(cur);
             }
         });
         if (!flagA) self.func_outSquare('A');
 
-        // mouse over B : show fraction
+        // Mouse over B : show fraction
         self.B.blocks.forEach(cur => {
-
-            const valid = y >= cur.yWithAnchor && y <= (cur.yWithAnchor + cur.height * cur.scale) &&
-                (x >= cur.xWithAnchor && x <= (cur.xWithAnchor + cur.width * cur.scale));
-
-            if (valid) {
+            if (game.math.isOverIcon(x, y, cur)) {
                 flagB = true;
                 self.func_overSquare(cur);
             }
         });
         if (!flagB) self.func_outSquare('B');
 
-        if (!flagA && !flagB) document.body.style.cursor = "auto";
+        if (!flagA && !flagB) document.body.style.cursor = 'auto';
 
 
 
-        // mouse over navigation icons : show name
+        // Mouse over navigation icons : show name
         navigationIcons.func_onInputOver(x, y);
 
         game.render.all();
@@ -407,38 +393,43 @@ const squareTwo = {
 
     /* CALLED BY EVENT HANDLER */
 
+    /**
+     * Function called when cursor is over a valid rectangle
+     * 
+     * @param {object} curBlock rectangle the cursor is over
+     */
     func_overSquare: function (curBlock) { // curBlock : self.A.blocks[i] || self.B.blocks[i]
 
-        const curSet = curBlock.figure; // "A" || "B"
+        const curSet = curBlock.figure; // 'A' || 'B'
 
         if (!self[curSet].hasClicked) { // self.A.hasClicked || self.B.hasClicked 
 
             // If over fraction 'n/n' shows warning message not allowing it
             if (curBlock.index == self[curSet].blocks.length - 1) {
 
-                const otherSet = (curSet == "A") ? "B" : "A";
+                const otherSet = (curSet == 'A') ? 'B' : 'A';
 
                 self[curSet].warningText.name = game.lang.error_msg;
-                self[otherSet].warningText.name = "";
+                self[otherSet].warningText.name = '';
 
                 self.func_outSquare(curSet);
 
             } else {
 
-                document.body.style.cursor = "pointer";
+                document.body.style.cursor = 'pointer';
 
-                self.A.warningText.name = "";
-                self.B.warningText.name = "";
+                self.A.warningText.name = '';
+                self.B.warningText.name = '';
 
-                // selected blocks become fully visible
+                // Selected blocks become fully visible
                 for (let i in self[curSet].blocks) {
                     self[curSet].blocks[i].alpha = (i <= curBlock.index) ? 1 : 0.5;
                 }
 
-                self[curSet].fractions[0].name = curBlock.index + 1; // nominator : selected blocks
-                self[curSet].fractions[1].name = self[curSet].blocks.length; // denominator : total blocks
+                self[curSet].fractions[0].name = curBlock.index + 1; // Nominator : selected blocks
+                self[curSet].fractions[1].name = self[curSet].blocks.length; // Denominator : total blocks
 
-                const newX = curBlock.finalX + ((curBlock.index + 1) * (self.figureWidth / self[curSet].blocks.length)) + 25;;
+                const newX = curBlock.finalX + ((curBlock.index + 1) * (self.figureWidth / self[curSet].blocks.length)) + 25;
                 self[curSet].fractions[0].x = newX;
                 self[curSet].fractions[1].x = newX;
                 self[curSet].fractions[2].x = newX;
@@ -451,6 +442,11 @@ const squareTwo = {
 
     },
 
+    /**
+     * Function called when cursor is out of a valid rectangle
+     * 
+     * @param {object} curSet set of rectangles (top or bottom)
+     */
     func_outSquare: function (curSet) { // curSet : self.A || self.B
 
         if (!self[curSet].hasClicked) {
@@ -467,20 +463,25 @@ const squareTwo = {
 
     },
 
+    /**
+     * Function called when player clicked a valid rectangle
+     * 
+     * @param {object} curBlock clicked rectangle
+     */
     func_clickSquare: function (curBlock) { // curBlock : self.A.blocks[i] || self.B.blocks[i]
 
-        const curSet = curBlock.figure; // "A" || "B"
+        const curSet = curBlock.figure; // 'A' || 'B'
 
         if (!self[curSet].hasClicked && curBlock.index != self[curSet].blocks.length - 1) {
 
-            document.body.style.cursor = "auto";
+            document.body.style.cursor = 'auto';
 
-            // turn auxiliar blocks invisible
+            // Turn auxiliar blocks invisible
             for (let i in self[curSet].blocks) {
                 if (i > curBlock.index) self[curSet].auxBlocks[i].alpha = 0;
             }
 
-            // turn value label invisible
+            // Turn value label invisible
             self[curSet].label.alpha = 0;
 
             if (audioStatus) game.audio.beepSound.play();
@@ -488,7 +489,7 @@ const squareTwo = {
             // Save number of selected blocks
             self[curSet].selected = curBlock.index + 1;
 
-            // set fraction x position
+            // Set fraction x position
             const newX = curBlock.finalX + (self[curSet].selected * (self.figureWidth / self[curSet].blocks.length)) + 25;
             self[curSet].fractions[0].x = newX;
             self[curSet].fractions[1].x = newX;
@@ -497,8 +498,8 @@ const squareTwo = {
             self[curSet].fractions[1].alpha = 1;
             self[curSet].fractions[2].alpha = 1;
 
-            self[curSet].hasClicked = true; // inform player have clicked in current block set
-            self[curSet].animate = true; // let it initiate animation
+            self[curSet].hasClicked = true; // Inform player have clicked in current block set
+            self[curSet].animate = true; // Let it initiate animation
 
         }
 
@@ -510,21 +511,24 @@ const squareTwo = {
 
     /* METADATA FOR GAME */
 
+    /**
+     * Saves players data after level
+     */
     func_postScore: function () {
 
         // Create some variables we need to send to our PHP file
-        const data = "&s_game=" + gameShape
-            + "&s_mode=" + levelType
-            + "&s_oper=Equal"
-            + "&s_leve=" + gameDifficulty
-            + "&s_posi=" + mapPosition
-            + "&s_resu=" + self.result
-            + "&s_time=" + game.timer.elapsed
-            + "&s_deta="
-            + "numBlocksA: " + self.A.blocks.length
-            + ", valueA: " + self.A.selected
-            + ", numBlocksB: " + self.B.blocks.length
-            + ", valueB: " + self.B.selected;;
+        const data = '&s_game=' + gameShape
+            + '&s_mode=' + levelType
+            + '&s_oper=Equal'
+            + '&s_leve=' + gameDifficulty
+            + '&s_posi=' + mapPosition
+            + '&s_resu=' + self.result
+            + '&s_time=' + game.timer.elapsed
+            + '&s_deta='
+            + 'numBlocksA: ' + self.A.blocks.length
+            + ', valueA: ' + self.A.selected
+            + ', numBlocksB: ' + self.B.blocks.length
+            + ', valueB: ' + self.B.selected;
 
         postScore(data);
 

+ 28 - 53
php/save.php

@@ -1,15 +1,16 @@
 <?php
 
-// ATENCAO ao
-// * nome da base de dados: db_ifractions
-// * nome da tabela dados : ifractions
+// IMPORTANT
 
-// php/save.php on line 23, referer: http://milanesa.ime.usp.br/ifractions1/
+// * database name : db_ifractions
+// * table name : ifractions
 
-/// @see js/circleOne.js
-/// @see js/squareOne.js
-/// @see js/squareTwo.js
-/// @see js/globals.js
+// php/save.php on line 24, referer: http://milanesa.ime.usp.br/ifractions1/
+
+// @see js/globals.js
+// @see js/circleOne.js
+// @see js/squareOne.js
+// @see js/squareTwo.js
 
 function remove_accents ($stripAccents) {
   /*
@@ -21,21 +22,8 @@ function remove_accents ($stripAccents) {
   return $stripAccents;
 }
 
-// Monta vetor [0,1] de dados da m<E1>quina cliente
-function ipMaquina0 () {
-  if (getenv("HTTP_CLIENT_IP"))
-    $ip = getenv("HTTP_CLIENT_IP");
-  elseif (getenv("HTTP_X_FORWARDED_FOR"))
-    $ip = getenv("HTTP_X_FORWARDED_FOR");
-  elseif (getenv("REMOTE_ADDR"))
-    $ip = getenv("REMOTE_ADDR");
-  $resp[0] = $ip;
-  $resp[1] = gethostbyaddr($ip);
-  return $resp;
-}
-
-// Monta vetor [0,1] de dados da m<E1>quina cliente
-function ipMaquina () {
+// Creates array [0,1] of client data
+function clientIP () {
   if (getenv("HTTP_CLIENT_IP"))
     $ip = getenv("HTTP_CLIENT_IP");
   elseif (getenv("HTTP_X_FORWARDED_FOR"))
@@ -50,7 +38,6 @@ function ipMaquina () {
   return $strIP;
 }
 
-
 $servername = "localhost";
 $username = "root"; // put here the name of user root of MySQL
 $password = "put_paswd"; // put here the password of user root of MySQL
@@ -58,27 +45,17 @@ $dbname = "put_name_of_base"; // put here the name of data base used to register
 
 // Create connection
 $conn = new mysqli($servername, $username, $password, $dbname);
+
 // Check connection
 if ($conn->connect_error) {
   die("Connection failed: " . $conn->connect_error);
 }
 
+$ip = clientIP();
 
-// $ip = $_REQUEST["s_ip"];
-$ip = ipMaquina();
-/*
-$vet_ip = ipMaquina0();
-$ip = "";
-if (isset($vet_ip[0]) && strlen($vet_ip[0]>0))
-  $ip = $vet_ip[0];
-if (isset($vet_ip[1]) && strlen($vet_ip[1]>0))
-  if (strlen($ip)>0)
-    $ip = $ip . " - " . $vet_ip[1];
-  else
-    $ip = $vet_ip[1];
-*/
-
-$play = $_REQUEST["s_name"];
+// /js/globals.js: data = s_ip=120.0.0.1&s_name=name&s_lang=pt_BR
+// /js/squareOne.js: data += &s_game=Square&s_mode=A&s_oper=Plus&s_leve=1&s_posi=1&s_resu=true&s_time=3&s_deta=numBlocks:3, valBlocks: 1,1,1, blockIndex: 2, floorIndex: 2;url=php/save.php
+$name = $_REQUEST["s_name"];
 $date = date("Y-m-d H:i:s");
 $lang = $_REQUEST["s_lang"];
 $game = $_REQUEST["s_game"];
@@ -90,8 +67,9 @@ $resu = $_REQUEST["s_resu"];
 $time = $_REQUEST["s_time"];
 $deta = $_REQUEST["s_deta"];
 
-$play0 = $play; // /var/www/html/ifractions1/js/preMenu.js: insert_name
-$play = remove_accents($play); // /js/squareOne.js:vars=s_ip=143.107.45.11&s_name=&s_lang=pt&s_game=Square&s_mode=A&s_oper=Plus&s_leve=1&s_posi=1&s_resu=true&s_time=3&s_deta=numBlocks:3, valBlocks: 1,1,1, blockIndex: 2, floorIndex: 2; url=php/save.php
+$nameUnchanged = $name; // /js/preMenu.js: playerName
+
+$name = remove_accents($name); 
 
 if (is_object($lang))
   $lang = json_decode($lang);
@@ -100,28 +78,25 @@ if (is_object($lang))
 $sql = "INSERT INTO ifractions
 (s_hostip, s_playername, s_datetime, s_lang, s_game, s_mode, s_operator, s_level, s_mappos, s_result, s_time, s_details)
 VALUES
-('$ip', '$play', '$date', '$lang', '$game', '$mode', '$oper', $leve, $posi, '$resu', $time, '$deta')";
+('$ip', '$name', '$date', '$lang', '$game', '$mode', '$oper', $leve, $posi, '$resu', $time, '$deta')";
 
 // Register in database
 if ($conn->query($sql) === TRUE) {
-  print "Gravado/Grabado";
+  print "Saved.";
   $result = "OK";
 } else {
   print "Error: " . $sql . "<br>" . $conn->error;
-  $result = "Erro: " . $conn->error;
+  $result = "Error: " . $conn->error;
 }
 
 
-//DEBUG
-// js/menu.js : var menuState = { player_info = ... username ...}
-// welcome
-// index.php: game.state.add('name', nameState);
-$name = $_REQUEST["name"];
-$username = $_REQUEST["username"];
-$data = date('Y_m_d_H_i_s');
-$fp = fopen('../../temp/file_' . $data . ".txt", 'w');
-fwrite($fp, "nome=" . $play0 . ", name=" . $name . ", username=" . $username . "\n" . $sql . "\nResultado: " . $result);
+
+// DEBUG
+$date = date('Y_m_d_H_i_s');
+$fp = fopen('../temp/file_' . $date . ".txt", 'w');
+fwrite($fp, "name_unchanged=" . $nameUnchanged . ", name=" . $name . "\n" . $sql . "\nResultado: " . $result);
 fclose($fp);
 
 $conn->close();
+
 ?>