123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648 |
- /**************************************************************
- * LInE - Free Education, Private Data - http://www.usp.br/line
- *
- * This file holds all global elements to the game.
- *
- * Generating game levels in menu:
- * .....................................................
- * ...............square....................circle...... } = gameShape
- * .........../...........\....................|........ } = gameType (game)
- * ........One.............Two................One....... }
- * ......./...\.........../...\............./....\......
- * ......A.....B.........A.....B...........A......B..... = gameMode (game mode)
- * .(floor)..(stack)..(top)..(bottom)..(floor)..(stack).
- * .......\./.............\./................\./........
- * ........|...............|..................|.........
- * ......./.\..............|................/.|.\.......
- * ...Plus...Minus.......Equals........Plus.Minus.Mixed. = gameOperation (game math operation)
- * .......\./..............|................\.|./.......
- * ........|...............|..................|.........
- * ......1,2,3.........1,2,3,4,5..........1,2,3,4,5..... = gameDifficulty (difficulty level)
- * .....................................................
- *
- * About levels in map:
- *
- * ..................(game.levels)......................
- * ......................__|__..........................
- * .....................|.|.|.|.........................
- * ...................0,1,2,3,4,5....................... = mapPosition (map positions)
- * ...................|.........|.......................
- * ................(start)....(end).....................
- **************************************************************/
- /**
- * Turns console messages ON/OFF (for debug purposes only)
- * @type {boolean}
- */
- const debugMode = false;
- /** FOR MOODLE <br>
- *
- * iFractions can run on a server or inside moodle through iAssign. <br>
- * This variable should be set according to where it is suposed to run: <br>
- * - if true, on moodle <br>
- * - if false, on a server
- */
- const moodle = true;
- /**
- * HTMLCanvasElement : Canvas where all the game elements are rendered.
- * @type {object}
- */
- let canvas;
- /**
- * Selected game.<br>
- * Can be the objects: squareOne, squareTwo or circleOne.
- *
- * @type {object}
- */
- let gameType;
- /**
- * Name of the selected game.<br>
- * Can be: 'squareOne', 'squareTwo' or 'circleOne'.
- *
- * @type {string}
- */
- let gameTypeString;
- /**
- * Used for text and game information.<br>
- * Shape that makes the name of the game - e.g in 'squareOne' it is 'square'.<br>
- * Can be: 'circle' or 'square'.
- *
- * @type {string}
- */
- let gameShape;
- /**
- * Holds selected game mode.<br>
- * In squareOne/circleOne can be: 'A' (click on the floor) or 'B' (click on the amount to go/stacked figures).<br>
- * In squareTwo can be: 'A' (more subdivisions on top) or 'B' (more subdivisions on bottom).
- *
- * @type {string}
- */
- let gameMode;
- /**
- * Holds game math operation.<br>
- * In squareOne can be: 'Plus' (green tractor goes right) or 'Minus' (red tractor goes left).<br>
- * In circleOne can be: 'Plus' (green tractor goes right), 'Minus' (red tractor goes left) or 'Mixed' (green tractor goes both sides).<br>
- * In squareTwo can be: 'Equals' (compares two rectangle subdivisions).
- *
- * @type {string}
- */
- let gameOperation;
- /**
- * Holds game overall difficulty. 1 (easier) -> n (harder).<br>
- * In squareOne can be: 1..3.<br>
- * In circleOne/squareTwo can be: 1..5.
- *
- * @type {number}
- */
- let gameDifficulty;
- /**
- * Turns displaying the fraction labels on levels ON/OFF
- * @type {boolean}
- */
- let fractionLabel = true;
- /**
- * When true, the character can move to next position in the map
- * @type {boolean}
- */
- let mapMove;
- /**
- * Character position on the map, aka game levels (1..4: valid; 5: end)
- * @type {number}
- */
- let mapPosition;
- /**
- * Number of finished levels in the map
- * @type {number}
- */
- let completedLevels;
- /**
- * Turns game audio ON/OFF
- * @type {boolean}
- */
- let audioStatus = false;
- /**
- * Player's name
- * @type {string}
- */
- let playerName;
- /**
- * String that contains the selected language.<br>
- * It is the name of the language file.
- * @type {string}
- */
- let langString;
- /**
- * Holds the current state.<br>
- * Is used as if it was a 'this' inside state functions.
- * @type {object}
- */
- let self;
- const medSrc = 'assets/img/'; // Base directory for media
- /**
- * Metadata for all games
- * @type {object}
- */
- const info = {
- squareOne: {
- gameShape: 'square',
- gameType: 'squareOne',
- gameTypeUrl: 'game0',
- gameMode: ['A', 'B'],
- gameModeUrl: ['mode0', 'mode1'],
- gameOperation: ['Plus', 'Minus'],
- gameDifficulty: 3
- },
- circleOne: {
- gameShape: 'circle',
- gameType: 'circleOne',
- gameTypeUrl: 'game1',
- gameMode: ['A', 'B'],
- gameModeUrl: ['mode2', 'mode3'],
- gameOperation: ['Plus', 'Minus', 'Mixed'],
- gameDifficulty: 5
- },
- squareTwo: {
- gameShape: 'square',
- gameType: 'squareTwo',
- gameTypeUrl: 'game2',
- gameMode: ['A', 'B'],
- gameModeUrl: ['mode4', 'mode5'],
- gameOperation: ['Equals'],
- gameDifficulty: 5
- },
- gameShape: [],
- gameType: [],
- gameTypeUrl: [],
- gameMode: [],
- gameModeUrl: [],
- gameOperation: [],
- gameDifficulty: [],
- // When game starts, update values
- start: function () {
- info.gameShape = [
- info.squareOne.gameShape,
- info.circleOne.gameShape,
- info.squareTwo.gameShape
- ];
- info.gameType = [
- info.squareOne.gameType,
- info.circleOne.gameType,
- info.squareTwo.gameType
- ];
- info.gameTypeUrl = [
- info.squareOne.gameTypeUrl,
- info.circleOne.gameTypeUrl,
- info.squareTwo.gameTypeUrl
- ];
- info.gameDifficulty = [
- info.squareOne.gameDifficulty,
- info.circleOne.gameDifficulty,
- info.squareTwo.gameDifficulty
- ];
- info.gameMode = info.squareOne.gameMode.concat(info.circleOne.gameMode, info.squareTwo.gameMode);
- info.gameModeUrl = info.squareOne.gameModeUrl.concat(info.circleOne.gameModeUrl, info.squareTwo.gameModeUrl);
- info.gameOperation = info.squareOne.gameOperation.concat(info.circleOne.gameOperation, info.squareTwo.gameOperation);
- }
- };
- /**
- * Preset colors for graphic elements.
- * @type {object}
- */
- 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', // 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: '#ffef1f'
- };
- /**
- * Preset text styles for game text.<br>
- * Contains: font, size, text color and text align.
- * @type {object}
- */
- 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 (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)
- h3__white: { font: '23px Arial,sans-serif', fill: colors.white, align: 'center' }, // Difficulty numbers (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
- p_brown: { font: '14px Arial,sans-serif', fill: colors.darkRed, align: 'center' }, // Map difficulty label
- 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 URL for all media in the game
- * divided 1st by the 'state' that loads the media
- * and 2nd by the 'media type' for that state.
- *
- * @type {object}
- */
- const url = {
- /**
- * url.<state>
- * where <state> can be: boot, menu, squareOne, squareTwo, circleOne.
- */
- boot: {
- /**
- * url.<state>.<media type>
- * where <media type> can be: image, sprite, audio <br><br>
- *
- * image: [ [name, source], ... ] <br>
- * sprite: [ [name, source, number of frames], ... ] <br>
- * audio: [ [name, [source, alternative source] ], ... ]
- */
- image: [
- // Scene
- ['bgimage', medSrc + 'scene/bg.jpg'],
- ['bgmap', medSrc + 'scene/bg_map.png'],
- ['broken_sign', medSrc + 'scene/broken_sign.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'],
- ['flag_IT', medSrc + 'flag/ITAL.png'],
- ['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'],
- // Interactive icons
- ['arrow_down', medSrc + 'interac_icon/down.png'],
- ['close', medSrc + 'interac_icon/close.png'],
- ['error', medSrc + 'interac_icon/error.png'],
- ['help_pointer', medSrc + 'interac_icon/pointer.png'],
- ['info', medSrc + 'interac_icon/info.png'],
- ['ok', medSrc + 'interac_icon/ok.png'],
- ],
- sprite: [
- // Game Sprites
- ['kid_walk', medSrc + 'character/kid/walk.png', 26],
- // Navigation icons on the top of the page
- ['audio', medSrc + 'navig_icon/audio.png', 2],
- // Interactive icons
- ['select', medSrc + 'interac_icon/selectionBox.png', 2]
- ],
- audio: [
- // Sound effects
- ['beepSound', ['assets/audio/beep.ogg', 'assets/audio/beep.mp3']],
- ['okSound', ['assets/audio/ok.ogg', 'assets/audio/ok.mp3']],
- ['errorSound', ['assets/audio/error.ogg', 'assets/audio/error.mp3']]
- ]
- },
- menu: {
- image: [
- // Game
- ['game0', medSrc + 'levels/squareOne.png'], // Square I
- ['game1', medSrc + 'levels/circleOne.png'], // Circle I
- ['game2', medSrc + 'levels/squareTwo.png'], // Square II
- // Info box icons
- ['c1-A', medSrc + 'info_box/c1-A.png'],
- ['c1-A-h', medSrc + 'info_box/c1-A-h.png'],
- ['c1-B-h', medSrc + 'info_box/c1-B-h.png'],
- ['c1-diff-1', medSrc + 'info_box/c1-diff-1.png'],
- ['c1-diff-5', medSrc + 'info_box/c1-diff-5.png'],
- ['c1-label', medSrc + 'info_box/c1-label.png'],
- ['map-c1s2', medSrc + 'info_box/map-c1s2.png'],
- ['map-s1', medSrc + 'info_box/map-s1.png'],
- ['s1-A', medSrc + 'info_box/s1-A.png'],
- ['s1-A-h', medSrc + 'info_box/s1-A-h.png'],
- ['s1-B-h', medSrc + 'info_box/s1-B-h.png'],
- ['s1-diff-1', medSrc + 'info_box/s1-diff-1.png'],
- ['s1-diff-3', medSrc + 'info_box/s1-diff-3.png'],
- ['s1-label', medSrc + 'info_box/s1-label.png'],
- ['s2', medSrc + 'info_box/s2.png'],
- ['s2-A-h', medSrc + 'info_box/s2-A-h.png'],
- ['s2-B-h', medSrc + 'info_box/s2-B-h.png'],
- ['s2-diff-1', medSrc + 'info_box/s2-diff-1.png'],
- ['s2-diff-5', medSrc + 'info_box/s2-diff-5.png'],
- ['s2-label', medSrc + 'info_box/s2-label.png'],
- ['operation_plus', medSrc + 'info_box/operation_plus.png'],
- ['operation_minus', medSrc + 'info_box/operation_minus.png'],
- ['operation_mixed', medSrc + 'info_box/operation_mixed.png'],
- ['operation_equals', medSrc + 'info_box/operation_equals.png'],
- ],
- sprite: [
- // Game modes
- ['mode0', medSrc + 'levels/squareOne_1.png', 2], // Square I : A
- ['mode1', medSrc + 'levels/squareOne_2.png', 2], // Square I : B
- ['mode2', medSrc + 'levels/circleOne_1.png', 2], // Circle I : A
- ['mode3', medSrc + 'levels/circleOne_2.png', 2], // Circle I : B
- ['mode4', medSrc + 'levels/squareTwo_1.png', 2], // Square II : A
- ['mode5', medSrc + 'levels/squareTwo_2.png', 2], // Square II : B
- // Math operations
- ['operation_plus', medSrc + 'levels/operation_plus.png', 2], // Square/circle I : right
- ['operation_minus', medSrc + 'levels/operation_minus.png', 2], // Square/circle I : left
- ['operation_mixed', medSrc + 'levels/operation_mixed.png', 2], // Circle I : mixed
- ['operation_equals', medSrc + 'levels/operation_equals.png', 2], // Square II : equals
- ],
- audio: []
- },
- squareOne: {
- image: [
- // Scene
- ['farm', medSrc + 'scene/farm.png'],
- ['garage', medSrc + 'scene/garage.png']
- ],
- sprite: [
- // Game sprites
- ['tractor', medSrc + 'character/tractor/tractor.png', 15]
- ],
- audio: []
- },
- squareTwo: {
- image: [
- // Scene
- ['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]
- ],
- audio: []
- },
- circleOne: {
- image: [
- // Scene
- ['house', medSrc + 'scene/house.png'],
- ['school', medSrc + 'scene/school.png'],
- // Game images
- ['balloon', medSrc + 'character/balloon/airballoon_upper.png'],
- ['balloon_basket', medSrc + 'character/balloon/airballoon_base.png']
- ],
- sprite: [
- // Game sprites
- ['kid_run', medSrc + 'character/kid/run.png', 12]
- ],
- audio: []
- }
- };
- /**
- * Manages navigation icons on the top of the screen
- * @namespace
- */
- const navigationIcons = {
- /**
- * Add navigation icons.<br>
- * * The icons on the left are ordered from left to right. <br>
- * * The icons on the right are ordered from right to left.
- *
- * @param {boolean} leftIcon0 1st left icon (back)
- * @param {boolean} leftIcon1 2nd left icon (main menu)
- * @param {boolean} leftIcon2 3rd left icon (solve game)
- * @param {boolean} rightIcon0 1st right icon (audio)
- * @param {boolean} rightIcon1 2nd right icon (lang)
- * @param {undefined|string} state state to be called by the 'back' button (must exist if param 'leftIcon0' is true)
- * @param {undefined|function} help function in the current game state that display correct answer
- */
- add: function (leftIcon0, leftIcon1, leftIcon2, rightIcon0, rightIcon1, state, help) {
- let left_x = 10;
- let right_x = defaultWidth - 50 - 10;
- this.iconsList = [];
- // 'Descriptive labels' for the navigation icons
- this.left_text = game.add.text(left_x, 73, '', textStyles.h4_brown);
- this.left_text.align = 'left';
- this.right_text = game.add.text(right_x + 50, 73, '', textStyles.h4_brown);
- this.right_text.align = 'right';
- // Left icons
- if (leftIcon0) { // Return to previous screen
- if (!state) {
- console.error('Game error: You tried to add a \'back\' icon without the \'state\' parameter.');
- } else {
- this.state = state;
- this.iconsList.push(game.add.image(left_x, 10, 'back'));
- left_x += 50;
- }
- }
- if (leftIcon1) { // Return to main menu screen
- this.iconsList.push(game.add.image(left_x, 10, 'menu'));
- left_x += 50;
- }
- if (leftIcon2) { // Shows solution to the game
- if (!help) {
- console.error('Game error: You tried to add a \'game solution\' icon without the \'help\' parameter.');
- } else {
- this.help = help;
- this.iconsList.push(game.add.image(left_x, 10, 'help'));
- left_x += 50;
- }
- }
- // Right icons
- if (rightIcon0) { // Turns game audio on/off
- this.audioIcon = game.add.sprite(right_x, 10, 'audio', 1);
- this.audioIcon.curFrame = audioStatus ? 0 : 1;
- this.iconsList.push(this.audioIcon);
- right_x -= 50;
- }
- if (rightIcon1) { // Return to select language screen
- this.iconsList.push(game.add.image(right_x, 10, 'language'));
- right_x -= 50;
- }
- },
- /**
- * When 'back' icon is clicked go to this state
- *
- * @param {string} state name of the next state
- */
- callState: function (state) {
- if (audioStatus) game.audio.beepSound.play();
- game.event.clear(self);
- 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
- */
- onInputDown: function (x, y) {
- navigationIcons.iconsList.forEach(cur => {
- if (game.math.isOverIcon(x, y, cur)) {
- const name = cur.name;
- switch (name) {
- case 'back': navigationIcons.callState(navigationIcons.state); break;
- case 'menu': navigationIcons.callState('menu'); break;
- case 'help': navigationIcons.help(); break;
- case 'language': navigationIcons.callState('lang'); break;
- case 'audio':
- if (audioStatus) {
- audioStatus = false;
- navigationIcons.audioIcon.curFrame = 1;
- } else {
- audioStatus = true;
- if (audioStatus) game.audio.beepSound.play();
- navigationIcons.audioIcon.curFrame = 0;
- }
- game.render.all();
- break;
- default: console.error('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
- */
- onInputOver: function (x, y) {
- let flag = false;
- navigationIcons.iconsList.forEach(cur => {
- if (game.math.isOverIcon(x, y, cur)) {
- flag = true;
- let name = cur.name;
- switch (name) {
- case 'back': navigationIcons.left_text.name = game.lang.nav_back; break;
- case 'menu': navigationIcons.left_text.name = game.lang.nav_menu; break;
- case 'help': navigationIcons.left_text.name = game.lang.nav_help; break;
- case 'language': navigationIcons.right_text.name = game.lang.nav_lang; break;
- case 'audio': navigationIcons.right_text.name = game.lang.audio; break;
- }
- }
- });
- if (!flag) {
- navigationIcons.left_text.name = '';
- navigationIcons.right_text.name = '';
- } else {
- document.body.style.cursor = 'pointer';
- }
- }
- };
- /**
- * Sends game information to database
- *
- * @param {string} extraData player information for the current game
- */
- const sendToDB = function (extraData) {
- // FOR MOODLE
- if (moodle) {
- if (self.result) moodleVar.hits[mapPosition - 1]++;
- else moodleVar.errors[mapPosition - 1]++;
- moodleVar.time[mapPosition - 1] += game.timer.elapsed;
- } else {
- // Create some variables we need to send to our PHP file
- // Attention: this names must be compactible to data table (MySQL server)
- // @see php/save.php
- const data = 'line_ip=143.107.45.11' // INSERT database server IP
- + '&line_name=' + playerName
- + '&line_lang=' + langString
- + extraData;
- const url = 'php/save.php';
- const init = { method: 'POST', body: data, headers: { 'Content-type': 'application/x-www-form-urlencoded' } };
- fetch(url, init)
- .then(response => {
- if (response.ok) {
- if (debugMode) console.log("Processing...");
- response.text().then(text => { if (debugMode) { console.log(text); } })
- } else {
- console.error("Game error: Network response was not ok.");
- }
- })
- .catch(error => {
- console.error('Game error: problem with fetch operation - ' + error.message + '.');
- });
- }
- };
|