View file Space-Quiz-master/src/js/modules/quiz.js

File size: 4.64Kb
'use strict';

/** Class representing a quiz. */
export default class Quiz {
  /**
   * @param {Object} game Game instance.
   */
  constructor(game) {
    // assign game instance to local property
    this._game = game;

    this._width = this._game.width;
    this._height = this._game.height;
    // basic falling text speed
    this._speed = 60;
    this._questCount = 0;
    // body element font-size
    this._fontSize = parseInt(window.getComputedStyle(document.body).fontSize);
    // array with quiz from database
    this._quizBox = this._game.data;
    // shuffle quiz array
    this._quizBox = shuffleArray(this._quizBox);
    // current question
    this._question = '';
    this._qWidth = 0;
    // current answers array
    this._answers = [];
    this._aWidth = 0;
    // correct answer
    this._correct = '';

  }

  /**
   * Create new quest with questions, answers and correct answer
   * from quiz box.
   */
  newQuest() {
    // finish the game if there are no more questions
    if (this._questCount >= this._quizBox.length) {
      this._game.gameOver();
    }
    // clear answers field
    this._answers = [];
    // count the number of quiz
    let num = this._questCount;

    let quest = this._quizBox[num];
    this._question = new Block(quest.question, this._width / 2, 0);

    this._correct = quest.correct;
    quest.answers = shuffleArray(quest.answers);

    let aLength = quest.answers.length;

    // devide the canvas into paths and draw answers in each of them
    for (let i = 0; i < aLength; i++) {
      let wordWidth = quest.answers[i].length * this._fontSize;
      let maxX = (i + 2) * this._width / (aLength + 2) - wordWidth;
      let minX = (i + 1) * this._width / (aLength + 2) + wordWidth;
      let x = Math.random() * (maxX - minX) + minX;
      this._answers[i] = new Block(quest.answers[i], x, -this._fontSize);
    };

    // the number of next question
    this._questCount++;
  }

  /**
   * Update location of the text.
   * @param {number} delta The amount of time that has passed
   *     between rendering frames.
   */
  update(delta) {
    // avoid the current call of the function if there's no valid
    // delta value
    if (isNaN(delta) || delta <= 0) {
      return;
    }

    if (this._question.y < (this._height - this._fontSize * 3)) {
      this._question.y += Math.floor(delta * this._speed * 2);
    } else {
      for (let i = 0; i < this._answers.length; i++) {
        let answer = this._answers[i];
        answer.y += delta * this._speed;
        this._checkAnswer(answer);
      }
    }
  }

  /**
   * Renders the text onto the canvas.
   * @param {CanvasRenderingContext2D} ctx Current game canvas context.
   */
  render(ctx) {
    ctx.fillStyle = '#fff';
    ctx.font = 'small-caps 3em Righteous';
    this._qWidth = ctx.measureText(this._question.text).width;
    ctx.fillText(this._question.text,
      this._question.x - this._qWidth / 2,
      this._question.y);

    for (let i = 0; i < this._answers.length; i++) {
      let answer = this._answers[i];
      ctx.save();
      ctx.fillStyle = '#fff';
      ctx.font = 'small-caps 2em Righteous';
      this._aWidth = ctx.measureText(answer.text).width;
      ctx.fillText(answer.text, answer.x, Math.floor(answer.y));
      ctx.restore();
    };
  }

  /**
   * Check answer, callback function to get progress and start new quest
   * on completion if cursor hovers over the answer.
   * @param {string} answer Current answer from answers array.
   * @return {string} The img src.
   */
  _checkAnswer(answer) {
    if ((this._game.cursor.x > answer.x) &&
      (this._game.cursor.x < answer.x + this._aWidth) &&
      (this._game.cursor.y > answer.y) &&
      (this._game.cursor.y < answer.y + this._fontSize)) {
      let progress = answer.text === this._correct ? true : false;
      this._game.state.getState(progress);
      this.newQuest();
    };

    //	If the answers have moved from the bottom of the screen, spawn new quest.
    if (answer.y > this._height) {
      this.newQuest();
    }
  }
}

/**
 * Computer-optimized version of Fisher-Yates algorithm for
 * randomizing an array.
 * @param {CanvasRenderingContext2D} ctx Current game canvas context.
 */
function shuffleArray(array) {
  for (let i = array.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1));
    let temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  return array;
}

/**
 * Class for generating a text with x and y values.
 */
class Block {
  /**
   * @param {string} text Text to be rendered onto canvas.
   * @param {number} x The x value.
   * @param {number} y The y value.
   */
  constructor(text, x, y) {
    this.text = text;
    this.x = Math.floor(x);
    this.y = y;
  }
}