From 0a0ee24a2abb7cc34334d3871586ae5417706efd Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Tue, 6 Jul 2021 05:27:07 +0300 Subject: [PATCH] to pc --- .gitignore | 2 - ENGINE_INFO_RU.txt | 58 ++++++++ TODO.md | 9 +- app/.gitignore | 2 + app/assets/logo.png | Bin 0 -> 9798 bytes app/config.json | 5 +- app/js/draw.js | 10 +- app/js/game.js | 14 +- app/js/index.bak.js | 242 +++++++++++++++++++++++++++++++++ app/js/index.js | 319 +++++++++++++++++++++----------------------- 10 files changed, 480 insertions(+), 181 deletions(-) create mode 100644 ENGINE_INFO_RU.txt create mode 100644 app/.gitignore create mode 100644 app/assets/logo.png create mode 100644 app/js/index.bak.js diff --git a/.gitignore b/.gitignore index 0747ea9..504afef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ node_modules/ package-lock.json -app/dist -app/assets diff --git a/ENGINE_INFO_RU.txt b/ENGINE_INFO_RU.txt new file mode 100644 index 0000000..3295514 --- /dev/null +++ b/ENGINE_INFO_RU.txt @@ -0,0 +1,58 @@ +# Welcome +... + +## Переменные движка + +-- DEBUG +Тип: bool + +В зависимости от значения в консоль будет выхлоп данных для отладки. + +Значение берётся из файла конфигурации `config.json` и устанавливается при инициализации переменной. + +-- canvas +Переменная ссылатся на HTML объект canvas. + +Значение устанавливается в функции `window.onload = function()` + +-- context +Значение устанавливается в функции `window.onload = function()` + +-- cW +Значение устанавливается в функции `window.onload = function()` + +-- cH +Значение устанавливается в функции `window.onload = function()` + +-- landscape_orientation +Хранит значение ориентации экрана. + +Значение устанавливается в функции `window.onload = function()` в true, если ширина canvas больше или равна высоте canvas, в протином случает false. + +-- images +Объект со всеми изображениями квестов + +-- game +В переменной хранятся все данные игрового процесса (сцены, текущий квест, кол-во ответов и прочее). + +-- game.loaded +Тип: bool +Состояние загрузки игры. +Значение false будет до тех пор, пока не будут загружены все шрифты, изображение (возможно что-то ещё). + +-- game.currentQuest +Индекс текущего квеста. + +-- game.finish +Тип: bool +Устанавливается значение true, когда игрок ответил на все вопросы. + +## Главные функции движка +-- window.onload = function() +Инициализирующая функция, в которой устанавливаются значения переменных движка + +-- gameLoop(timeStamp) + +-- update() + +-- draw() diff --git a/TODO.md b/TODO.md index fa61c1a..5a39b48 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,10 @@ -- add quest progress +- loading all quest images with loading +- splash (loading) screen - change quest animation - button hover animation -- splash (loading) screen - make docs/ + +- google: if webpack mode production remove DEBUG code + +## done +- add quest progress [aac38ec] diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..bd7c4a1 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,2 @@ +dist/ +assets/images/*.jpg diff --git a/app/assets/logo.png b/app/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cc145054246b8e056a94590484783edbb1d44129 GIT binary patch literal 9798 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 Tilo4N7@oSyYvn4C`RD%winevI literal 0 HcmV?d00001 diff --git a/app/config.json b/app/config.json index 7841c41..638a11c 100644 --- a/app/config.json +++ b/app/config.json @@ -1,8 +1,5 @@ { "gameName": "quizEngine", "gameVersion": [0, 0, 1], - - "scene": { - "backGradient": ["#2f80ff", "#3ccbff"] - } + "debug": true } diff --git a/app/js/draw.js b/app/js/draw.js index 054b53a..8e98818 100644 --- a/app/js/draw.js +++ b/app/js/draw.js @@ -1,17 +1,17 @@ // функции рисоввания -export function clearContext(canvas, config) { +export function clearContext(canvas) { // var:canvas -- канвас, на котором рисуем - // var:config -- используется для получения цветов фона градиента сцены let cW = canvas.width; let cH = canvas.height; let context = canvas.getContext('2d'); let graBack = context.createLinearGradient(cW / 2, 0, cW / 2, cH); - graBack.addColorStop(0, config.scene.backGradient[0]); - graBack.addColorStop(1, config.scene.backGradient[1]); - context.fillStyle = graBack; + // graBack.addColorStop(0, config.scene.backGradient[0]); + // graBack.addColorStop(1, config.scene.backGradient[1]); + // context.fillStyle = graBack; + context.fillStyle = "#444444"; context.fillRect(0, 0, cW, cH); } diff --git a/app/js/game.js b/app/js/game.js index 6009879..2362f69 100644 --- a/app/js/game.js +++ b/app/js/game.js @@ -1,5 +1,13 @@ // функции игры +export function loadingLogo(imagesArray) { + // FIXME: возможно потом просто удалить функцию, если будет реализован imageLoader + let imgLogo = new Image(); + imgLogo.src = 'assets/logo.png'; + + imagesArray.logo = imgLogo; +} + export function clickAnswer(questions, game, answer) { if (questions[game.questIndex].rightAnswer.toLowerCase() == answer.toLowerCase()) { questions[game.questIndex].status = true; @@ -18,9 +26,9 @@ export function clickAnswer(questions, game, answer) { } } -export function shuffleQuestAnswer(answers) { - for (let i = answers.length - 1; i > 0; i--) { +export function shuffle(array) { + for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); - [answers[i], answers[j]] = [answers[j], answers[i]]; + [array[i], array[j]] = [array[j], array[i]]; } } diff --git a/app/js/index.bak.js b/app/js/index.bak.js new file mode 100644 index 0000000..e94410d --- /dev/null +++ b/app/js/index.bak.js @@ -0,0 +1,242 @@ +'use strict'; + +import config from '../config.json'; // game configuration +import gameData from '../gameData.json'; // game data + +import { getMousePos, isInside } from './buttons.js'; +import { clearContext, getCenterH, getCenterV } from './draw.js'; +import { clickAnswer, shuffleQuestAnswer } from './game.js'; + +// Engine variables ------------------------------------- +let DEBUG = true; +let canvas = null; // canvas id +let context = null; // context id +let cW = null; // canvas with +let cH = null; // canvas height +let orientation = null; // screen orientation +let button = null; // buttons array +let area = null; // game areas (buttons, images, etc.) +let game = null; + +// Init ------------------------------------------------- +window.onload = function() { + // init canvas id and sizes + canvas = document.getElementById('game'); + context = canvas.getContext('2d'); + cW = canvas.width; + cH = canvas.height; + + // set screen orientation by carculate canvas width&height + if (cW >= cH) { orientation = true; } + else { orientation = false; } + + if (DEBUG) { + console.log(`Loaded ${gameData.length} quests.`); + } + + game = { + // TODO: change quest by script + questIndex: 0, + quest: null, + questImage: null, + totalRightAnswers: 0, // количество правильных ответов + scene: null, + }; + shuffleQuestAnswer(gameData); // shuffle quest + game.quest = gameData[game.questIndex]; + shuffleQuestAnswer(gameData[game.questIndex].answer); // shuffle first quest answers + + // присваем всем квестам статус не выполнен + gameData.forEach(element => element.status = null); + + if (!orientation) { + area = { + answerButtons: { x: 10, y: cH - 340, w: cW - 20, h: 250 }, + questionLabel: { x: 10, y: cH - 340 - 80, w: cW - 20, h: 70 }, + uiButtons: { x: 10, y: cH - 80, w: cW - 20, h: 70 }, + questProgress: { x: 10, y: 10, w: cW - 20, h: 20 }, + } + area.image = { x: 10, y: area.questProgress.y + area.questProgress.h + 10, + w: cW - 20, h: area.questionLabel.y - area.questProgress.y - (area.questProgress.h * 2) }; + } + // TODO: add areas for landscape mode + + button = { + info: { x: 10, y: cH - 80, w: 70, h: 70 }, + sfx: { x: cW - 80, y: cH - 80, w: 70, h: 70 }, + // TODO: change data: to null + answerButtons: [ + { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, + { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, + { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, + { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, + ], + } + + button.answerButtons.forEach(function callback(value, index, array) { + if (index == 0) + array[index].y = area.answerButtons.y; + else + array[index].y = array[index - 1].y + value.h + 15; + }); + + canvas.addEventListener('click', function(evt) { + let mousePos = getMousePos(canvas, evt); + + // click info button + if (isInside(mousePos, button.info)) { + console.log("info"); + } + + // click sfx button + if (isInside(mousePos, button.sfx)) { + console.log("sfx"); + } + + // click by first answer button + if (isInside(mousePos, button.answerButtons[0])) { + clickAnswer(gameData, game, button.answerButtons[0].data); + } + + // click by second answer button + if (isInside(mousePos, button.answerButtons[1])) { + clickAnswer(gameData, game, button.answerButtons[1].data); + } + + // click by third answer button + if (isInside(mousePos, button.answerButtons[2])) { + clickAnswer(gameData, game, button.answerButtons[2].data); + } + + // click by four answer button + if (isInside(mousePos, button.answerButtons[3])) { + clickAnswer(gameData, game, button.answerButtons[3].data); + } + }, false); + + window.requestAnimationFrame(gameLoop); +}; + + +// GameLoop --------------------------------------------- +function gameLoop(timeStamp) { + update(); + draw(); + + window.requestAnimationFrame(gameLoop); +} + +// Game update func ------------------------------------- +function update() { + // Update answer buttons label + button.answerButtons.forEach(function callback(value, index) { + value.data = game.quest.answer[index]; + }); +} + +// Draw to canvas func ---------------------------------- +function draw() { + clearContext(canvas, config); // flush?! canvas + + // draw question label + context.font = "32px Ubuntu"; + context.textAlign = "center"; + context.fillStyle = "white"; + context.fillText(game.quest.question, cW / 2, area.questionLabel.y + 30); + + // draw answer buttons + context.fillStyle = "purple"; + context.strokeStyle = "navy"; + context.lineWidth = 2; + + for (let i = 0; i <= button.answerButtons.length - 1; i++) { + context.fillRect(button.answerButtons[i].x, button.answerButtons[i].y, + button.answerButtons[i].w, button.answerButtons[i].h); + context.strokeRect(button.answerButtons[i].x, button.answerButtons[i].y, + button.answerButtons[i].w, button.answerButtons[i].h); + } + + // draw answer button label + context.font = "32px Ubuntu"; + context.textAlign = "center"; + context.fillStyle = "white"; + + button.answerButtons.forEach(function callback(value) { + context.fillText(value.data, cW / 2, value.y + 35); + }); + + // draw image + game.questImage = new Image(); + game.questImage.src = 'assets/images/' + game.quest.image; + + // carculate image ratio by area.image size + if (game.questImage.width >= game.questImage.height) { + if (game.questImage.height > area.image.h) { + let ratio = game.questImage.width / area.image.w; + let newImageW = area.image.w / ratio; + let newImageH = area.image.h; + + context.drawImage(game.questImage, getCenterH(cW, newImageW), area.image.y, + newImageW, newImageH); + } + else { + // TODO: draw image center + // TODO: add option to sizeUp images to engine config + } + } + else { + let ratio = game.questImage.height / area.image.h; + let newImageW = area.image.w / ratio; + + context.drawImage(game.questImage, getCenterH(cW, newImageW), area.image.y, + newImageW, area.image.h); + } + + // draw progress bar + let sizeProgressItem = area.questProgress.w / gameData.length; + + context.strokeStyle = "black"; + + for (let i = 0; i < gameData.length; i++) { + // change progress item color by status answer + switch (gameData[i].status) { + case null: + context.fillStyle = "gray"; + break; + case true: + context.fillStyle = "green"; + break; + case false: + context.fillStyle = "red"; + break; + } + + context.fillRect(10 + (i * sizeProgressItem), 10, sizeProgressItem, 20); + context.strokeRect(10 + (i * sizeProgressItem), 10, sizeProgressItem, 20); + } + + // UI ------------------------------------------ + // TODO: переписать это всё г* + context.fillStyle = "red"; + context.strokeStyle = "navy"; + context.lineWidth = 2; + context.fillRect(button.info.x, button.info.y, button.info.w, button.info.h); // info button + context.strokeRect(button.info.x, button.info.y, button.info.w, button.info.h); // info button + context.fillRect(button.sfx.x, button.sfx.y, button.sfx.w, button.sfx.h); // sfx button + context.strokeRect(button.sfx.x, button.sfx.y, button.sfx.w, button.sfx.h); // sfx button + + // draw game areas + if (DEBUG) { + context.strokeStyle = "red"; + context.lineWidth = 2; + + // answer buttons area + if (orientation) + // TODO: draw answer buttons area by landscape + console.log('TODO: draw answer buttons area by landscape'); + else + for (const [key, value] of Object.entries(area)) { + context.strokeRect(value.x, value.y, value.w, value.h); + } + } +} diff --git a/app/js/index.js b/app/js/index.js index 24d2eef..fce4a32 100644 --- a/app/js/index.js +++ b/app/js/index.js @@ -5,18 +5,20 @@ import gameData from '../gameData.json'; // game data import { getMousePos, isInside } from './buttons.js'; import { clearContext, getCenterH, getCenterV } from './draw.js'; -import { clickAnswer, shuffleQuestAnswer } from './game.js'; +import { loadingLogo, clickAnswer, shuffle } from './game.js'; // Engine variables ------------------------------------- -let DEBUG = true; +const DEBUG = config.debug; let canvas = null; // canvas id let context = null; // context id let cW = null; // canvas with let cH = null; // canvas height -let orientation = null; // screen orientation -let button = null; // buttons array -let area = null; // game areas (buttons, images, etc.) -let game = null; +let landscape_orientation = null; // canvas orientation +let game = {}; // main game variable +let areas = null; +let images = {}; +let buttons = {}; + // Init ------------------------------------------------- window.onload = function() { @@ -25,87 +27,50 @@ window.onload = function() { context = canvas.getContext('2d'); cW = canvas.width; cH = canvas.height; + if (DEBUG) + console.log(`Canvas size ${cW} x ${cH}`); - // set screen orientation by carculate canvas width&height - if (cW >= cH) { orientation = true; } - else { orientation = false; } + // set screen orientation by carculate canvas width & height + if (cW >= cH) { landscape_orientation = true; } + else { landscape_orientation = false; } + if (DEBUG) + console.log(landscape_orientation ? "Canvas orientation set to landscape" : "Canvas orientation set to portrait"); - if (DEBUG) { - console.log(`Loaded ${gameData.length} quests.`); - } + loadingLogo(images); - game = { - // TODO: change quest by script - questIndex: 0, - quest: null, - questImage: null, - totalRightAnswers: 0, // количество правильных ответов - scene: null, - }; - shuffleQuestAnswer(gameData); // shuffle quest - game.quest = gameData[game.questIndex]; - shuffleQuestAnswer(gameData[game.questIndex].answer); // shuffle first quest answers + game.loadedState = false; + game.finish = false; + game.currentQuest = 0; + + shuffle(gameData); // shuffle quests + shuffle(gameData[game.currentQuest].answer); // shuffle first quest answers // присваем всем квестам статус не выполнен gameData.forEach(element => element.status = null); - if (!orientation) { - area = { - answerButtons: { x: 10, y: cH - 340, w: cW - 20, h: 250 }, - questionLabel: { x: 10, y: cH - 340 - 80, w: cW - 20, h: 70 }, - uiButtons: { x: 10, y: cH - 80, w: cW - 20, h: 70 }, + if (!landscape_orientation) { + areas = { + btnAnswer: { x: 10, y: cH - 340, w: cW - 20, h: 250 }, + labelQuestion: { x: 10, y: cH - 340 - 80, w: cW - 20, h: 70 }, + btnUi: { x: 10, y: cH - 80, w: cW - 20, h: 70 }, questProgress: { x: 10, y: 10, w: cW - 20, h: 20 }, } - area.image = { x: 10, y: area.questProgress.y + area.questProgress.h + 10, - w: cW - 20, h: area.questionLabel.y - area.questProgress.y - (area.questProgress.h * 2) }; + areas.questImage = { x: 10, y: areas.questProgress.y + areas.questProgress.h + 10, + w: cW - 20, h: areas.labelQuestion.y - areas.questProgress.y - (areas.questProgress.h * 2) }; } // TODO: add areas for landscape mode - button = { - info: { x: 10, y: cH - 80, w: 70, h: 70 }, - sfx: { x: cW - 80, y: cH - 80, w: 70, h: 70 }, - // TODO: change data: to null - answerButtons: [ - { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, - { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, - { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, - { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }, - ], - } - - button.answerButtons.forEach(function callback(value, index, array) { - if (index == 0) - array[index].y = area.answerButtons.y; - else - array[index].y = array[index - 1].y + value.h + 15; - }); - canvas.addEventListener('click', function(evt) { let mousePos = getMousePos(canvas, evt); - // bet inscrease - if (isInside(mousePos, button.info)) { - console.log("info"); - } + // if (isInside(mousePos, button.info)) { + // console.log("info"); + // } - // click by first answer button - if (isInside(mousePos, button.answerButtons[0])) { - clickAnswer(gameData, game, button.answerButtons[0].data); - } - - // click by second answer button - if (isInside(mousePos, button.answerButtons[1])) { - clickAnswer(gameData, game, button.answerButtons[1].data); - } - - // click by third answer button - if (isInside(mousePos, button.answerButtons[2])) { - clickAnswer(gameData, game, button.answerButtons[2].data); - } - - // click by four answer button - if (isInside(mousePos, button.answerButtons[3])) { - clickAnswer(gameData, game, button.answerButtons[3].data); + for (const [key, value] of Object.entries(buttons)) { + if (isInside(mousePos, value)) { + console.log(`click on ${key}`); + } } }, false); @@ -123,114 +88,138 @@ function gameLoop(timeStamp) { // Game update func ------------------------------------- function update() { - // Update answer buttons label - button.answerButtons.forEach(function callback(value, index) { - value.data = game.quest.answer[index]; - }); + // progressBar %percentage updater + // and set gameStateLoaded true + if (!game.loadedState && game.loadingProgress <= 99) { + // TODO: реализовать функционал проверки загрузки изображений and fonts + if (DEBUG) game.loadingProgress += 10; // FIXME: костыль + else game.loadingProgress += 1; + } + else if (game.loadingProgress == 100) + game.loadedState = true; + + if (game.loadedState && !game.finish) { + buttons.answerButton0 = { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }; + buttons.answerButton1 = { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }; + buttons.answerButton2 = { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }; + buttons.answerButton3 = { x: getCenterH(cW, cW / 1.5), y: 0, w: cW / 1.5, h: 50, data: null }; + + let answerButtonsArray = [buttons.answerButton0, buttons.answerButton1, + buttons.answerButton2, buttons.answerButton3]; + + answerButtonsArray.forEach(function callback(value, index, array) { + if (index == 0) + array[index].y = areas.btnAnswer.y; + else + array[index].y = array[index - 1].y + value.h + 15; + }); + + // Update answer buttons label + answerButtonsArray.forEach(function callback(value, index) { + value.data = gameData[game.currentQuest].answer[index]; + }); + } } // Draw to canvas func ---------------------------------- function draw() { - clearContext(canvas, config); // flush?! canvas + clearContext(canvas); // clean canvas - // draw question label - context.font = "32px Ubuntu"; - context.textAlign = "center"; - context.fillStyle = "white"; - context.fillText(game.quest.question, cW / 2, area.questionLabel.y + 30); - - // draw answer buttons - context.fillStyle = "purple"; - context.strokeStyle = "navy"; - context.lineWidth = 2; - - for (let i = 0; i <= button.answerButtons.length - 1; i++) { - context.fillRect(button.answerButtons[i].x, button.answerButtons[i].y, - button.answerButtons[i].w, button.answerButtons[i].h); - context.strokeRect(button.answerButtons[i].x, button.answerButtons[i].y, - button.answerButtons[i].w, button.answerButtons[i].h); - } - - // draw answer button label - context.font = "32px Ubuntu"; - context.textAlign = "center"; - context.fillStyle = "white"; - - button.answerButtons.forEach(function callback(value) { - context.fillText(value.data, cW / 2, value.y + 35); - }); - - // draw image - game.questImage = new Image(); - game.questImage.src = 'assets/images/' + game.quest.image; - - // carculate image ratio by area.image size - if (game.questImage.width >= game.questImage.height) { - if (game.questImage.height > area.image.h) { - let ratio = game.questImage.width / area.image.w; - let newImageW = area.image.w / ratio; - let newImageH = area.image.h; - - context.drawImage(game.questImage, getCenterH(cW, newImageW), area.image.y, - newImageW, newImageH); - } - else { - // TODO: draw image center - // TODO: add option to sizeUp images to engine config - } - } - else { - let ratio = game.questImage.height / area.image.h; - let newImageW = area.image.w / ratio; - - context.drawImage(game.questImage, getCenterH(cW, newImageW), area.image.y, - newImageW, area.image.h); - } - - // draw progress bar - let sizeProgressItem = area.questProgress.w / gameData.length; - - context.strokeStyle = "black"; - - for (let i = 0; i < gameData.length; i++) { - // change progress item color by status answer - switch (gameData[i].status) { - case null: - context.fillStyle = "gray"; - break; - case true: - context.fillStyle = "green"; - break; - case false: - context.fillStyle = "red"; - break; + // render splash screen ----------------------------- + if (!game.loadedState) { + // TODO: change if(! to NaN check + if (!game.loadingProgress) { + game.loadingProgress = 0; } - context.fillRect(10 + (i * sizeProgressItem), 10, sizeProgressItem, 20); - context.strokeRect(10 + (i * sizeProgressItem), 10, sizeProgressItem, 20); - } + context.drawImage(images.logo, getCenterH(cW, images.logo.width), getCenterV(cH, images.logo.height)); - // UI ------------------------------------------ - // TODO: переписать это всё г* - context.fillStyle = "red"; - context.strokeStyle = "navy"; - context.lineWidth = 2; - context.fillRect(button.info.x, button.info.y, button.info.w, button.info.h); // info button - context.strokeRect(button.info.x, button.info.y, button.info.w, button.info.h); // info button - context.fillRect(button.sfx.x, button.sfx.y, button.sfx.w, button.sfx.h); // sfx button - context.strokeRect(button.sfx.x, button.sfx.y, button.sfx.w, button.sfx.h); // sfx button - - // draw game areas - if (DEBUG) { - context.strokeStyle = "red"; + // TODO: check loadedState to final loading game + context.strokeStyle = "black"; context.lineWidth = 2; + context.fillStyle = "yellow"; + + // FIXME: translate to English + // если расстояние от нижнего края картинки до конца канваса меньше ??? + // то рисуем прогрессбар от нижнего края + // если больше, то на расстояние от картинки + let progressBarHeight = cH - (getCenterV(cH, images.logo.height) + images.logo.height) > 301 ? + getCenterV(cH, images.logo.height) + images.logo.height + 70 : cH - 70; + + context.fillRect(50, progressBarHeight, ((cW - 100) / 100 * game.loadingProgress), 20); + context.strokeRect(50, progressBarHeight, cW - 100, 20); + } + + // render game -------------------------------------- + if (!game.finish && game.loadedState) { + // draw progress bar + let sizeProgressItem = areas.questProgress.w / gameData.length; + + context.strokeStyle = "black"; + + for (let i = 0; i < gameData.length; i++) { + // change progress item color by status answer + switch (gameData[i].status) { + case null: + context.fillStyle = "gray"; + break; + case true: + context.fillStyle = "green"; + break; + case false: + context.fillStyle = "red"; + break; + } + + context.fillRect(10 + (i * sizeProgressItem), 10, sizeProgressItem, 20); + context.strokeRect(10 + (i * sizeProgressItem), 10, sizeProgressItem, 20); + } + + // draw question label + context.font = "32px Ubuntu"; + context.textAlign = "center"; + context.fillStyle = "white"; + context.fillText(gameData[game.currentQuest].question, cW / 2, areas.labelQuestion.y + 30); + + // draw answer buttons + context.fillStyle = "purple"; + context.strokeStyle = "navy"; + context.lineWidth = 2; + + let answerButtonsArray = [buttons.answerButton0, buttons.answerButton1, + buttons.answerButton2, buttons.answerButton3]; + + answerButtonsArray.forEach(function(btn) { + context.fillRect(btn.x, btn.y, btn.w, btn.h); + context.strokeRect(btn.x, btn.y, btn.w, btn.h); + }); + + // draw answer button label + context.font = "32px Ubuntu"; + context.textAlign = "center"; + context.fillStyle = "white"; + + answerButtonsArray.forEach(function callback(value) { + context.fillText(value.data, cW / 2, value.y + 35); + }); + } + + // render result game ------------------------------- + if (game.finish) { + // + } + + // draw game areas ---------------------------------- + if (DEBUG && !game.finish && game.loadedState) { + context.strokeStyle = "red"; + context.lineWidth = 1; // answer buttons area - if (orientation) + if (landscape_orientation) // TODO: draw answer buttons area by landscape console.log('TODO: draw answer buttons area by landscape'); else - for (const [key, value] of Object.entries(area)) { + for (const [key, value] of Object.entries(areas)) { context.strokeRect(value.x, value.y, value.w, value.h); } }